diff options
1373 files changed, 60623 insertions, 48823 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 3c59e41a13..7f7a882cee 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,34 +1,54 @@ env: # Global defaults CIRRUS_CLONE_DEPTH: 1 - PACKAGE_MANAGER_INSTALL: "apt-get update && apt-get install -y" + CIRRUS_LOG_TIMESTAMP: true MAKEJOBS: "-j10" TEST_RUNNER_PORT_MIN: "14000" # Must be larger than 12321, which is used for the http cache. See https://cirrus-ci.org/guide/writing-tasks/#http-cache CI_FAILFAST_TEST_LEAVE_DANGLING: "1" # Cirrus CI does not care about dangling processes and setting this variable avoids killing the CI script itself on error - CCACHE_MAXSIZE: "200M" - CCACHE_DIR: "/tmp/ccache_dir" - CCACHE_NOHASHDIR: "1" # Debug info might contain a stale path if the build dir changes, but this is fine +# A self-hosted machine(s) can be used via Cirrus CI. It can be configured with +# multiple users to run tasks in parallel. No sudo permission is required. +# # https://cirrus-ci.org/guide/persistent-workers/ # -# It is possible to select a specific persistent worker by label. Refer to the +# Generally, a persistent worker must run Ubuntu 23.04+ or Debian 12+. +# +# The following specific types should exist, with the following requirements: +# - small: For an x86_64 machine, with at least 2 vCPUs and 8 GB of memory. +# - medium: For an x86_64 machine, with at least 4 vCPUs and 16 GB of memory. +# - arm64: For an aarch64 machine, with at least 2 vCPUs and 8 GB of memory. +# +# CI jobs for the latter configuration can be run on x86_64 hardware +# by installing qemu-user-static, which works out of the box with +# podman or docker. Background: https://stackoverflow.com/a/72890225/313633 +# +# The above machine types are matched to each task by their label. Refer to the # Cirrus CI docs for more details. # -# Generally, a persistent worker must run Ubuntu 23.04+ or Debian 12+. -# Specifically, -# - apt-get is required due to PACKAGE_MANAGER_INSTALL -# - podman-docker-4.1+ is required due to the use of `podman` when -# RESTART_CI_DOCKER_BEFORE_RUN is set and 4.1+ due to the bugfix in 4.1 +# 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. +# +# Futhermore: +# - podman-docker-4.1+ is required due to the bugfix in 4.1 # (https://github.com/bitcoin/bitcoin/pull/21652#issuecomment-1657098200) -# - The ./ci/ depedencies (with cirrus-cli) should be installed: +# - The ./ci/ dependencies (with cirrus-cli) should be installed. One-liner example +# for a single user setup with sudo permission: # # ``` -# apt update && apt install git screen python3 bash podman-docker curl -y && curl -L -o cirrus "https://github.com/cirruslabs/cirrus-cli/releases/latest/download/cirrus-linux-$(dpkg --print-architecture)" && mv cirrus /usr/local/bin/cirrus && chmod +x /usr/local/bin/cirrus +# apt update && apt install git screen python3 bash podman-docker uidmap slirp4netns curl -y && curl -L -o cirrus "https://github.com/cirruslabs/cirrus-cli/releases/latest/download/cirrus-linux-$(dpkg --print-architecture)" && mv cirrus /usr/local/bin/cirrus && chmod +x /usr/local/bin/cirrus # ``` # -# - There are no strict requirements on the hardware, because having less CPUs -# runs the same CI script (maybe slower). To avoid rare and intermittent OOM -# due to short memory usage spikes, it is recommended to add (and persist) -# swap: +# - There are no strict requirements on the hardware. Having fewer CPU threads +# than recommended merely causes the CI script to run slower. +# To avoid rare and intermittent OOM due to short memory usage spikes, +# it is recommended to add (and persist) swap: # # ``` # fallocate -l 16G /swapfile_ci && chmod 600 /swapfile_ci && mkswap /swapfile_ci && swapon /swapfile_ci && ( echo '/swapfile_ci none swap sw 0 0' | tee -a /etc/fstab ) @@ -39,23 +59,20 @@ env: # Global defaults # ``` # RESTART_CI_DOCKER_BEFORE_RUN=1 screen cirrus worker run --labels type=todo_fill_in_type --token todo_fill_in_token # ``` -# -# The following specific types should exist, with the following requirements: -# - small: For an x86_64 machine, recommended to have 2 CPUs and 8 GB of memory. -# - medium: For an x86_64 machine, recommended to have 4 CPUs and 16 GB of memory. -# - noble: For a machine running the Linux kernel shipped with exaclty Ubuntu Noble 24.04. The machine is recommended to have 4 CPUs and 16 GB of memory. -# - arm64: For an aarch64 machine, recommended to have 2 CPUs and 8 GB of memory. # 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 << : *FILTER_TEMPLATE merge_base_script: - # Unconditionally install git (used in fingerprint_script). - - git --version || bash -c "$PACKAGE_MANAGER_INSTALL git" + # Require git (used in fingerprint_script). + - git --version || ( apt-get update && apt-get install -y git ) - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts @@ -160,19 +177,6 @@ task: FILE_ENV: "./ci/test/00_setup_env_native_msan.sh" task: - name: 'ASan + LSan + UBSan + integer, no depends, USDT' - enable_bpfcc_script: - # In the image build step, no external environment variables are available, - # so any settings will need to be written to the settings env file: - - sed -i "s|\${CIRRUS_CI}|true|g" ./ci/test/00_setup_env_native_asan.sh - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: noble # Must use this specific worker (needed for USDT functional tests) - env: - FILE_ENV: "./ci/test/00_setup_env_native_asan.sh" - -task: name: 'fuzzer,address,undefined,integer, no depends' << : *GLOBAL_TASK_TEMPLATE persistent_worker: diff --git a/.editorconfig b/.editorconfig index ae7e92d1c8..c5f3028c50 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,17 +10,17 @@ insert_final_newline = true trim_trailing_whitespace = true # Source code files -[*.{h,cpp,py,sh}] +[*.{h,cpp,rs,py,sh}] indent_size = 4 -# .cirrus.yml, .fuzzbuzz.yml, etc. +# .cirrus.yml, etc. [*.yml] indent_size = 2 -# Makefiles -[{*.am,Makefile.*.include}] +# Makefiles (only relevant for depends build) +[Makefile] indent_style = tab -# Autoconf scripts -[configure.ac] +# CMake files +[{CMakeLists.txt,*.cmake,*.cmake.in}] indent_size = 2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5c322fc23..439d02cc8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,6 @@ concurrency: cancel-in-progress: true env: - DANGER_RUN_CI_ON_HOST: 1 CI_FAILFAST_TEST_LEAVE_DANGLING: 1 # GHA does not care about dangling processes and setting this variable avoids killing the CI script itself on error MAKEJOBS: '-j10' @@ -59,21 +58,27 @@ 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 + sudo apt-get install clang ccache build-essential cmake pkg-config python3-zmq libevent-dev libboost-dev libsqlite3-dev libdb++-dev systemtap-sdt-dev libminiupnpc-dev libzmq3-dev qtbase5-dev qttools5-dev qttools5-dev-tools qtwayland5 libqrencode-dev -y - name: Compile and run tests 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 ) && CC=clang CXX=clang++ cmake -B build -DWERROR=ON -DWITH_ZMQ=ON -DBUILD_GUI=ON -DBUILD_BENCH=ON -DBUILD_FUZZ_BINARY=ON -DWITH_BDB=ON -DWITH_MINIUPNPC=ON -DWITH_USDT=ON && cmake --build build -j $(nproc) && ctest --test-dir build -j $(nproc) && ./build/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' + macos-native-arm64: + name: 'macOS 14 native, arm64, no depends, sqlite only, gui' # Use latest image, but hardcode version to avoid silent upgrades (and breaks). # See: https://github.com/actions/runner-images#available-images. - runs-on: macos-13 + runs-on: macos-14 # No need to run on the read-only mirror, unless it is a PR. if: github.repository != 'bitcoin-core/gui' || github.event_name == 'pull_request' @@ -81,6 +86,7 @@ jobs: timeout-minutes: 120 env: + DANGER_RUN_CI_ON_HOST: 1 FILE_ENV: './ci/test/00_setup_env_mac_native.sh' BASE_ROOT_DIR: ${{ github.workspace }} @@ -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 coreutils ninja pkg-config gnu-getopt ccache boost libevent miniupnpc zeromq qt@5 qrencode - name: Set Ccache directory run: echo "CCACHE_DIR=${RUNNER_TEMP}/ccache_dir" >> "$GITHUB_ENV" @@ -133,11 +139,6 @@ jobs: if: github.repository != 'bitcoin-core/gui' || github.event_name == 'pull_request' env: - CCACHE_MAXSIZE: '200M' - CI_CCACHE_VERSION: '4.7.5' - CI_QT_CONF: '-release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml' - CI_QT_DIR: 'qt-everywhere-src-5.15.11' - CI_QT_URL: 'https://download.qt.io/official_releases/qt/5.15/5.15.11/single/qt-everywhere-opensource-src-5.15.11.zip' PYTHONUTF8: 1 TEST_RUNNER_TIMEOUT_FACTOR: 40 @@ -153,98 +154,18 @@ jobs: - name: Get tool information run: | - msbuild -version | Out-File -FilePath "$env:GITHUB_WORKSPACE\msbuild_version" - Get-Content -Path "$env:GITHUB_WORKSPACE\msbuild_version" - $env:VCToolsVersion | Out-File -FilePath "$env:GITHUB_WORKSPACE\toolset_version" - Write-Host "VCToolsVersion $(Get-Content -Path "$env:GITHUB_WORKSPACE\toolset_version")" - $env:CI_QT_URL | Out-File -FilePath "$env:GITHUB_WORKSPACE\qt_url" - $env:CI_QT_CONF | Out-File -FilePath "$env:GITHUB_WORKSPACE\qt_conf" + cmake -version | Tee-Object -FilePath "cmake_version" + Write-Output "---" + msbuild -version | Tee-Object -FilePath "msbuild_version" + $env:VCToolsVersion | Tee-Object -FilePath "toolset_version" py -3 --version Write-Host "PowerShell version $($PSVersionTable.PSVersion.ToString())" - - name: Restore static Qt cache - id: static-qt-cache - uses: actions/cache/restore@v4 - with: - path: C:\Qt_static - key: ${{ github.job }}-static-qt-${{ hashFiles('msbuild_version', 'qt_url', 'qt_conf') }} - - - name: Build static Qt. Download - if: steps.static-qt-cache.outputs.cache-hit != 'true' - shell: cmd - run: | - curl --location --output C:\qt-src.zip %CI_QT_URL% - choco install --yes --no-progress jom - - - name: Build static Qt. Expand source archive - if: steps.static-qt-cache.outputs.cache-hit != 'true' - shell: cmd - run: tar -xf C:\qt-src.zip -C C:\ - - - name: Build static Qt. Create build directory - if: steps.static-qt-cache.outputs.cache-hit != 'true' - run: | - Rename-Item -Path "C:\$env:CI_QT_DIR" -NewName "C:\qt-src" - New-Item -ItemType Directory -Path "C:\qt-src\build" - - - name: Build static Qt. Configure - if: steps.static-qt-cache.outputs.cache-hit != 'true' - working-directory: C:\qt-src\build - shell: cmd - run: ..\configure %CI_QT_CONF% -prefix C:\Qt_static - - - name: Build static Qt. Build - if: steps.static-qt-cache.outputs.cache-hit != 'true' - working-directory: C:\qt-src\build - shell: cmd - run: jom - - - name: Build static Qt. Install - if: steps.static-qt-cache.outputs.cache-hit != 'true' - working-directory: C:\qt-src\build - shell: cmd - run: jom install - - - name: Save static Qt cache - if: steps.static-qt-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 - with: - path: C:\Qt_static - key: ${{ github.job }}-static-qt-${{ hashFiles('msbuild_version', 'qt_url', 'qt_conf') }} - - - name: Ccache installation cache - id: ccache-installation-cache - uses: actions/cache@v4 - with: - path: | - C:\ProgramData\chocolatey\lib\ccache - C:\ProgramData\chocolatey\bin\ccache.exe - C:\ccache\cl.exe - key: ${{ github.job }}-ccache-installation-${{ env.CI_CCACHE_VERSION }} - - - name: Install Ccache - if: steps.ccache-installation-cache.outputs.cache-hit != 'true' - run: | - choco install --yes --no-progress ccache --version=$env:CI_CCACHE_VERSION - New-Item -ItemType Directory -Path "C:\ccache" - Copy-Item -Path "$env:ChocolateyInstall\lib\ccache\tools\ccache-$env:CI_CCACHE_VERSION-windows-x86_64\ccache.exe" -Destination "C:\ccache\cl.exe" - - - name: Restore Ccache cache - id: ccache-cache - uses: actions/cache/restore@v4 - with: - path: ~/AppData/Local/ccache - key: ${{ github.job }}-ccache-${{ github.run_id }} - restore-keys: ${{ github.job }}-ccache- - - name: Using vcpkg with MSBuild run: | Set-Location "$env:VCPKG_INSTALLATION_ROOT" + Add-Content -Path "triplets\x64-windows.cmake" -Value "set(VCPKG_BUILD_TYPE release)" Add-Content -Path "triplets\x64-windows-static.cmake" -Value "set(VCPKG_BUILD_TYPE release)" - Add-Content -Path "triplets\x64-windows-static.cmake" -Value "set(VCPKG_PLATFORM_TOOLSET_VERSION $env:VCToolsVersion)" - .\vcpkg.exe --vcpkg-root "$env:VCPKG_INSTALLATION_ROOT" integrate install - git rev-parse HEAD | Out-File -FilePath "$env:GITHUB_WORKSPACE\vcpkg_commit" - Get-Content -Path "$env:GITHUB_WORKSPACE\vcpkg_commit" - name: vcpkg tools cache uses: actions/cache@v4 @@ -252,46 +173,41 @@ jobs: path: C:/vcpkg/downloads/tools key: ${{ github.job }}-vcpkg-tools - - name: vcpkg binary cache - uses: actions/cache@v4 + - name: Restore vcpkg binary cache + uses: actions/cache/restore@v4 + id: vcpkg-binary-cache with: path: ~/AppData/Local/vcpkg/archives - key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('vcpkg_commit', 'msbuild_version', 'toolset_version', 'build_msvc/vcpkg.json') }} - - - name: Generate project files - run: py -3 build_msvc\msvc-autogen.py + key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('cmake_version', 'msbuild_version', 'toolset_version', 'vcpkg.json') }} - - name: Build - shell: cmd + - name: Generate build system run: | - ccache --zero-stats - msbuild build_msvc\bitcoin.sln -property:CLToolPath=C:\ccache;CLToolExe=cl.exe;UseMultiToolTask=true;Configuration=Release -maxCpuCount -verbosity:minimal -noLogo + cmake -B build --preset vs2022-static -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" -DBUILD_GUI=ON -DWITH_BDB=ON -DWITH_MINIUPNPC=ON -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DBUILD_FUZZ_BINARY=ON -DWERROR=ON - - name: Ccache stats - run: ccache --show-stats - - - name: Save Ccache cache + - name: Save vcpkg binary cache uses: actions/cache/save@v4 - if: github.event_name != 'pull_request' && steps.ccache-cache.outputs.cache-hit != 'true' + if: github.event_name != 'pull_request' && steps.vcpkg-binary-cache.outputs.cache-hit != 'true' with: - path: ~/AppData/Local/ccache - # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache - key: ${{ github.job }}-ccache-${{ github.run_id }} - - - name: Run unit tests - run: src\test_bitcoin.exe -l test_suite - - - name: Run benchmarks - run: src\bench_bitcoin.exe -sanity-check + path: ~/AppData/Local/vcpkg/archives + key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('cmake_version', 'msbuild_version', 'toolset_version', 'vcpkg.json') }} - - name: Run util tests - run: py -3 test\util\test_runner.py + - name: Build + working-directory: build + run: | + cmake --build . -j $env:NUMBER_OF_PROCESSORS --config Release - - name: Run rpcauth test - run: py -3 test\util\rpcauth-test.py + - name: Run test suite + working-directory: build + run: | + ctest -j $env:NUMBER_OF_PROCESSORS -C Release - name: Run functional tests + working-directory: build env: + BITCOIND: '${{ github.workspace }}\build\src\Release\bitcoind.exe' + BITCOINCLI: '${{ github.workspace }}\build\src\Release\bitcoin-cli.exe' + BITCOINUTIL: '${{ github.workspace }}\build\src\Release\bitcoin-util.exe' + BITCOINWALLET: '${{ github.workspace }}\build\src\Release\bitcoin-wallet.exe' TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }} shell: cmd run: py -3 test\functional\test_runner.py --jobs %NUMBER_OF_PROCESSORS% --ci --quiet --tmpdirprefix=%RUNNER_TEMP% --combinedlogslen=99999999 --timeout-factor=%TEST_RUNNER_TIMEOUT_FACTOR% %TEST_RUNNER_EXTRA% @@ -304,7 +220,51 @@ jobs: git log -1 - name: Run fuzz binaries + working-directory: build env: - BITCOINFUZZ: "${{ github.workspace}}\\src\\fuzz.exe" + BITCOINFUZZ: '${{ github.workspace }}\build\src\test\fuzz\Release\fuzz.exe' shell: cmd - run: py -3 test\fuzz\test_runner.py --par %NUMBER_OF_PROCESSORS% --loglevel DEBUG %RUNNER_TEMP%\qa-assets\fuzz_seed_corpus + run: py -3 test\fuzz\test_runner.py --par %NUMBER_OF_PROCESSORS% --loglevel DEBUG %RUNNER_TEMP%\qa-assets\fuzz_corpora + + asan-lsan-ubsan-integer-no-depends-usdt: + name: 'ASan + LSan + UBSan + integer, no depends, USDT' + runs-on: ubuntu-24.04 # has to match container in ci/test/00_setup_env_native_asan.sh for tracing tools + # No need to run on the read-only mirror, unless it is a PR. + if: github.repository != 'bitcoin-core/gui' || github.event_name == 'pull_request' + timeout-minutes: 120 + env: + FILE_ENV: "./ci/test/00_setup_env_native_asan.sh" + DANGER_CI_ON_HOST_CACHE_FOLDERS: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set Ccache directory + run: echo "CCACHE_DIR=${RUNNER_TEMP}/ccache_dir" >> "$GITHUB_ENV" + + - name: Set base root directory + run: echo "BASE_ROOT_DIR=${RUNNER_TEMP}" >> "$GITHUB_ENV" + + - name: Restore Ccache cache + id: ccache-cache + uses: actions/cache/restore@v4 + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ github.job }}-ccache-${{ github.run_id }} + restore-keys: ${{ github.job }}-ccache- + + - name: Enable bpfcc script + # In the image build step, no external environment variables are available, + # so any settings will need to be written to the settings env file: + run: sed -i "s|\${INSTALL_BCC_TRACING_TOOLS}|true|g" ./ci/test/00_setup_env_native_asan.sh + + - name: CI script + run: ./ci/test_run_all.sh + + - name: Save Ccache cache + uses: actions/cache/save@v4 + if: github.event_name != 'pull_request' && steps.ccache-cache.outputs.cache-hit != 'true' + with: + path: ${{ env.CCACHE_DIR }} + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache + key: ${{ github.job }}-ccache-${{ github.run_id }} diff --git a/.gitignore b/.gitignore index f7bcbd1459..a419c9bde7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,151 +1,23 @@ -*.tar.gz +# Build subdirectories. +/*build* +!/build-aux +!/build_msvc -*.exe -*.pdb -src/bitcoin -src/bitcoind -src/bitcoin-cli -src/bitcoin-gui -src/bitcoin-node -src/bitcoin-tx -src/bitcoin-util -src/bitcoin-chainstate -src/bitcoin-wallet -src/test/fuzz/fuzz -src/test/test_bitcoin -src/qt/test/test_bitcoin-qt - -# autoreconf -Makefile.in -aclocal.m4 -autom4te.cache/ -build-aux/config.guess -build-aux/config.sub -build-aux/depcomp -build-aux/install-sh -build-aux/ltmain.sh -build-aux/m4/libtool.m4 -build-aux/m4/lt~obsolete.m4 -build-aux/m4/ltoptions.m4 -build-aux/m4/ltsugar.m4 -build-aux/m4/ltversion.m4 -build-aux/missing -build-aux/compile -build-aux/test-driver -config.cache -config.log -config.status -configure -libtool -src/config/bitcoin-config.h -src/config/bitcoin-config.h.in -src/config/stamp-h1 -src/obj -share/setup.nsi -share/qt/Info.plist - -src/qt/*.moc -src/qt/moc_*.cpp -src/qt/forms/ui_*.h - -src/qt/test/moc*.cpp - -src/qt/bitcoin-qt.config -src/qt/bitcoin-qt.creator -src/qt/bitcoin-qt.creator.user -src/qt/bitcoin-qt.files -src/qt/bitcoin-qt.includes - -.deps -.dirstamp -.libs -.*.swp -*~ -*.bak -*.rej -*.orig *.pyc -*.o -*.o-* -*.a -*.pb.cc -*.pb.h -*.dat - -*.log -*.trs -*.zip - -*.json.h -*.raw.h # Only ignore unexpected patches *.patch !contrib/guix/patches/*.patch !depends/patches/**/*.patch -#libtool object files -*.lo -*.la - -# Compilation and Qt preprocessor part -*.qm -Makefile -!depends/Makefile -src/qt/bitcoin-qt -Bitcoin-Qt.app - -# Qt Creator -Makefile.am.user - -# Unit-tests -Makefile.test -bitcoin-qt_test - -# Resources cpp -qrc_*.cpp - -# Mac specific -.DS_Store -build +/CMakeUserPresets.json # Previous releases -releases - -#lcov -*.gcno -*.gcda -/*.info -test_bitcoin.coverage/ -total.coverage/ -fuzz.coverage/ -coverage_percent.txt -/cov_tool_wrapper.sh -qa-assets/ +/releases #build tests -linux-coverage-build -linux-build -win32-build -test/config.ini -test/cache/* -test/.mypy_cache/ test/lint/test_runner/target/ -!src/leveldb*/Makefile - -/doc/doxygen/ - -contrib/devtools/split-debug.sh - -# Output from running db4 installation -db4/ - -# clang-check -*.plist - -dist/ - /guix-build-* /ci/scratch/ diff --git a/.python-version b/.python-version index 43077b2460..1445aee866 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.9.18 +3.10.14 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/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..edc4710637 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,651 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# Ubuntu 22.04 LTS Jammy Jellyfish, https://wiki.ubuntu.com/Releases, EOSS in June 2027: +# - CMake 3.22.1, https://packages.ubuntu.com/jammy/cmake +# +# Centos Stream 9, https://www.centos.org/cl-vs-cs/#end-of-life, EOL in May 2027: +# - CMake 3.26.5, https://mirror.stream.centos.org/9-stream/AppStream/x86_64/os/Packages/ +cmake_minimum_required(VERSION 3.22) + +if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds are not allowed.") +endif() + +#============================= +# Project / Package metadata +#============================= +set(PACKAGE_NAME "Bitcoin Core") +set(CLIENT_VERSION_MAJOR 28) +set(CLIENT_VERSION_MINOR 99) +set(CLIENT_VERSION_BUILD 0) +set(CLIENT_VERSION_RC 0) +set(CLIENT_VERSION_IS_RELEASE "false") +set(COPYRIGHT_YEAR "2024") + +# During the enabling of the CXX and CXXOBJ languages, we modify +# CMake's compiler/linker invocation strings by appending the content +# of the user-defined `APPEND_*` variables, which allows overriding +# any flag. We also ensure that the APPEND_* flags are considered +# during CMake's tests, which use the `try_compile()` command. +# +# CMake's docs state that the `CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` +# variable "is meant to be set by CMake's platform information modules +# for the current toolchain, or by a toolchain file." We do our best +# to set it before the `project()` command. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + CMAKE_CXX_COMPILE_OBJECT + CMAKE_OBJCXX_COMPILE_OBJECT + CMAKE_CXX_LINK_EXECUTABLE +) + +project(BitcoinCore + VERSION ${CLIENT_VERSION_MAJOR}.${CLIENT_VERSION_MINOR}.${CLIENT_VERSION_BUILD} + DESCRIPTION "Bitcoin client software" + HOMEPAGE_URL "https://bitcoincore.org/" + LANGUAGES NONE +) + +set(PACKAGE_VERSION ${PROJECT_VERSION}) +if(CLIENT_VERSION_RC GREATER 0) + string(APPEND PACKAGE_VERSION "rc${CLIENT_VERSION_RC}") +endif() + +set(COPYRIGHT_HOLDERS "The %s developers") +set(COPYRIGHT_HOLDERS_FINAL "The ${PACKAGE_NAME} developers") +set(PACKAGE_BUGREPORT "https://github.com/bitcoin/bitcoin/issues") + +#============================= +# Language setup +#============================= +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_HOST_APPLE) + # We do not use the install_name_tool when cross-compiling for macOS. + # So disable this tool check in further enable_language() commands. + set(CMAKE_PLATFORM_HAS_INSTALLNAME FALSE) +endif() +enable_language(CXX) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/module) + +#============================= +# Configurable options +#============================= +include(CMakeDependentOption) +# When adding a new option, end the <help_text> with a full stop for consistency. +option(BUILD_DAEMON "Build bitcoind executable." ON) +option(BUILD_GUI "Build bitcoin-qt executable." OFF) +option(BUILD_CLI "Build bitcoin-cli executable." ON) + +option(BUILD_TESTS "Build test_bitcoin executable." ON) +option(BUILD_TX "Build bitcoin-tx executable." ${BUILD_TESTS}) +option(BUILD_UTIL "Build bitcoin-util executable." ${BUILD_TESTS}) + +option(BUILD_UTIL_CHAINSTATE "Build experimental bitcoin-chainstate executable." OFF) +option(BUILD_KERNEL_LIB "Build experimental bitcoinkernel library." ${BUILD_UTIL_CHAINSTATE}) + +option(ENABLE_WALLET "Enable wallet." ON) +option(WITH_SQLITE "Enable SQLite wallet support." ${ENABLE_WALLET}) +if(WITH_SQLITE) + if(VCPKG_TARGET_TRIPLET) + # Use of the `unofficial::` namespace is a vcpkg package manager convention. + find_package(unofficial-sqlite3 CONFIG REQUIRED) + else() + find_package(SQLite3 3.7.17 REQUIRED) + endif() + set(USE_SQLITE ON) +endif() +option(WITH_BDB "Enable Berkeley DB (BDB) wallet support." OFF) +cmake_dependent_option(WARN_INCOMPATIBLE_BDB "Warn when using a Berkeley DB (BDB) version other than 4.8." ON "WITH_BDB" OFF) +if(WITH_BDB) + find_package(BerkeleyDB 4.8 MODULE REQUIRED) + set(USE_BDB ON) + if(NOT BerkeleyDB_VERSION VERSION_EQUAL 4.8) + message(WARNING "Found Berkeley DB (BDB) other than 4.8.\n" + "BDB (legacy) wallets opened by this build will not be portable!" + ) + if(WARN_INCOMPATIBLE_BDB) + message(WARNING "If this is intended, pass \"-DWARN_INCOMPATIBLE_BDB=OFF\".\n" + "Passing \"-DWITH_BDB=OFF\" will suppress this warning." + ) + endif() + endif() +endif() +cmake_dependent_option(BUILD_WALLET_TOOL "Build bitcoin-wallet tool." ${BUILD_TESTS} "ENABLE_WALLET" OFF) + +option(ENABLE_HARDENING "Attempt to harden the resulting executables." ON) +option(REDUCE_EXPORTS "Attempt to reduce exported symbols in the resulting executables." OFF) +option(WERROR "Treat compiler warnings as errors." OFF) +option(WITH_CCACHE "Attempt to use ccache for compiling." ON) + +option(WITH_MINIUPNPC "Enable UPnP." OFF) +if(WITH_MINIUPNPC) + find_package(MiniUPnPc MODULE REQUIRED) +endif() + +option(WITH_ZMQ "Enable ZMQ notifications." OFF) +if(WITH_ZMQ) + if(VCPKG_TARGET_TRIPLET) + find_package(ZeroMQ CONFIG REQUIRED) + else() + # The ZeroMQ project has provided config files since v4.2.2. + # However, mainstream distributions do not yet provide CMake + # config files for ZeroMQ packages. If they do in the future, + # find_package(ZeroMQ) may be used instead. + find_package(PkgConfig REQUIRED) + pkg_check_modules(libzmq REQUIRED IMPORTED_TARGET libzmq>=4) + endif() +endif() + +option(WITH_USDT "Enable tracepoints for Userspace, Statically Defined Tracing." OFF) +if(WITH_USDT) + find_package(USDT MODULE REQUIRED) +endif() + +cmake_dependent_option(ENABLE_EXTERNAL_SIGNER "Enable external signer support." ON "NOT WIN32" OFF) + +cmake_dependent_option(WITH_QRENCODE "Enable QR code support." ON "BUILD_GUI" OFF) +if(WITH_QRENCODE) + find_package(PkgConfig REQUIRED) + pkg_check_modules(libqrencode REQUIRED IMPORTED_TARGET libqrencode) + set(USE_QRCODE TRUE) +endif() + +cmake_dependent_option(WITH_DBUS "Enable DBus support." ON "CMAKE_SYSTEM_NAME STREQUAL \"Linux\" AND BUILD_GUI" OFF) + +option(WITH_MULTIPROCESS "Build multiprocess bitcoin-node and bitcoin-gui executables in addition to monolithic bitcoind and bitcoin-qt executables. Requires libmultiprocess library. Experimental." OFF) +if(WITH_MULTIPROCESS) + find_package(Libmultiprocess COMPONENTS Lib) + find_package(LibmultiprocessNative COMPONENTS Bin + NAMES Libmultiprocess + ) +endif() + +cmake_dependent_option(BUILD_GUI_TESTS "Build test_bitcoin-qt executable." ON "BUILD_GUI;BUILD_TESTS" OFF) +if(BUILD_GUI) + set(qt_components Core Gui Widgets LinguistTools) + if(ENABLE_WALLET) + list(APPEND qt_components Network) + endif() + if(WITH_DBUS) + list(APPEND qt_components DBus) + set(USE_DBUS TRUE) + endif() + if(BUILD_GUI_TESTS) + list(APPEND qt_components Test) + endif() + find_package(Qt 5.11.3 MODULE REQUIRED + COMPONENTS ${qt_components} + ) + unset(qt_components) +endif() + +option(BUILD_BENCH "Build bench_bitcoin executable." OFF) +option(BUILD_FUZZ_BINARY "Build fuzz binary." OFF) +option(BUILD_FOR_FUZZING "Build for fuzzing. Enabling this will disable all other targets and override BUILD_FUZZ_BINARY." OFF) + +option(INSTALL_MAN "Install man pages." ON) + +set(APPEND_CPPFLAGS "" CACHE STRING "Preprocessor flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +set(APPEND_CFLAGS "" CACHE STRING "C compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +set(APPEND_CXXFLAGS "" CACHE STRING "(Objective) C++ compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +set(APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +# Appending to this low-level rule variables is the only way to +# guarantee that the flags appear at the end of the command line. +string(APPEND CMAKE_CXX_COMPILE_OBJECT " ${APPEND_CPPFLAGS} ${APPEND_CXXFLAGS}") +string(APPEND CMAKE_CXX_CREATE_SHARED_LIBRARY " ${APPEND_LDFLAGS}") +string(APPEND CMAKE_CXX_LINK_EXECUTABLE " ${APPEND_LDFLAGS}") + +set(configure_warnings) + +include(CheckPIESupported) +check_pie_supported(OUTPUT_VARIABLE check_pie_output LANGUAGES CXX) +if(CMAKE_CXX_LINK_PIE_SUPPORTED) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +elseif(NOT WIN32) + # The warning is superfluous for Windows. + message(WARNING "PIE is not supported at link time: ${check_pie_output}") + list(APPEND configure_warnings "Position independent code disabled.") +endif() +unset(check_pie_output) + +# The core_interface library aims to encapsulate common build flags. +# It is a usage requirement for all targets except for secp256k1, which +# gets its flags by other means. +add_library(core_interface INTERFACE) +add_library(core_interface_relwithdebinfo INTERFACE) +add_library(core_interface_debug INTERFACE) +target_link_libraries(core_interface INTERFACE + $<$<CONFIG:RelWithDebInfo>:core_interface_relwithdebinfo> + $<$<CONFIG:Debug>:core_interface_debug> +) + +if(BUILD_FOR_FUZZING) + message(WARNING "BUILD_FOR_FUZZING=ON will disable all other targets and force BUILD_FUZZ_BINARY=ON.") + set(BUILD_DAEMON OFF) + set(BUILD_CLI OFF) + set(BUILD_TX OFF) + set(BUILD_UTIL OFF) + set(BUILD_UTIL_CHAINSTATE OFF) + set(BUILD_KERNEL_LIB OFF) + set(BUILD_WALLET_TOOL OFF) + set(BUILD_GUI OFF) + set(ENABLE_EXTERNAL_SIGNER OFF) + set(WITH_MINIUPNPC OFF) + set(WITH_ZMQ OFF) + set(BUILD_TESTS OFF) + set(BUILD_GUI_TESTS OFF) + set(BUILD_BENCH OFF) + set(BUILD_FUZZ_BINARY ON) + + target_compile_definitions(core_interface INTERFACE + ABORT_ON_FAILED_ASSUME + FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ) +endif() + +include(ProcessConfigurations) + +include(TryAppendCXXFlags) +include(TryAppendLinkerFlag) + +if(WIN32) + #[=[ + This build system supports two ways to build binaries for Windows. + + 1. Building on Windows using MSVC. + Implementation notes: + - /DWIN32 and /D_WINDOWS definitions are included into the CMAKE_CXX_FLAGS_INIT + and CMAKE_CXX_FLAGS_INIT variables by default. + - A run-time library is selected using the CMAKE_MSVC_RUNTIME_LIBRARY variable. + - MSVC-specific options, for example, /Zc:__cplusplus, are additionally required. + + 2. Cross-compiling using MinGW. + Implementation notes: + - WIN32 and _WINDOWS definitions must be provided explicitly. + - A run-time library must be specified explicitly using _MT definition. + ]=] + + target_compile_definitions(core_interface INTERFACE + _WIN32_WINNT=0x0601 + _WIN32_IE=0x0501 + WIN32_LEAN_AND_MEAN + NOMINMAX + ) + + if(MSVC) + if(VCPKG_TARGET_TRIPLET MATCHES "-static") + set(msvc_library_linkage "") + else() + set(msvc_library_linkage "DLL") + endif() + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>${msvc_library_linkage}") + unset(msvc_library_linkage) + + target_compile_definitions(core_interface INTERFACE + _UNICODE;UNICODE + ) + target_compile_options(core_interface INTERFACE + /utf-8 + /Zc:preprocessor + /Zc:__cplusplus + /sdl + ) + # Improve parallelism in MSBuild. + # See: https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/. + list(APPEND CMAKE_VS_GLOBALS "UseMultiToolTask=true") + endif() + + if(MINGW) + target_compile_definitions(core_interface INTERFACE + WIN32 + _WINDOWS + _MT + ) + # Avoid the use of aligned vector instructions when building for Windows. + # See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412. + try_append_cxx_flags("-Wa,-muse-unaligned-vector-move" TARGET core_interface SKIP_LINK) + try_append_linker_flag("-static" TARGET core_interface) + # We require Windows 7 (NT 6.1) or later. + try_append_linker_flag("-Wl,--major-subsystem-version,6" TARGET core_interface) + try_append_linker_flag("-Wl,--minor-subsystem-version,1" TARGET core_interface) + endif() +endif() + +# Use 64-bit off_t on 32-bit Linux. +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SIZEOF_VOID_P EQUAL 4) + # Ensure 64-bit offsets are used for filesystem accesses for 32-bit compilation. + target_compile_definitions(core_interface INTERFACE + _FILE_OFFSET_BITS=64 + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_compile_definitions(core_interface INTERFACE + MAC_OSX + OBJC_OLD_DISPATCH_PROTOTYPES=0 + ) + # These flags are specific to ld64, and may cause issues with other linkers. + # For example: GNU ld will interpret -dead_strip as -de and then try and use + # "ad_strip" as the symbol for the entry point. + try_append_linker_flag("-Wl,-dead_strip" TARGET core_interface) + try_append_linker_flag("-Wl,-dead_strip_dylibs" TARGET core_interface) + if(CMAKE_HOST_APPLE) + try_append_linker_flag("-Wl,-headerpad_max_install_names" TARGET core_interface) + endif() +endif() + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +target_link_libraries(core_interface INTERFACE + Threads::Threads +) + +add_library(sanitize_interface INTERFACE) +target_link_libraries(core_interface INTERFACE sanitize_interface) +if(SANITIZERS) + # First check if the compiler accepts flags. If an incompatible pair like + # -fsanitize=address,thread is used here, this check will fail. This will also + # fail if a bad argument is passed, e.g. -fsanitize=undfeined + try_append_cxx_flags("-fsanitize=${SANITIZERS}" TARGET sanitize_interface + RESULT_VAR cxx_supports_sanitizers + SKIP_LINK + ) + if(NOT cxx_supports_sanitizers) + message(FATAL_ERROR "Compiler did not accept requested flags.") + endif() + + # Some compilers (e.g. GCC) require additional libraries like libasan, + # libtsan, libubsan, etc. Make sure linking still works with the sanitize + # flag. This is a separate check so we can give a better error message when + # the sanitize flags are supported by the compiler but the actual sanitizer + # libs are missing. + try_append_linker_flag("-fsanitize=${SANITIZERS}" VAR SANITIZER_LDFLAGS + SOURCE " + #include <cstdint> + #include <cstddef> + extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } + __attribute__((weak)) // allow for libFuzzer linking + int main() { return 0; } + " + RESULT_VAR linker_supports_sanitizers + ) + if(NOT linker_supports_sanitizers) + message(FATAL_ERROR "Linker did not accept requested flags, you are missing required libraries.") + endif() +endif() +target_link_options(sanitize_interface INTERFACE ${SANITIZER_LDFLAGS}) + +if(BUILD_FUZZ_BINARY) + include(CheckSourceCompilesAndLinks) + check_cxx_source_links_with_flags("${SANITIZER_LDFLAGS}" " + #include <cstdint> + #include <cstddef> + extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } + // No main() function. + " FUZZ_BINARY_LINKS_WITHOUT_MAIN_FUNCTION + ) +endif() + +include(AddBoostIfNeeded) +add_boost_if_needed() + +if(BUILD_DAEMON OR BUILD_GUI OR BUILD_CLI OR BUILD_TESTS OR BUILD_BENCH OR BUILD_FUZZ_BINARY) + find_package(Libevent 2.1.8 MODULE REQUIRED) +endif() + +include(cmake/introspection.cmake) + +include(cmake/ccache.cmake) + +add_library(warn_interface INTERFACE) +target_link_libraries(core_interface INTERFACE warn_interface) +if(MSVC) + try_append_cxx_flags("/W3" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("/wd4018" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("/wd4244" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("/wd4267" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("/wd4715" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("/wd4805" TARGET warn_interface SKIP_LINK) + target_compile_definitions(warn_interface INTERFACE + _CRT_SECURE_NO_WARNINGS + _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING + ) +else() + try_append_cxx_flags("-Wall" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wextra" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wgnu" TARGET warn_interface SKIP_LINK) + # Some compilers will ignore -Wformat-security without -Wformat, so just combine the two here. + try_append_cxx_flags("-Wformat -Wformat-security" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wvla" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wshadow-field" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wthread-safety" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wloop-analysis" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wredundant-decls" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wunused-member-function" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wdate-time" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wconditional-uninitialized" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wduplicated-branches" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wduplicated-cond" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wlogical-op" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Woverloaded-virtual" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wsuggest-override" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wimplicit-fallthrough" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wunreachable-code" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wdocumentation" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wself-assign" TARGET warn_interface SKIP_LINK) + try_append_cxx_flags("-Wundef" TARGET warn_interface SKIP_LINK) + + # Some compilers (gcc) ignore unknown -Wno-* options, but warn about all + # unknown options if any other warning is produced. Test the -Wfoo case, and + # set the -Wno-foo case if it works. + try_append_cxx_flags("-Wunused-parameter" TARGET warn_interface SKIP_LINK + IF_CHECK_PASSED "-Wno-unused-parameter" + ) +endif() + +configure_file(cmake/script/Coverage.cmake Coverage.cmake USE_SOURCE_PERMISSIONS COPYONLY) +configure_file(cmake/script/CoverageFuzz.cmake CoverageFuzz.cmake USE_SOURCE_PERMISSIONS COPYONLY) +configure_file(cmake/script/CoverageInclude.cmake.in CoverageInclude.cmake USE_SOURCE_PERMISSIONS @ONLY) +configure_file(contrib/filter-lcov.py filter-lcov.py USE_SOURCE_PERMISSIONS COPYONLY) + +# Don't allow extended (non-ASCII) symbols in identifiers. This is easier for code review. +try_append_cxx_flags("-fno-extended-identifiers" TARGET core_interface SKIP_LINK) + +# Currently all versions of gcc are subject to a class of bugs, see the +# gccbug_90348 test case (only reproduces on GCC 11 and earlier) and +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111843. To work around that, set +# -fstack-reuse=none for all gcc builds. (Only gcc understands this flag). +try_append_cxx_flags("-fstack-reuse=none" TARGET core_interface) + +if(ENABLE_HARDENING) + add_library(hardening_interface INTERFACE) + target_link_libraries(core_interface INTERFACE hardening_interface) + if(MSVC) + try_append_linker_flag("/DYNAMICBASE" TARGET hardening_interface) + try_append_linker_flag("/HIGHENTROPYVA" TARGET hardening_interface) + try_append_linker_flag("/NXCOMPAT" TARGET hardening_interface) + else() + + # _FORTIFY_SOURCE requires that there is some level of optimization, + # otherwise it does nothing and just creates a compiler warning. + try_append_cxx_flags("-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3" + RESULT_VAR cxx_supports_fortify_source + SOURCE "int main() { + # if !defined __OPTIMIZE__ || __OPTIMIZE__ <= 0 + #error + #endif + }" + ) + if(cxx_supports_fortify_source) + target_compile_options(hardening_interface INTERFACE + -U_FORTIFY_SOURCE + -D_FORTIFY_SOURCE=3 + ) + endif() + unset(cxx_supports_fortify_source) + + try_append_cxx_flags("-Wstack-protector" TARGET hardening_interface SKIP_LINK) + try_append_cxx_flags("-fstack-protector-all" TARGET hardening_interface) + try_append_cxx_flags("-fcf-protection=full" TARGET hardening_interface) + + if(MINGW) + # stack-clash-protection doesn't compile with GCC 10 and earlier. + # In any case, it is a no-op for Windows. + # See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90458 for more details. + else() + try_append_cxx_flags("-fstack-clash-protection" TARGET hardening_interface) + endif() + + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + try_append_cxx_flags("-mbranch-protection=bti" TARGET hardening_interface SKIP_LINK) + else() + try_append_cxx_flags("-mbranch-protection=standard" TARGET hardening_interface SKIP_LINK) + endif() + endif() + + try_append_linker_flag("-Wl,--enable-reloc-section" TARGET hardening_interface) + try_append_linker_flag("-Wl,--dynamicbase" TARGET hardening_interface) + try_append_linker_flag("-Wl,--nxcompat" TARGET hardening_interface) + try_append_linker_flag("-Wl,--high-entropy-va" TARGET hardening_interface) + try_append_linker_flag("-Wl,-z,relro" TARGET hardening_interface) + try_append_linker_flag("-Wl,-z,now" TARGET hardening_interface) + try_append_linker_flag("-Wl,-z,separate-code" TARGET hardening_interface) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + try_append_linker_flag("-Wl,-fixup_chains" TARGET hardening_interface) + endif() + endif() +endif() + +if(REDUCE_EXPORTS) + set(CMAKE_CXX_VISIBILITY_PRESET hidden) + try_append_linker_flag("-Wl,--exclude-libs,ALL" TARGET core_interface) + try_append_linker_flag("-Wl,-no_exported_symbols" VAR CMAKE_EXE_LINKER_FLAGS) +endif() + +if(WERROR) + if(MSVC) + set(werror_flag "/WX") + else() + set(werror_flag "-Werror") + endif() + try_append_cxx_flags(${werror_flag} TARGET core_interface SKIP_LINK RESULT_VAR compiler_supports_werror) + if(NOT compiler_supports_werror) + message(FATAL_ERROR "WERROR set but ${werror_flag} is not usable.") + endif() + unset(werror_flag) +endif() + +find_package(Python3 3.10 COMPONENTS Interpreter) +if(Python3_EXECUTABLE) + set(PYTHON_COMMAND ${Python3_EXECUTABLE}) +else() + list(APPEND configure_warnings + "Minimum required Python not found. Utils and rpcauth tests are disabled." + ) +endif() + +target_compile_definitions(core_interface INTERFACE ${DEPENDS_COMPILE_DEFINITIONS}) +target_compile_definitions(core_interface_relwithdebinfo INTERFACE ${DEPENDS_COMPILE_DEFINITIONS_RELWITHDEBINFO}) +target_compile_definitions(core_interface_debug INTERFACE ${DEPENDS_COMPILE_DEFINITIONS_DEBUG}) + +# If the {CXX,LD}FLAGS environment variables are defined during building depends +# and configuring this build system, their content might be duplicated. +if(DEFINED ENV{CXXFLAGS}) + deduplicate_flags(CMAKE_CXX_FLAGS) +endif() +if(DEFINED ENV{LDFLAGS}) + deduplicate_flags(CMAKE_EXE_LINKER_FLAGS) +endif() + +if(BUILD_TESTS) + enable_testing() +endif() +# TODO: The `CMAKE_SKIP_BUILD_RPATH` variable setting can be deleted +# in the future after reordering Guix script commands to +# perform binary checks after the installation step. +# Relevant discussions: +# - https://github.com/hebasto/bitcoin/pull/236#issuecomment-2183120953 +# - https://github.com/bitcoin/bitcoin/pull/30312#issuecomment-2191235833 +set(CMAKE_SKIP_BUILD_RPATH TRUE) +set(CMAKE_SKIP_INSTALL_RPATH TRUE) +add_subdirectory(test) +add_subdirectory(doc) + +include(cmake/crc32c.cmake) +include(cmake/leveldb.cmake) +include(cmake/minisketch.cmake) +add_subdirectory(src) + +include(cmake/tests.cmake) + +include(Maintenance) +setup_split_debug_script() +add_maintenance_targets() +add_windows_deploy_target() +add_macos_deploy_target() + +message("\n") +message("Configure summary") +message("=================") +message("Executables:") +message(" bitcoind ............................ ${BUILD_DAEMON}") +message(" bitcoin-node (multiprocess) ......... ${WITH_MULTIPROCESS}") +message(" bitcoin-qt (GUI) .................... ${BUILD_GUI}") +if(BUILD_GUI AND WITH_MULTIPROCESS) + set(bitcoin_gui_status ON) +else() + set(bitcoin_gui_status OFF) +endif() +message(" bitcoin-gui (GUI, multiprocess) ..... ${bitcoin_gui_status}") +message(" bitcoin-cli ......................... ${BUILD_CLI}") +message(" bitcoin-tx .......................... ${BUILD_TX}") +message(" bitcoin-util ........................ ${BUILD_UTIL}") +message(" bitcoin-wallet ...................... ${BUILD_WALLET_TOOL}") +message(" bitcoin-chainstate (experimental) ... ${BUILD_UTIL_CHAINSTATE}") +message(" libbitcoinkernel (experimental) ..... ${BUILD_KERNEL_LIB}") +message("Optional features:") +message(" wallet support ...................... ${ENABLE_WALLET}") +if(ENABLE_WALLET) + message(" - descriptor wallets (SQLite) ...... ${WITH_SQLITE}") + message(" - legacy wallets (Berkeley DB) ..... ${WITH_BDB}") +endif() +message(" external signer ..................... ${ENABLE_EXTERNAL_SIGNER}") +message(" port mapping using UPnP ............. ${WITH_MINIUPNPC}") +message(" ZeroMQ .............................. ${WITH_ZMQ}") +message(" USDT tracing ........................ ${WITH_USDT}") +message(" QR code (GUI) ....................... ${WITH_QRENCODE}") +message(" DBus (GUI, Linux only) .............. ${WITH_DBUS}") +message("Tests:") +message(" test_bitcoin ........................ ${BUILD_TESTS}") +message(" test_bitcoin-qt ..................... ${BUILD_GUI_TESTS}") +message(" bench_bitcoin ....................... ${BUILD_BENCH}") +message(" fuzz binary ......................... ${BUILD_FUZZ_BINARY}") +message("") +if(CMAKE_CROSSCOMPILING) + set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}") +else() + set(cross_status "FALSE") +endif() +message("Cross compiling ....................... ${cross_status}") +message("C++ compiler .......................... ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}, ${CMAKE_CXX_COMPILER}") +include(FlagsSummary) +flags_summary() +message("Attempt to harden executables ......... ${ENABLE_HARDENING}") +message("Treat compiler warnings as errors ..... ${WERROR}") +message("Use ccache for compiling .............. ${WITH_CCACHE}") +message("\n") +if(configure_warnings) + message(" ******\n") + foreach(warning IN LISTS configure_warnings) + message(WARNING "${warning}") + endforeach() + message(" ******\n") +endif() + +# We want all build properties to be encapsulated properly. +include(WarnAboutGlobalProperties) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..3bbb61afce --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,96 @@ +{ + "version": 3, + "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0}, + "configurePresets": [ + { + "name": "vs2022", + "displayName": "Build using 'Visual Studio 17 2022' generator and 'x64-windows' triplet", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "generator": "Visual Studio 17 2022", + "architecture": "x64", + "toolchainFile": "$env{VCPKG_ROOT}\\scripts\\buildsystems\\vcpkg.cmake", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows", + "BUILD_GUI": "ON", + "WITH_QRENCODE": "OFF" + } + }, + { + "name": "vs2022-static", + "displayName": "Build using 'Visual Studio 17 2022' generator and 'x64-windows-static' triplet", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "generator": "Visual Studio 17 2022", + "architecture": "x64", + "toolchainFile": "$env{VCPKG_ROOT}\\scripts\\buildsystems\\vcpkg.cmake", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static", + "BUILD_GUI": "ON", + "WITH_QRENCODE": "OFF" + } + }, + { + "name": "libfuzzer", + "displayName": "Build for fuzzing with libfuzzer, and sanitizers enabled", + "binaryDir": "${sourceDir}/build_fuzz", + "cacheVariables": { + "BUILD_FOR_FUZZING": "ON", + "CMAKE_C_COMPILER": "clang", + "CMAKE_C_FLAGS": "-ftrivial-auto-var-init=pattern", + "CMAKE_CXX_COMPILER": "clang++", + "CMAKE_CXX_FLAGS": "-ftrivial-auto-var-init=pattern", + "SANITIZERS": "undefined,address,fuzzer" + } + }, + { + "name": "libfuzzer-nosan", + "displayName": "Build for fuzzing with libfuzzer, and sanitizers disabled", + "binaryDir": "${sourceDir}/build_fuzz_nosan", + "cacheVariables": { + "BUILD_FOR_FUZZING": "ON", + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++", + "SANITIZERS": "fuzzer" + } + }, + { + "name": "dev-mode", + "displayName": "Developer mode, with all features/dependencies enabled", + "binaryDir": "${sourceDir}/build_dev_mode", + "cacheVariables": { + "BUILD_BENCH": "ON", + "BUILD_CLI": "ON", + "BUILD_DAEMON": "ON", + "BUILD_FUZZ_BINARY": "ON", + "BUILD_GUI": "ON", + "BUILD_GUI_TESTS": "ON", + "BUILD_KERNEL_LIB": "ON", + "BUILD_SHARED_LIBS": "ON", + "BUILD_TESTING": "ON", + "BUILD_TESTS": "ON", + "BUILD_TX": "ON", + "BUILD_UTIL": "ON", + "BUILD_UTIL_CHAINSTATE": "ON", + "BUILD_WALLET_TOOL": "ON", + "ENABLE_EXTERNAL_SIGNER": "ON", + "ENABLE_HARDENING": "ON", + "ENABLE_WALLET": "ON", + "WARN_INCOMPATIBLE_BDB": "OFF", + "WITH_BDB": "ON", + "WITH_MINIUPNPC": "ON", + "WITH_MULTIPROCESS": "ON", + "WITH_QRENCODE": "ON", + "WITH_SQLITE": "ON", + "WITH_USDT": "ON", + "WITH_ZMQ": "ON" + } + } + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f594172333..e86ac5cb7a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -153,7 +153,7 @@ the pull request affects. Valid areas as: - `test`, `qa` or `ci` for changes to the unit tests, QA tests or CI code - `util` or `lib` for changes to the utils or libraries - `wallet` for changes to the wallet code - - `build` for changes to the GNU Autotools or MSVC builds + - `build` for changes to CMake - `guix` for changes to the GUIX reproducible builds Examples: diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 2ff6dd0a11..0000000000 --- a/Makefile.am +++ /dev/null @@ -1,347 +0,0 @@ -# Copyright (c) 2013-2020 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Pattern rule to print variables, e.g. make print-top_srcdir -print-%: FORCE - @echo '$*'='$($*)' - -ACLOCAL_AMFLAGS = -I build-aux/m4 -SUBDIRS = src -if ENABLE_MAN -SUBDIRS += doc/man -endif -.PHONY: deploy FORCE -.INTERMEDIATE: $(COVERAGE_INFO) - -BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) -BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT) -BITCOIN_TEST_BIN=$(top_builddir)/src/test/$(BITCOIN_TEST_NAME)$(EXEEXT) -BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) -BITCOIN_TX_BIN=$(top_builddir)/src/$(BITCOIN_TX_NAME)$(EXEEXT) -BITCOIN_UTIL_BIN=$(top_builddir)/src/$(BITCOIN_UTIL_NAME)$(EXEEXT) -BITCOIN_WALLET_BIN=$(top_builddir)/src/$(BITCOIN_WALLET_TOOL_NAME)$(EXEEXT) -BITCOIN_NODE_BIN=$(top_builddir)/src/$(BITCOIN_MP_NODE_NAME)$(EXEEXT) -BITCOIN_GUI_BIN=$(top_builddir)/src/$(BITCOIN_MP_GUI_NAME)$(EXEEXT) -BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win64-setup$(EXEEXT) - -empty := -space := $(empty) $(empty) - -OSX_APP=Bitcoin-Qt.app -OSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME)) -OSX_ZIP = $(OSX_VOLNAME).zip -OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus -OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns -OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed - -DIST_CONTRIB = \ - $(top_srcdir)/test/sanitizer_suppressions/lsan \ - $(top_srcdir)/test/sanitizer_suppressions/tsan \ - $(top_srcdir)/test/sanitizer_suppressions/ubsan \ - $(top_srcdir)/contrib/linearize/linearize-data.py \ - $(top_srcdir)/contrib/linearize/linearize-hashes.py \ - $(top_srcdir)/contrib/signet/miner - -DIST_SHARE = \ - $(top_srcdir)/share/genbuild.sh \ - $(top_srcdir)/share/rpcauth - -BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ - $(top_srcdir)/contrib/devtools/security-check.py \ - $(top_srcdir)/contrib/devtools/utils.py - -WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ - $(top_srcdir)/share/pixmaps/nsis-header.bmp \ - $(top_srcdir)/share/pixmaps/nsis-wizard.bmp \ - $(top_srcdir)/doc/README_windows.txt - -OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_INSTALLER_ICONS) \ - $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh - -COVERAGE_INFO = $(COV_TOOL_WRAPPER) baseline.info \ - test_bitcoin_filtered.info total_coverage.info \ - baseline_filtered.info functional_test.info functional_test_filtered.info \ - test_bitcoin_coverage.info test_bitcoin.info fuzz.info fuzz_filtered.info fuzz_coverage.info - -dist-hook: - -$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf - - -if TARGET_WINDOWS -$(BITCOIN_WIN_INSTALLER): all-recursive - $(MKDIR_P) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_TEST_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_TX_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_WALLET_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_UTIL_BIN) $(top_builddir)/release - @test -f $(MAKENSIS) && echo 'OutFile "$@"' | cat $(top_builddir)/share/setup.nsi - | $(MAKENSIS) -V2 - || \ - echo error: could not build $@ - @echo built $@ - -deploy: $(BITCOIN_WIN_INSTALLER) -endif - -if TARGET_DARWIN -$(OSX_APP)/Contents/PkgInfo: - $(MKDIR_P) $(@D) - @echo "APPL????" > $@ - -$(OSX_APP)/Contents/Resources/empty.lproj: - $(MKDIR_P) $(@D) - @touch $@ - -$(OSX_APP)/Contents/Info.plist: $(OSX_PLIST) - $(MKDIR_P) $(@D) - $(INSTALL_DATA) $< $@ - -$(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS) - $(MKDIR_P) $(@D) - $(INSTALL_DATA) $< $@ - -$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: all-recursive - $(MKDIR_P) $(@D) - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $@ - -$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: - $(MKDIR_P) $(@D) - echo '{ CFBundleDisplayName = "$(PACKAGE_NAME)"; CFBundleName = "$(PACKAGE_NAME)"; }' > $@ - -OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ - $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ - $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings - -if BUILD_DARWIN -$(OSX_ZIP): $(OSX_APP_BUILT) $(OSX_PACKAGING) - $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR) -zip - -deploydir: $(OSX_ZIP) -else !BUILD_DARWIN -APP_DIST_DIR=$(top_builddir)/dist - -$(OSX_ZIP): deploydir - if [ -n "$(SOURCE_DATE_EPOCH)" ]; then find $(APP_DIST_DIR) -exec touch -d @$(SOURCE_DATE_EPOCH) {} +; fi - cd $(APP_DIST_DIR) && find . | sort | $(ZIP) -X@ $@ - -$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) - OBJDUMP=$(OBJDUMP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR) - -deploydir: $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt -endif !BUILD_DARWIN - -deploy: $(OSX_ZIP) -endif - -$(BITCOIN_QT_BIN): FORCE - $(MAKE) -C src qt/$(@F) - -$(BITCOIND_BIN): FORCE - $(MAKE) -C src $(@F) - -$(BITCOIN_CLI_BIN): FORCE - $(MAKE) -C src $(@F) - -$(BITCOIN_TX_BIN): FORCE - $(MAKE) -C src $(@F) - -$(BITCOIN_UTIL_BIN): FORCE - $(MAKE) -C src $(@F) - -$(BITCOIN_WALLET_BIN): FORCE - $(MAKE) -C src $(@F) - -$(BITCOIN_NODE_BIN): FORCE - $(MAKE) -C src $(@F) - -$(BITCOIN_GUI_BIN): FORCE - $(MAKE) -C src $(@F) - -if USE_LCOV -LCOV_FILTER_PATTERN = \ - -p "/usr/local/" \ - -p "/usr/include/" \ - -p "/usr/lib/" \ - -p "/usr/lib64/" \ - -p "src/leveldb/" \ - -p "src/crc32c/" \ - -p "src/bench/" \ - -p "src/crypto/ctaes" \ - -p "src/minisketch" \ - -p "src/secp256k1" \ - -p "depends" - -DIR_FUZZ_SEED_CORPUS ?= qa-assets/fuzz_seed_corpus - -$(COV_TOOL_WRAPPER): - @echo 'exec $(COV_TOOL) "$$@"' > $(COV_TOOL_WRAPPER) - @chmod +x $(COV_TOOL_WRAPPER) - -baseline.info: $(COV_TOOL_WRAPPER) - $(LCOV) $(LCOV_OPTS) -c -i -d $(abs_builddir)/src -o $@ - -baseline_filtered.info: baseline.info - $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ - $(LCOV) -a $@ $(LCOV_OPTS) -o $@ - -fuzz.info: baseline_filtered.info - @test/fuzz/test_runner.py $(DIR_FUZZ_SEED_CORPUS) -l DEBUG - $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t fuzz-tests -o $@ - $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src - -fuzz_filtered.info: fuzz.info - $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ - $(LCOV) -a $@ $(LCOV_OPTS) -o $@ - -test_bitcoin.info: baseline_filtered.info - $(MAKE) -C src/ check - $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src -t test_bitcoin -o $@ - $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src - -test_bitcoin_filtered.info: test_bitcoin.info - $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ - $(LCOV) -a $@ $(LCOV_OPTS) -o $@ - -functional_test.info: test_bitcoin_filtered.info - @test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS) - $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t functional-tests -o $@ - $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src - -functional_test_filtered.info: functional_test.info - $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ - $(LCOV) -a $@ $(LCOV_OPTS) -o $@ - -fuzz_coverage.info: fuzz_filtered.info - $(LCOV) $(LCOV_OPTS) -a baseline_filtered.info -a fuzz_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt - -test_bitcoin_coverage.info: baseline_filtered.info test_bitcoin_filtered.info - $(LCOV) $(LCOV_OPTS) -a baseline_filtered.info -a test_bitcoin_filtered.info -o $@ - -total_coverage.info: test_bitcoin_filtered.info functional_test_filtered.info - $(LCOV) $(LCOV_OPTS) -a baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt - -fuzz.coverage/.dirstamp: fuzz_coverage.info - $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) - @touch $@ - -test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info - $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) - @touch $@ - -total.coverage/.dirstamp: total_coverage.info - $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) - @touch $@ - -cov_fuzz: fuzz.coverage/.dirstamp - -cov: test_bitcoin.coverage/.dirstamp total.coverage/.dirstamp - -endif - -dist_noinst_SCRIPTS = autogen.sh - -EXTRA_DIST = $(DIST_SHARE) $(DIST_CONTRIB) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) - -EXTRA_DIST += \ - test/functional \ - test/fuzz - -EXTRA_DIST += \ - test/util/test_runner.py \ - test/util/data/bitcoin-util-test.json \ - test/util/data/blanktxv1.hex \ - test/util/data/blanktxv1.json \ - test/util/data/blanktxv2.hex \ - test/util/data/blanktxv2.json \ - test/util/data/tt-delin1-out.hex \ - test/util/data/tt-delin1-out.json \ - test/util/data/tt-delout1-out.hex \ - test/util/data/tt-delout1-out.json \ - test/util/data/tt-locktime317000-out.hex \ - test/util/data/tt-locktime317000-out.json \ - test/util/data/tx394b54bb.hex \ - test/util/data/txcreate1.hex \ - test/util/data/txcreate1.json \ - test/util/data/txcreate2.hex \ - test/util/data/txcreate2.json \ - test/util/data/txcreatedata1.hex \ - test/util/data/txcreatedata1.json \ - test/util/data/txcreatedata2.hex \ - test/util/data/txcreatedata2.json \ - test/util/data/txcreatedata_seq0.hex \ - test/util/data/txcreatedata_seq0.json \ - test/util/data/txcreatedata_seq1.hex \ - test/util/data/txcreatedata_seq1.json \ - test/util/data/txcreatemultisig1.hex \ - test/util/data/txcreatemultisig1.json \ - test/util/data/txcreatemultisig2.hex \ - test/util/data/txcreatemultisig2.json \ - test/util/data/txcreatemultisig3.hex \ - test/util/data/txcreatemultisig3.json \ - test/util/data/txcreatemultisig4.hex \ - test/util/data/txcreatemultisig4.json \ - test/util/data/txcreatemultisig5.json \ - test/util/data/txcreateoutpubkey1.hex \ - test/util/data/txcreateoutpubkey1.json \ - test/util/data/txcreateoutpubkey2.hex \ - test/util/data/txcreateoutpubkey2.json \ - test/util/data/txcreateoutpubkey3.hex \ - test/util/data/txcreateoutpubkey3.json \ - test/util/data/txcreatescript1.hex \ - test/util/data/txcreatescript1.json \ - test/util/data/txcreatescript2.hex \ - test/util/data/txcreatescript2.json \ - test/util/data/txcreatescript3.hex \ - test/util/data/txcreatescript3.json \ - test/util/data/txcreatescript4.hex \ - test/util/data/txcreatescript4.json \ - test/util/data/txcreatescript5.hex \ - test/util/data/txcreatescript6.hex \ - test/util/data/txcreatesignsegwit1.hex \ - test/util/data/txcreatesignv1.hex \ - test/util/data/txcreatesignv1.json \ - test/util/data/txcreatesignv2.hex \ - test/util/data/txreplace1.hex \ - test/util/data/txreplacenoinputs.hex \ - test/util/data/txreplaceomittedn.hex \ - test/util/data/txreplacesingleinput.hex \ - test/util/rpcauth-test.py - -CLEANFILES = $(OSX_ZIP) $(BITCOIN_WIN_INSTALLER) - -DISTCHECK_CONFIGURE_FLAGS = --enable-man - -doc/doxygen/.stamp: doc/Doxyfile FORCE - $(MKDIR_P) $(@D) - $(DOXYGEN) $^ - $(AM_V_at) touch $@ - -if HAVE_DOXYGEN -docs: doc/doxygen/.stamp -else -docs: - @echo "error: doxygen not found" -endif - -clean-docs: - rm -rf doc/doxygen - -clean-local: clean-docs - rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ fuzz.coverage/ test/tmp/ cache/ $(OSX_APP) - rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache share/rpcauth/__pycache__ - rm -rf dist/ test/lint/test_runner/target/ test/lint/__pycache__ - -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 -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 -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 -endif @@ -48,12 +48,13 @@ lots of money. Developers are strongly encouraged to write [unit tests](src/test/README.md) for new code, and to submit new unit tests for old code. Unit tests can be compiled and run -(assuming they weren't disabled in configure) with: `make check`. Further details on running +(assuming they weren't disabled during the generation of the build system) with: `ctest`. Further details on running and extending unit tests can be found in [/src/test/README.md](/src/test/README.md). There are also [regression and integration tests](/test), written in Python. -These tests can be run (if the [test dependencies](/test) are installed) with: `test/functional/test_runner.py` +These tests can be run (if the [test dependencies](/test) are installed) with: `build/test/functional/test_runner.py` +(assuming `build` is your build directory). The CI (Continuous Integration) systems make sure that every pull request is built for Windows, Linux, and macOS, and that unit/sanity tests are run automatically. diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 69c892ffa0..0000000000 --- a/autogen.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# Copyright (c) 2013-2019 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -export LC_ALL=C -set -e -srcdir="$(dirname "$0")" -cd "$srcdir" -if [ -z "${LIBTOOLIZE}" ] && GLIBTOOLIZE="$(command -v glibtoolize)"; then - LIBTOOLIZE="${GLIBTOOLIZE}" - export LIBTOOLIZE -fi -command -v autoreconf >/dev/null || \ - (echo "configuration failed, please install autoconf first" && exit 1) -autoreconf --install --force --warnings=all - -if expr "'$(build-aux/config.guess --timestamp)" \< "'$(depends/config.guess --timestamp)" > /dev/null; then - chmod ug+w build-aux/config.guess - chmod ug+w src/secp256k1/build-aux/config.guess - cp depends/config.guess build-aux - cp depends/config.guess src/secp256k1/build-aux -fi -if expr "'$(build-aux/config.sub --timestamp)" \< "'$(depends/config.sub --timestamp)" > /dev/null; then - chmod ug+w build-aux/config.sub - chmod ug+w src/secp256k1/build-aux/config.sub - cp depends/config.sub build-aux - cp depends/config.sub src/secp256k1/build-aux -fi diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 deleted file mode 100644 index f6620882a2..0000000000 --- a/build-aux/m4/ax_boost_base.m4 +++ /dev/null @@ -1,256 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# -# DESCRIPTION -# -# Test for the Boost C++ headers of a particular version (or newer) -# -# If no path to the installed boost library is given the macro searchs -# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates -# the $BOOST_ROOT environment variable. Further documentation is available -# at <http://randspringer.de/boost/index.html>. -# -# This macro calls: -# -# AC_SUBST(BOOST_CPPFLAGS) -# -# And sets: -# -# HAVE_BOOST -# -# Note that this macro has been modified compared to upstream. -# -# LICENSE -# -# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de> -# Copyright (c) 2009 Peter Adolphs -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 51 - -# example boost program (need to pass version) -m4_define([_AX_BOOST_BASE_PROGRAM], - [AC_LANG_PROGRAM([[ -#include <boost/version.hpp> -]],[[ -(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))])); -]])]) - -AC_DEFUN([AX_BOOST_BASE], -[ -AC_ARG_WITH([boost], - [AS_HELP_STRING([--with-boost@<:@=ARG@:>@], - [use Boost library from a standard location (ARG=yes), - from the specified location (ARG=<path>), - or disable it (ARG=no) - @<:@ARG=yes@:>@ ])], - [ - AS_CASE([$withval], - [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""], - [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""], - [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"]) - ], - [want_boost="yes"]) - -BOOST_CPPFLAGS="" -AS_IF([test "x$want_boost" = "xyes"], - [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])]) -AC_SUBST(BOOST_CPPFLAGS) -]) - - -# convert a version string in $2 to numeric and affect to polymorphic var $1 -AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[ - AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"]) - _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'` - _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'` - AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"], - [AC_MSG_ERROR([You should at least specify libboost major version])]) - _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'` - AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"], - [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"]) - _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` - AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"], - [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"]) - _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` - AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET) -]) - -dnl Run the detection of boost should be run only if $want_boost -AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ - _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1]) - succeeded=no - - - AC_REQUIRE([AC_CANONICAL_HOST]) - dnl On 64-bit systems check for system libraries in both lib64 and lib. - dnl The former is specified by FHS, but e.g. Debian does not adhere to - dnl this (as it rises problems for generic multi-arch support). - dnl The last entry in the list is chosen by default when no libraries - dnl are found, e.g. when only header-only libraries are installed! - AS_CASE([${host_cpu}], - [x86_64],[libsubdirs="lib64 libx32 lib lib64"], - [mips*64*],[libsubdirs="lib64 lib32 lib lib64"], - [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k],[libsubdirs="lib64 lib lib64"], - [libsubdirs="lib"] - ) - - dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give - dnl them priority over the other paths since, if libs are found there, they - dnl are almost assuredly the ones desired. - AS_CASE([${host_cpu}], - [i?86],[multiarch_libsubdir="lib/i386-${host_os}"], - [armv7l],[multiarch_libsubdir="lib/arm-${host_os}"], - [multiarch_libsubdir="lib/${host_cpu}-${host_os}"] - ) - - dnl first we check the system location for boost libraries - dnl this location is chosen if boost libraries are installed with the --layout=system option - dnl or if you install boost with RPM - AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ - AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) - AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[ - AC_MSG_RESULT([yes]) - BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" - for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do - AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"]) - AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[ - AC_MSG_RESULT([yes]) - break; - ], - [AC_MSG_RESULT([no])]) - done],[ - AC_MSG_RESULT([no])]) - ],[ - if test X"$cross_compiling" = Xyes; then - search_libsubdirs=$multiarch_libsubdir - else - search_libsubdirs="$multiarch_libsubdir $libsubdirs" - fi - for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew ; do - if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then - for libsubdir in $search_libsubdirs ; do - if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi - done - BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" - break; - fi - done - ]) - - AC_MSG_CHECKING([for Boost headers >= $1 ($WANT_BOOST_VERSION)]) - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - AC_REQUIRE([AC_PROG_CXX]) - AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ - AC_MSG_RESULT(yes) - succeeded=yes - found_system=yes - ],[ - ]) - AC_LANG_POP([C++]) - - - - dnl if we found no boost with system layout we search for boost libraries - dnl built and installed without the --layout=system option or for a staged(not installed) version - if test "x$succeeded" != "xyes" ; then - CPPFLAGS="$CPPFLAGS_SAVED" - BOOST_CPPFLAGS= - - _version=0 - if test -n "$_AX_BOOST_BASE_boost_path" ; then - if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then - for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` - V_CHECK=`expr $_version_tmp \> $_version` - if test "x$V_CHECK" = "x1" ; then - _version=$_version_tmp - fi - VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" - done - dnl if nothing found search for layout used in Windows distributions - if test -z "$BOOST_CPPFLAGS"; then - if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then - BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" - fi - fi - fi - else - if test "x$cross_compiling" != "xyes" ; then - for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local /opt/homebrew ; do - if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then - for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` - V_CHECK=`expr $_version_tmp \> $_version` - if test "x$V_CHECK" = "x1" ; then - _version=$_version_tmp - best_path=$_AX_BOOST_BASE_boost_path - fi - done - fi - done - - VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" - fi - - if test -n "$BOOST_ROOT" ; then - for libsubdir in $libsubdirs ; do - if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi - done - if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then - version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` - stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` - stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` - V_CHECK=`expr $stage_version_shorten \>\= $_version` - if test "x$V_CHECK" = "x1" ; then - AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) - BOOST_CPPFLAGS="-I$BOOST_ROOT" - fi - fi - fi - fi - - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ - AC_MSG_RESULT(yes) - succeeded=yes - found_system=yes - ],[ - ]) - AC_LANG_POP([C++]) - fi - - if test "x$succeeded" != "xyes" ; then - if test "x$_version" = "x0" ; then - AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]]) - else - AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) - fi - # execute ACTION-IF-NOT-FOUND (if present): - ifelse([$3], , :, [$3]) - else - AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) - # execute ACTION-IF-FOUND (if present): - ifelse([$2], , :, [$2]) - fi - - CPPFLAGS="$CPPFLAGS_SAVED" -]) diff --git a/build-aux/m4/ax_check_compile_flag.m4 b/build-aux/m4/ax_check_compile_flag.m4 deleted file mode 100644 index bd753b34d7..0000000000 --- a/build-aux/m4/ax_check_compile_flag.m4 +++ /dev/null @@ -1,53 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) -# -# DESCRIPTION -# -# Check whether the given FLAG works with the current language's compiler -# or gives an error. (Warnings, however, are ignored) -# -# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on -# success/failure. -# -# If EXTRA-FLAGS is defined, it is added to the current language's default -# flags (e.g. CFLAGS) when the check is done. The check is thus made with -# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to -# force the compiler to issue an error when a bad flag is given. -# -# INPUT gives an alternative input source to AC_COMPILE_IFELSE. -# -# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this -# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. -# -# LICENSE -# -# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> -# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 6 - -AC_DEFUN([AX_CHECK_COMPILE_FLAG], -[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF -AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl -AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ - ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS - _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" - AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], - [AS_VAR_SET(CACHEVAR,[yes])], - [AS_VAR_SET(CACHEVAR,[no])]) - _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) -AS_VAR_IF(CACHEVAR,yes, - [m4_default([$2], :)], - [m4_default([$3], :)]) -AS_VAR_POPDEF([CACHEVAR])dnl -])dnl AX_CHECK_COMPILE_FLAGS diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4 deleted file mode 100644 index 03a30ce4c7..0000000000 --- a/build-aux/m4/ax_check_link_flag.m4 +++ /dev/null @@ -1,53 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) -# -# DESCRIPTION -# -# Check whether the given FLAG works with the linker or gives an error. -# (Warnings, however, are ignored) -# -# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on -# success/failure. -# -# If EXTRA-FLAGS is defined, it is added to the linker's default flags -# when the check is done. The check is thus made with the flags: "LDFLAGS -# EXTRA-FLAGS FLAG". This can for example be used to force the linker to -# issue an error when a bad flag is given. -# -# INPUT gives an alternative input source to AC_LINK_IFELSE. -# -# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this -# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. -# -# LICENSE -# -# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> -# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 6 - -AC_DEFUN([AX_CHECK_LINK_FLAG], -[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF -AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl -AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ - ax_check_save_flags=$LDFLAGS - LDFLAGS="$LDFLAGS $4 $1" - AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], - [AS_VAR_SET(CACHEVAR,[yes])], - [AS_VAR_SET(CACHEVAR,[no])]) - LDFLAGS=$ax_check_save_flags]) -AS_VAR_IF(CACHEVAR,yes, - [m4_default([$2], :)], - [m4_default([$3], :)]) -AS_VAR_POPDEF([CACHEVAR])dnl -])dnl AX_CHECK_LINK_FLAGS diff --git a/build-aux/m4/ax_check_preproc_flag.m4 b/build-aux/m4/ax_check_preproc_flag.m4 deleted file mode 100644 index e43560fbd3..0000000000 --- a/build-aux/m4/ax_check_preproc_flag.m4 +++ /dev/null @@ -1,53 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_check_preproc_flag.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) -# -# DESCRIPTION -# -# Check whether the given FLAG works with the current language's -# preprocessor or gives an error. (Warnings, however, are ignored) -# -# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on -# success/failure. -# -# If EXTRA-FLAGS is defined, it is added to the preprocessor's default -# flags when the check is done. The check is thus made with the flags: -# "CPPFLAGS EXTRA-FLAGS FLAG". This can for example be used to force the -# preprocessor to issue an error when a bad flag is given. -# -# INPUT gives an alternative input source to AC_PREPROC_IFELSE. -# -# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this -# macro in sync with AX_CHECK_{COMPILE,LINK}_FLAG. -# -# LICENSE -# -# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> -# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 6 - -AC_DEFUN([AX_CHECK_PREPROC_FLAG], -[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF -AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]cppflags_$4_$1])dnl -AC_CACHE_CHECK([whether _AC_LANG preprocessor accepts $1], CACHEVAR, [ - ax_check_save_flags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $4 $1" - AC_PREPROC_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], - [AS_VAR_SET(CACHEVAR,[yes])], - [AS_VAR_SET(CACHEVAR,[no])]) - CPPFLAGS=$ax_check_save_flags]) -AS_VAR_IF(CACHEVAR,yes, - [m4_default([$2], :)], - [m4_default([$3], :)]) -AS_VAR_POPDEF([CACHEVAR])dnl -])dnl AX_CHECK_PREPROC_FLAGS diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 deleted file mode 100644 index 51a35054d0..0000000000 --- a/build-aux/m4/ax_cxx_compile_stdcxx.m4 +++ /dev/null @@ -1,1005 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the specified -# version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11', '14', '17', or '20' for -# the respective C++ standard version. -# -# The second argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -# -std=c++11). If neither is specified, you get whatever works, with -# preference for no added switch, and then for an extended mode. -# -# The third argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline support for the specified C++ standard is -# required and that the macro should error out if no mode with that -# support is found. If specified 'optional', then configuration proceeds -# regardless, after defining HAVE_CXX${VERSION} if and only if a -# supporting mode is found. -# -# LICENSE -# -# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> -# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> -# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> -# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com> -# Copyright (c) 2015 Paul Norman <penorman@mac.com> -# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu> -# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com> -# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com> -# Copyright (c) 2020 Jason Merrill <jason@redhat.com> -# Copyright (c) 2021 Jörn Heusipp <osmanx@problemloesungsmaschine.de> -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 14 - -dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro -dnl (serial version number 13). - -AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl - m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], - [$1], [14], [ax_cxx_compile_alternatives="14 1y"], - [$1], [17], [ax_cxx_compile_alternatives="17 1z"], - [$1], [20], [ax_cxx_compile_alternatives="20"], - [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$2], [], [], - [$2], [ext], [], - [$2], [noext], [], - [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], - [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], - [$3], [optional], [ax_cxx_compile_cxx$1_required=false], - [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) - AC_LANG_PUSH([C++])dnl - ac_success=no - - m4_if([$2], [], [dnl - AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, - ax_cv_cxx_compile_cxx$1, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [ax_cv_cxx_compile_cxx$1=yes], - [ax_cv_cxx_compile_cxx$1=no])]) - if test x$ax_cv_cxx_compile_cxx$1 = xyes; then - ac_success=yes - fi]) - - m4_if([$2], [noext], [], [dnl - if test x$ac_success = xno; then - for alternative in ${ax_cxx_compile_alternatives}; do - switch="-std=gnu++${alternative}" - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - fi]) - - m4_if([$2], [ext], [], [dnl - if test x$ac_success = xno; then - dnl HP's aCC needs +std=c++11 according to: - dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf - dnl Cray's crayCC needs "-h std=c++11" - for alternative in ${ax_cxx_compile_alternatives}; do - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - if test x$ac_success = xyes; then - break - fi - done - fi]) - AC_LANG_POP([C++]) - if test x$ax_cxx_compile_cxx$1_required = xtrue; then - if test x$ac_success = xno; then - AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) - fi - fi - if test x$ac_success = xno; then - HAVE_CXX$1=0 - AC_MSG_NOTICE([No compiler with C++$1 support was found]) - else - HAVE_CXX$1=1 - AC_DEFINE(HAVE_CXX$1,1, - [define if the compiler supports basic C++$1 syntax]) - fi - AC_SUBST(HAVE_CXX$1) -]) - - -dnl Test body for checking C++11 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 -) - -dnl Test body for checking C++14 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 -) - -dnl Test body for checking C++17 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 -) - -dnl Test body for checking C++20 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 -) - - -dnl Tests for new features in C++11 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ - -// If the compiler admits that it is not ready for C++11, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201103L - -#error "This is not a C++11 compiler" - -#else - -namespace cxx11 -{ - - namespace test_static_assert - { - - template <typename T> - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - } - - namespace test_final_override - { - - struct Base - { - virtual ~Base() {} - virtual void f() {} - }; - - struct Derived : public Base - { - virtual ~Derived() override {} - virtual void f() override {} - }; - - } - - namespace test_double_right_angle_brackets - { - - template < typename T > - struct check {}; - - typedef check<void> single_type; - typedef check<check<void>> double_type; - typedef check<check<check<void>>> triple_type; - typedef check<check<check<check<void>>>> quadruple_type; - - } - - namespace test_decltype - { - - int - f() - { - int a = 1; - decltype(a) b = 2; - return a + b; - } - - } - - namespace test_type_deduction - { - - template < typename T1, typename T2 > - struct is_same - { - static const bool value = false; - }; - - template < typename T > - struct is_same<T, T> - { - static const bool value = true; - }; - - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) - { - return a1 + a2; - } - - int - test(const int c, volatile int v) - { - static_assert(is_same<int, decltype(0)>::value == true, ""); - static_assert(is_same<int, decltype(c)>::value == false, ""); - static_assert(is_same<int, decltype(v)>::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same<int, decltype(ac)>::value == true, ""); - static_assert(is_same<int, decltype(av)>::value == true, ""); - static_assert(is_same<int, decltype(sumi)>::value == true, ""); - static_assert(is_same<int, decltype(sumf)>::value == false, ""); - static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); - } - - } - - namespace test_noexcept - { - - int f() { return 0; } - int g() noexcept { return 0; } - - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); - - } - - namespace test_constexpr - { - - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept - { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; - } - - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept - { - return strlen_c_r(s, 0UL); - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); - - } - - namespace test_rvalue_references - { - - template < int N > - struct answer - { - static constexpr int value = N; - }; - - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } - - void - test() - { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); - } - - } - - namespace test_uniform_initialization - { - - struct test - { - static const int zero {}; - static const int one {1}; - }; - - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); - - } - - namespace test_lambdas - { - - void - test1() - { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); - } - - int - test2() - { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; - } - - int - test3() - { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); - } - - } - - namespace test_variadic_templates - { - - template <int...> - struct sum; - - template <int N0, int... N1toN> - struct sum<N0, N1toN...> - { - static constexpr auto value = N0 + sum<N1toN...>::value; - }; - - template <> - struct sum<> - { - static constexpr auto value = 0; - }; - - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - - } - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae - { - - struct foo {}; - - template<typename T> - using member = typename T::member_type; - - template<typename T> - void func(...) {} - - template<typename T> - void func(member<T>*) {} - - void test(); - - void test() { func<foo>(0); } - - } - -} // namespace cxx11 - -#endif // __cplusplus >= 201103L - -]]) - - -dnl Tests for new features in C++14 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ - -// If the compiler admits that it is not ready for C++14, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201402L - -#error "This is not a C++14 compiler" - -#else - -namespace cxx14 -{ - - namespace test_polymorphic_lambdas - { - - int - test() - { - const auto lambda = [](auto&&... args){ - const auto istiny = [](auto x){ - return (sizeof(x) == 1UL) ? 1 : 0; - }; - const int aretiny[] = { istiny(args)... }; - return aretiny[0]; - }; - return lambda(1, 1L, 1.0f, '1'); - } - - } - - namespace test_binary_literals - { - - constexpr auto ivii = 0b0000000000101010; - static_assert(ivii == 42, "wrong value"); - - } - - namespace test_generalized_constexpr - { - - template < typename CharT > - constexpr unsigned long - strlen_c(const CharT *const s) noexcept - { - auto length = 0UL; - for (auto p = s; *p; ++p) - ++length; - return length; - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("x") == 1UL, ""); - static_assert(strlen_c("test") == 4UL, ""); - static_assert(strlen_c("another\0test") == 7UL, ""); - - } - - namespace test_lambda_init_capture - { - - int - test() - { - auto x = 0; - const auto lambda1 = [a = x](int b){ return a + b; }; - const auto lambda2 = [a = lambda1(x)](){ return a; }; - return lambda2(); - } - - } - - namespace test_digit_separators - { - - constexpr auto ten_million = 100'000'000; - static_assert(ten_million == 100000000, ""); - - } - - namespace test_return_type_deduction - { - - auto f(int& x) { return x; } - decltype(auto) g(int& x) { return x; } - - template < typename T1, typename T2 > - struct is_same - { - static constexpr auto value = false; - }; - - template < typename T > - struct is_same<T, T> - { - static constexpr auto value = true; - }; - - int - test() - { - auto x = 0; - static_assert(is_same<int, decltype(f(x))>::value, ""); - static_assert(is_same<int&, decltype(g(x))>::value, ""); - return x; - } - - } - -} // namespace cxx14 - -#endif // __cplusplus >= 201402L - -]]) - - -dnl Tests for new features in C++17 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ - -// If the compiler admits that it is not ready for C++17, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201703L - -#error "This is not a C++17 compiler" - -#else - -#include <initializer_list> -#include <utility> -#include <type_traits> - -namespace cxx17 -{ - - namespace test_constexpr_lambdas - { - - constexpr int foo = [](){return 42;}(); - - } - - namespace test::nested_namespace::definitions - { - - } - - namespace test_fold_expression - { - - template<typename... Args> - int multiply(Args... args) - { - return (args * ... * 1); - } - - template<typename... Args> - bool all(Args... args) - { - return (args && ...); - } - - } - - namespace test_extended_static_assert - { - - static_assert (true); - - } - - namespace test_auto_brace_init_list - { - - auto foo = {5}; - auto bar {5}; - - static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value); - static_assert(std::is_same<int, decltype(bar)>::value); - } - - namespace test_typename_in_template_template_parameter - { - - template<template<typename> typename X> struct D; - - } - - namespace test_fallthrough_nodiscard_maybe_unused_attributes - { - - int f1() - { - return 42; - } - - [[nodiscard]] int f2() - { - [[maybe_unused]] auto unused = f1(); - - switch (f1()) - { - case 17: - f1(); - [[fallthrough]]; - case 42: - f1(); - } - return f1(); - } - - } - - namespace test_extended_aggregate_initialization - { - - struct base1 - { - int b1, b2 = 42; - }; - - struct base2 - { - base2() { - b3 = 42; - } - int b3; - }; - - struct derived : base1, base2 - { - int d; - }; - - derived d1 {{1, 2}, {}, 4}; // full initialization - derived d2 {{}, {}, 4}; // value-initialized bases - - } - - namespace test_general_range_based_for_loop - { - - struct iter - { - int i; - - int& operator* () - { - return i; - } - - const int& operator* () const - { - return i; - } - - iter& operator++() - { - ++i; - return *this; - } - }; - - struct sentinel - { - int i; - }; - - bool operator== (const iter& i, const sentinel& s) - { - return i.i == s.i; - } - - bool operator!= (const iter& i, const sentinel& s) - { - return !(i == s); - } - - struct range - { - iter begin() const - { - return {0}; - } - - sentinel end() const - { - return {5}; - } - }; - - void f() - { - range r {}; - - for (auto i : r) - { - [[maybe_unused]] auto v = i; - } - } - - } - - namespace test_lambda_capture_asterisk_this_by_value - { - - struct t - { - int i; - int foo() - { - return [*this]() - { - return i; - }(); - } - }; - - } - - namespace test_enum_class_construction - { - - enum class byte : unsigned char - {}; - - byte foo {42}; - - } - - namespace test_constexpr_if - { - - template <bool cond> - int f () - { - if constexpr(cond) - { - return 13; - } - else - { - return 42; - } - } - - } - - namespace test_selection_statement_with_initializer - { - - int f() - { - return 13; - } - - int f2() - { - if (auto i = f(); i > 0) - { - return 3; - } - - switch (auto i = f(); i + 4) - { - case 17: - return 2; - - default: - return 1; - } - } - - } - - namespace test_template_argument_deduction_for_class_templates - { - - template <typename T1, typename T2> - struct pair - { - pair (T1 p1, T2 p2) - : m1 {p1}, - m2 {p2} - {} - - T1 m1; - T2 m2; - }; - - void f() - { - [[maybe_unused]] auto p = pair{13, 42u}; - } - - } - - namespace test_non_type_auto_template_parameters - { - - template <auto n> - struct B - {}; - - B<5> b1; - B<'a'> b2; - - } - - namespace test_structured_bindings - { - - int arr[2] = { 1, 2 }; - std::pair<int, int> pr = { 1, 2 }; - - auto f1() -> int(&)[2] - { - return arr; - } - - auto f2() -> std::pair<int, int>& - { - return pr; - } - - struct S - { - int x1 : 2; - volatile double y1; - }; - - S f3() - { - return {}; - } - - auto [ x1, y1 ] = f1(); - auto& [ xr1, yr1 ] = f1(); - auto [ x2, y2 ] = f2(); - auto& [ xr2, yr2 ] = f2(); - const auto [ x3, y3 ] = f3(); - - } - - namespace test_exception_spec_type_system - { - - struct Good {}; - struct Bad {}; - - void g1() noexcept; - void g2(); - - template<typename T> - Bad - f(T*, T*); - - template<typename T1, typename T2> - Good - f(T1*, T2*); - - static_assert (std::is_same_v<Good, decltype(f(g1, g2))>); - - } - - namespace test_inline_variables - { - - template<class T> void f(T) - {} - - template<class T> inline T g(T) - { - return T{}; - } - - template<> inline void f<>(int) - {} - - template<> int g<>(int) - { - return 5; - } - - } - -} // namespace cxx17 - -#endif // __cplusplus < 201703L - -]]) - - -dnl Tests for new features in C++20 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 202002L - -#error "This is not a C++20 compiler" - -#else - -#include <version> - -namespace cxx20 -{ - -// As C++20 supports feature test macros in the standard, there is no -// immediate need to actually test for feature availability on the -// Autoconf side. - -} // namespace cxx20 - -#endif // __cplusplus < 202002L - -]]) diff --git a/build-aux/m4/ax_pthread.m4 b/build-aux/m4/ax_pthread.m4 deleted file mode 100644 index 9f35d13914..0000000000 --- a/build-aux/m4/ax_pthread.m4 +++ /dev/null @@ -1,522 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_pthread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -# -# DESCRIPTION -# -# This macro figures out how to build C programs using POSIX threads. It -# sets the PTHREAD_LIBS output variable to the threads library and linker -# flags, and the PTHREAD_CFLAGS output variable to any special C compiler -# flags that are needed. (The user can also force certain compiler -# flags/libs to be tested by setting these environment variables.) -# -# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is -# needed for multi-threaded programs (defaults to the value of CC -# respectively CXX otherwise). (This is necessary on e.g. AIX to use the -# special cc_r/CC_r compiler alias.) -# -# NOTE: You are assumed to not only compile your program with these flags, -# but also to link with them as well. For example, you might link with -# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS -# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS -# -# If you are only building threaded programs, you may wish to use these -# variables in your default LIBS, CFLAGS, and CC: -# -# LIBS="$PTHREAD_LIBS $LIBS" -# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" -# CC="$PTHREAD_CC" -# CXX="$PTHREAD_CXX" -# -# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to -# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -# -# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the -# PTHREAD_PRIO_INHERIT symbol is defined when compiling with -# PTHREAD_CFLAGS. -# -# ACTION-IF-FOUND is a list of shell commands to run if a threads library -# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it -# is not found. If ACTION-IF-FOUND is not specified, the default action -# will define HAVE_PTHREAD. -# -# Please let the authors know if this macro fails on any platform, or if -# you have any other suggestions or comments. This macro was based on work -# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help -# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by -# Alejandro Forero Cuervo to the autoconf macro repository. We are also -# grateful for the helpful feedback of numerous users. -# -# Updated for Autoconf 2.68 by Daniel Richard G. -# -# LICENSE -# -# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu> -# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG> -# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl> -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see <https://www.gnu.org/licenses/>. -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 31 - -AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) -AC_DEFUN([AX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AC_PROG_SED]) -AC_LANG_PUSH([C]) -ax_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on Tru64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then - ax_pthread_save_CC="$CC" - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) - AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"]) - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) - AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = "xno"; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - CC="$ax_pthread_save_CC" - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items with a "," contain both -# C compiler flags (before ",") and linker flags (after ","). Other items -# starting with a "-" are C compiler flags, and remaining items are -# library names, except for "none" which indicates that we try without -# any flags at all, and "pthread-config" which is a program returning -# the flags for the Pth emulation library. - -ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 -# (Note: HP C rejects this with "bad form for `-t' option") -# -pthreads: Solaris/gcc (Note: HP C also rejects) -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads and -# -D_REENTRANT too), HP C (must be checked before -lpthread, which -# is present but should not be used directly; and before -mthreads, -# because the compiler interprets this as "-mt" + "-hreads") -# -mthreads: Mingw32/gcc, Lynx/gcc -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case $host_os in - - freebsd*) - - # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) - # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) - - ax_pthread_flags="-kthread lthread $ax_pthread_flags" - ;; - - hpux*) - - # From the cc(1) man page: "[-mt] Sets various -D flags to enable - # multi-threading and also sets -lpthread." - - ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" - ;; - - openedition*) - - # IBM z/OS requires a feature-test macro to be defined in order to - # enable POSIX threads at all, so give the user a hint if this is - # not set. (We don't define these ourselves, as they can affect - # other portions of the system API in unpredictable ways.) - - AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], - [ -# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) - AX_PTHREAD_ZOS_MISSING -# endif - ], - [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) - ;; - - solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (N.B.: The stubs are missing - # pthread_cleanup_push, or rather a function called by this macro, - # so we could check for that, but who knows whether they'll stub - # that too in a future libc.) So we'll check first for the - # standard Solaris way of linking pthreads (-mt -lpthread). - - ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" - ;; -esac - -# Are we compiling with Clang? - -AC_CACHE_CHECK([whether $CC is Clang], - [ax_cv_PTHREAD_CLANG], - [ax_cv_PTHREAD_CLANG=no - # Note that Autoconf sets GCC=yes for Clang as well as GCC - if test "x$GCC" = "xyes"; then - AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], - [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ -# if defined(__clang__) && defined(__llvm__) - AX_PTHREAD_CC_IS_CLANG -# endif - ], - [ax_cv_PTHREAD_CLANG=yes]) - fi - ]) -ax_pthread_clang="$ax_cv_PTHREAD_CLANG" - - -# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) - -# Note that for GCC and Clang -pthread generally implies -lpthread, -# except when -nostdlib is passed. -# This is problematic using libtool to build C++ shared libraries with pthread: -# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 -# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 -# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 -# To solve this, first try -pthread together with -lpthread for GCC - -AS_IF([test "x$GCC" = "xyes"], - [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"]) - -# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first - -AS_IF([test "x$ax_pthread_clang" = "xyes"], - [ax_pthread_flags="-pthread,-lpthread -pthread"]) - - -# The presence of a feature test macro requesting re-entrant function -# definitions is, on some systems, a strong hint that pthreads support is -# correctly enabled - -case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) - ax_pthread_check_macro="_REENTRANT" - ;; - - aix*) - ax_pthread_check_macro="_THREAD_SAFE" - ;; - - *) - ax_pthread_check_macro="--" - ;; -esac -AS_IF([test "x$ax_pthread_check_macro" = "x--"], - [ax_pthread_check_cond=0], - [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) - - -if test "x$ax_pthread_ok" = "xno"; then -for ax_pthread_try_flag in $ax_pthread_flags; do - - case $ax_pthread_try_flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - *,*) - PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` - PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` - AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) - PTHREAD_CFLAGS="$ax_pthread_try_flag" - ;; - - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) - PTHREAD_LIBS="-l$ax_pthread_try_flag" - ;; - esac - - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h> -# if $ax_pthread_check_cond -# error "$ax_pthread_check_macro must be defined" -# endif - static void *some_global = NULL; - static void routine(void *a) - { - /* To avoid any unused-parameter or - unused-but-set-parameter warning. */ - some_global = a; - } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - AC_MSG_RESULT([$ax_pthread_ok]) - AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - - -# Clang needs special handling, because older versions handle the -pthread -# option in a rather... idiosyncratic way - -if test "x$ax_pthread_clang" = "xyes"; then - - # Clang takes -pthread; it has never supported any other flag - - # (Note 1: This will need to be revisited if a system that Clang - # supports has POSIX threads in a separate library. This tends not - # to be the way of modern systems, but it's conceivable.) - - # (Note 2: On some systems, notably Darwin, -pthread is not needed - # to get POSIX threads support; the API is always present and - # active. We could reasonably leave PTHREAD_CFLAGS empty. But - # -pthread does define _REENTRANT, and while the Darwin headers - # ignore this macro, third-party headers might not.) - - # However, older versions of Clang make a point of warning the user - # that, in an invocation where only linking and no compilation is - # taking place, the -pthread option has no effect ("argument unused - # during compilation"). They expect -pthread to be passed in only - # when source code is being compiled. - # - # Problem is, this is at odds with the way Automake and most other - # C build frameworks function, which is that the same flags used in - # compilation (CFLAGS) are also used in linking. Many systems - # supported by AX_PTHREAD require exactly this for POSIX threads - # support, and in fact it is often not straightforward to specify a - # flag that is used only in the compilation phase and not in - # linking. Such a scenario is extremely rare in practice. - # - # Even though use of the -pthread flag in linking would only print - # a warning, this can be a nuisance for well-run software projects - # that build with -Werror. So if the active version of Clang has - # this misfeature, we search for an option to squash it. - - AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown - # Create an alternate version of $ac_link that compiles and - # links in two steps (.c -> .o, .o -> exe) instead of one - # (.c -> exe), because the warning occurs only in the second - # step - ax_pthread_save_ac_link="$ac_link" - ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' - ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"` - ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" - ax_pthread_save_CFLAGS="$CFLAGS" - for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do - AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) - CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" - ac_link="$ax_pthread_save_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [ac_link="$ax_pthread_2step_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [break]) - ]) - done - ac_link="$ax_pthread_save_ac_link" - CFLAGS="$ax_pthread_save_CFLAGS" - AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) - ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" - ]) - - case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in - no | unknown) ;; - *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; - esac - -fi # $ax_pthread_clang = yes - - - -# Various other checks: -if test "x$ax_pthread_ok" = "xyes"; then - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_CACHE_CHECK([for joinable pthread attribute], - [ax_cv_PTHREAD_JOINABLE_ATTR], - [ax_cv_PTHREAD_JOINABLE_ATTR=unknown - for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>], - [int attr = $ax_pthread_attr; return attr /* ; */])], - [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], - []) - done - ]) - AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ - test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ - test "x$ax_pthread_joinable_attr_defined" != "xyes"], - [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], - [$ax_cv_PTHREAD_JOINABLE_ATTR], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - ax_pthread_joinable_attr_defined=yes - ]) - - AC_CACHE_CHECK([whether more special flags are required for pthreads], - [ax_cv_PTHREAD_SPECIAL_FLAGS], - [ax_cv_PTHREAD_SPECIAL_FLAGS=no - case $host_os in - solaris*) - ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" - ;; - esac - ]) - AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ - test "x$ax_pthread_special_flags_added" != "xyes"], - [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" - ax_pthread_special_flags_added=yes]) - - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]], - [[int i = PTHREAD_PRIO_INHERIT; - return i;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ - test "x$ax_pthread_prio_inherit_defined" != "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) - ax_pthread_prio_inherit_defined=yes - ]) - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - # More AIX lossage: compile with *_r variant - if test "x$GCC" != "xyes"; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [ - AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"]) - AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])]) - ], - [ - AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC]) - AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])]) - ] - ) - ]) - ;; - esac - fi -fi - -test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" -test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" - -AC_SUBST([PTHREAD_LIBS]) -AC_SUBST([PTHREAD_CFLAGS]) -AC_SUBST([PTHREAD_CC]) -AC_SUBST([PTHREAD_CXX]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test "x$ax_pthread_ok" = "xyes"; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : -else - ax_pthread_ok=no - $2 -fi -AC_LANG_POP -])dnl AX_PTHREAD diff --git a/build-aux/m4/bitcoin_find_bdb48.m4 b/build-aux/m4/bitcoin_find_bdb48.m4 deleted file mode 100644 index 3ef7fab5b5..0000000000 --- a/build-aux/m4/bitcoin_find_bdb48.m4 +++ /dev/null @@ -1,97 +0,0 @@ -dnl Copyright (c) 2013-2015 The Bitcoin Core developers -dnl Distributed under the MIT software license, see the accompanying -dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. - -AC_DEFUN([BITCOIN_FIND_BDB48],[ - AC_ARG_VAR([BDB_CFLAGS], [C compiler flags for BerkeleyDB, bypasses autodetection]) - AC_ARG_VAR([BDB_LIBS], [Linker flags for BerkeleyDB, bypasses autodetection]) - - if test "$use_bdb" = "no"; then - use_bdb=no - elif test "$BDB_CFLAGS" = ""; then - AC_MSG_CHECKING([for Berkeley DB C++ headers]) - BDB_CPPFLAGS= - bdbpath=X - bdb48path=X - bdbdirlist= - for _vn in 4.8 48 4 5 5.3 ''; do - for _pfx in b lib ''; do - bdbdirlist="$bdbdirlist ${_pfx}db${_vn}" - done - done - for searchpath in $bdbdirlist ''; do - test -n "${searchpath}" && searchpath="${searchpath}/" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <${searchpath}db_cxx.h> - ]],[[ - #if !((DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || DB_VERSION_MAJOR > 4) - #error "failed to find bdb 4.8+" - #endif - ]])],[ - if test "$bdbpath" = "X"; then - bdbpath="${searchpath}" - fi - ],[ - continue - ]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <${searchpath}db_cxx.h> - ]],[[ - #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8) - #error "failed to find bdb 4.8" - #endif - ]])],[ - bdb48path="${searchpath}" - break - ],[]) - done - if test "$bdbpath" = "X"; then - use_bdb=no - AC_MSG_RESULT([no]) - AC_MSG_WARN([libdb_cxx headers missing]) - AC_MSG_WARN(AC_PACKAGE_NAME[ requires this library for BDB (legacy) wallet support]) - AC_MSG_WARN([Passing --without-bdb will suppress this warning]) - elif test "$bdb48path" = "X"; then - BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx) - AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[ - AC_MSG_WARN([Found Berkeley DB other than 4.8]) - AC_MSG_WARN([BDB (legacy) wallets opened by this build will not be portable!]) - use_bdb=yes - ],[ - AC_MSG_WARN([Found Berkeley DB other than 4.8]) - AC_MSG_WARN([BDB (legacy) wallets opened by this build would not be portable!]) - AC_MSG_WARN([If this is intended, pass --with-incompatible-bdb]) - AC_MSG_WARN([Passing --without-bdb will suppress this warning]) - use_bdb=no - ]) - else - BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb48path}],db_cxx) - bdbpath="${bdb48path}" - use_bdb=yes - fi - else - BDB_CPPFLAGS=${BDB_CFLAGS} - fi - AC_SUBST(BDB_CPPFLAGS) - - if test "$use_bdb" = "no"; then - use_bdb=no - elif test "$BDB_LIBS" = ""; then - # TODO: Ideally this could find the library version and make sure it matches the headers being used - for searchlib in db_cxx-4.8 db_cxx db4_cxx; do - AC_CHECK_LIB([$searchlib],[main],[ - BDB_LIBS="-l${searchlib}" - break - ]) - done - if test "$BDB_LIBS" = ""; then - AC_MSG_WARN([libdb_cxx headers missing]) - AC_MSG_WARN(AC_PACKAGE_NAME[ requires this library for BDB (legacy) wallet support]) - AC_MSG_WARN([Passing --without-bdb will suppress this warning]) - fi - fi - if test "$use_bdb" != "no"; then - AC_DEFINE([USE_BDB], [1], [Define if BDB support should be compiled in]) - use_bdb=yes - fi -]) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 deleted file mode 100644 index b87c38a6ab..0000000000 --- a/build-aux/m4/bitcoin_qt.m4 +++ /dev/null @@ -1,375 +0,0 @@ -dnl Copyright (c) 2013-2016 The Bitcoin Core developers -dnl Distributed under the MIT software license, see the accompanying -dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. - -dnl Helper for cases where a qt dependency is not met. -dnl Output: If qt version is auto, set bitcoin_enable_qt to false. Else, exit. -AC_DEFUN([BITCOIN_QT_FAIL],[ - if test "$bitcoin_qt_want_version" = "auto" && test "$bitcoin_qt_force" != "yes"; then - if test "$bitcoin_enable_qt" != "no"; then - AC_MSG_WARN([$1; bitcoin-qt frontend will not be built]) - fi - bitcoin_enable_qt=no - bitcoin_enable_qt_test=no - else - AC_MSG_ERROR([$1]) - fi -]) - -AC_DEFUN([BITCOIN_QT_CHECK],[ - if test "$bitcoin_enable_qt" != "no" && test "$bitcoin_qt_want_version" != "no"; then - true - $1 - else - true - $2 - fi -]) - -dnl BITCOIN_QT_PATH_PROGS([FOO], [foo foo2], [/path/to/search/first], [continue if missing]) -dnl Helper for finding the path of programs needed for Qt. -dnl Inputs: $1: Variable to be set -dnl Inputs: $2: List of programs to search for -dnl Inputs: $3: Look for $2 here before $PATH -dnl Inputs: $4: If "yes", don't fail if $2 is not found. -dnl Output: $1 is set to the path of $2 if found. $2 are searched in order. -AC_DEFUN([BITCOIN_QT_PATH_PROGS],[ - BITCOIN_QT_CHECK([ - if test "$3" != ""; then - AC_PATH_PROGS([$1], [$2], [], [$3]) - else - AC_PATH_PROGS([$1], [$2]) - fi - if test "$$1" = "" && test "$4" != "yes"; then - BITCOIN_QT_FAIL([$1 not found]) - fi - ]) -]) - -dnl Initialize qt input. -dnl This must be called before any other BITCOIN_QT* macros to ensure that -dnl input variables are set correctly. -dnl CAUTION: Do not use this inside of a conditional. -AC_DEFUN([BITCOIN_QT_INIT],[ - dnl enable qt support - AC_ARG_WITH([gui], - [AS_HELP_STRING([--with-gui@<:@=no|qt5|auto@:>@], - [build bitcoin-qt GUI (default=auto)])], - [ - bitcoin_qt_want_version=$withval - if test "$bitcoin_qt_want_version" = "yes"; then - bitcoin_qt_force=yes - bitcoin_qt_want_version=auto - fi - ], - [bitcoin_qt_want_version=auto]) - - AS_IF([test "$with_gui" = "qt5_debug"], - [AS_CASE([$host], - [*darwin*], [qt_lib_suffix=_debug], - [qt_lib_suffix= ]); bitcoin_qt_want_version=qt5], - [qt_lib_suffix= ]) - - AC_ARG_WITH([qt-incdir],[AS_HELP_STRING([--with-qt-incdir=INC_DIR],[specify qt include path (overridden by pkgconfig)])], [qt_include_path=$withval], []) - AC_ARG_WITH([qt-libdir],[AS_HELP_STRING([--with-qt-libdir=LIB_DIR],[specify qt lib path (overridden by pkgconfig)])], [qt_lib_path=$withval], []) - AC_ARG_WITH([qt-plugindir],[AS_HELP_STRING([--with-qt-plugindir=PLUGIN_DIR],[specify qt plugin path (overridden by pkgconfig)])], [qt_plugin_path=$withval], []) - AC_ARG_WITH([qt-translationdir],[AS_HELP_STRING([--with-qt-translationdir=PLUGIN_DIR],[specify qt translation path (overridden by pkgconfig)])], [qt_translation_path=$withval], []) - AC_ARG_WITH([qt-bindir],[AS_HELP_STRING([--with-qt-bindir=BIN_DIR],[specify qt bin path])], [qt_bin_path=$withval], []) - - AC_ARG_WITH([qtdbus], - [AS_HELP_STRING([--with-qtdbus], - [enable DBus support (default is yes if qt is enabled and QtDBus is found)])], - [use_dbus=$withval], - [use_dbus=auto]) - - AC_SUBST(QT_TRANSLATION_DIR,$qt_translation_path) -]) - -dnl Find Qt libraries and includes. -dnl -dnl BITCOIN_QT_CONFIGURE([MINIMUM-VERSION]) -dnl -dnl Outputs: See _BITCOIN_QT_FIND_LIBS -dnl Outputs: Sets variables for all qt-related tools. -dnl Outputs: bitcoin_enable_qt, bitcoin_enable_qt_dbus, bitcoin_enable_qt_test -AC_DEFUN([BITCOIN_QT_CONFIGURE],[ - qt_version=">= $1" - qt_lib_prefix="Qt5" - BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS]) - - dnl This is ugly and complicated. Yuck. Works as follows: - dnl We check a header to find out whether Qt is built statically. - dnl When Qt is built statically, some plugins must be linked into - dnl the final binary as well. _BITCOIN_QT_CHECK_STATIC_PLUGIN does - dnl a quick link-check and appends the results to QT_LIBS. - BITCOIN_QT_CHECK([ - TEMP_CPPFLAGS=$CPPFLAGS - TEMP_CXXFLAGS=$CXXFLAGS - CPPFLAGS="$QT_INCLUDES $CORE_CPPFLAGS $CPPFLAGS" - CXXFLAGS="$PIC_FLAGS $CORE_CXXFLAGS $CXXFLAGS" - _BITCOIN_QT_IS_STATIC - if test "$bitcoin_cv_static_qt" = "yes"; then - _BITCOIN_QT_CHECK_STATIC_LIBS - - if test "$qt_plugin_path" != ""; then - if test -d "$qt_plugin_path/platforms"; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" - fi - if test -d "$qt_plugin_path/styles"; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/styles" - fi - if test -d "$qt_plugin_path/accessible"; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - 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 - dnl Linking against wtsapi32 is required. See #17749 and - dnl https://bugreports.qt.io/browse/QTBUG-27097. - AX_CHECK_LINK_FLAG([-lwtsapi32], [QT_LIBS="$QT_LIBS -lwtsapi32"], [AC_MSG_ERROR([could not link against -lwtsapi32])]) - _BITCOIN_QT_CHECK_STATIC_PLUGIN([QWindowsIntegrationPlugin], [-lqwindows]) - _BITCOIN_QT_CHECK_STATIC_PLUGIN([QWindowsVistaStylePlugin], [-lqwindowsvistastyle]) - AC_DEFINE([QT_QPA_PLATFORM_WINDOWS], [1], [Define this symbol if the qt platform is windows]) - elif test "$TARGET_OS" = "linux"; then - _BITCOIN_QT_CHECK_STATIC_PLUGIN([QXcbIntegrationPlugin], [-lqxcb]) - AC_DEFINE([QT_QPA_PLATFORM_XCB], [1], [Define this symbol if the qt platform is xcb]) - elif test "$TARGET_OS" = "darwin"; then - AX_CHECK_LINK_FLAG([-framework Carbon], [QT_LIBS="$QT_LIBS -framework Carbon"], [AC_MSG_ERROR(could not link against Carbon framework)]) - AX_CHECK_LINK_FLAG([-framework IOSurface], [QT_LIBS="$QT_LIBS -framework IOSurface"], [AC_MSG_ERROR(could not link against IOSurface framework)]) - AX_CHECK_LINK_FLAG([-framework Metal], [QT_LIBS="$QT_LIBS -framework Metal"], [AC_MSG_ERROR(could not link against Metal framework)]) - AX_CHECK_LINK_FLAG([-framework QuartzCore], [QT_LIBS="$QT_LIBS -framework QuartzCore"], [AC_MSG_ERROR(could not link against QuartzCore framework)]) - _BITCOIN_QT_CHECK_STATIC_PLUGIN([QCocoaIntegrationPlugin], [-lqcocoa]) - _BITCOIN_QT_CHECK_STATIC_PLUGIN([QMacStylePlugin], [-lqmacstyle]) - AC_DEFINE([QT_QPA_PLATFORM_COCOA], [1], [Define this symbol if the qt platform is cocoa]) - fi - fi - CPPFLAGS=$TEMP_CPPFLAGS - CXXFLAGS=$TEMP_CXXFLAGS - ]) - - if test "$qt_bin_path" = ""; then - qt_bin_path="`$PKG_CONFIG --variable=host_bins ${qt_lib_prefix}Core 2>/dev/null`" - fi - - if test "$use_hardening" != "no"; then - BITCOIN_QT_CHECK([ - AC_MSG_CHECKING([whether -fPIE can be used with this Qt config]) - TEMP_CPPFLAGS=$CPPFLAGS - TEMP_CXXFLAGS=$CXXFLAGS - CPPFLAGS="$QT_INCLUDES $CORE_CPPFLAGS $CPPFLAGS" - CXXFLAGS="$PIE_FLAGS $CORE_CXXFLAGS $CXXFLAGS" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <QtCore/qconfig.h> - #ifndef QT_VERSION - # include <QtCore/qglobal.h> - #endif - ]], - [[ - #if defined(QT_REDUCE_RELOCATIONS) - choke - #endif - ]])], - [ AC_MSG_RESULT([yes]); QT_PIE_FLAGS=$PIE_FLAGS ], - [ AC_MSG_RESULT([no]); QT_PIE_FLAGS=$PIC_FLAGS] - ) - CPPFLAGS=$TEMP_CPPFLAGS - CXXFLAGS=$TEMP_CXXFLAGS - ]) - else - BITCOIN_QT_CHECK([ - AC_MSG_CHECKING([whether -fPIC is needed with this Qt config]) - TEMP_CPPFLAGS=$CPPFLAGS - CPPFLAGS="$QT_INCLUDES $CORE_CPPFLAGS $CPPFLAGS" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <QtCore/qconfig.h> - #ifndef QT_VERSION - # include <QtCore/qglobal.h> - #endif - ]], - [[ - #if defined(QT_REDUCE_RELOCATIONS) - choke - #endif - ]])], - [ AC_MSG_RESULT([no])], - [ AC_MSG_RESULT([yes]); QT_PIE_FLAGS=$PIC_FLAGS] - ) - CPPFLAGS=$TEMP_CPPFLAGS - ]) - fi - - BITCOIN_QT_PATH_PROGS([MOC], [moc-qt5 moc5 moc], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([UIC], [uic-qt5 uic5 uic], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt5 rcc5 rcc], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt5 lrelease5 lrelease], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt5 lupdate5 lupdate],$qt_bin_path, yes) - BITCOIN_QT_PATH_PROGS([LCONVERT], [lconvert-qt5 lconvert5 lconvert], $qt_bin_path, yes) - - MOC_DEFS='-I$(srcdir)' - case $host in - *darwin*) - BITCOIN_QT_CHECK([ - MOC_DEFS="${MOC_DEFS} -DQ_OS_MAC" - base_frameworks="-framework Foundation -framework AppKit" - AX_CHECK_LINK_FLAG([$base_frameworks], [QT_LIBS="$QT_LIBS $base_frameworks"], [AC_MSG_ERROR(could not find base frameworks)]) - ]) - ;; - *mingw*) - BITCOIN_QT_CHECK([ - AX_CHECK_LINK_FLAG([-mwindows], [QT_LDFLAGS="$QT_LDFLAGS -mwindows"], [AC_MSG_WARN([-mwindows linker support not detected])]) - ]) - esac - - - dnl enable qt support - AC_MSG_CHECKING([whether to build ]AC_PACKAGE_NAME[ GUI]) - BITCOIN_QT_CHECK([ - bitcoin_enable_qt=yes - bitcoin_enable_qt_test=yes - if test "$have_qt_test" = "no"; then - bitcoin_enable_qt_test=no - fi - bitcoin_enable_qt_dbus=no - if test "$use_dbus" != "no" && test "$have_qt_dbus" = "yes"; then - bitcoin_enable_qt_dbus=yes - fi - if test "$use_dbus" = "yes" && test "$have_qt_dbus" = "no"; then - AC_MSG_ERROR([libQtDBus not found. Install libQtDBus or remove --with-qtdbus.]) - fi - if test "$LUPDATE" = ""; then - AC_MSG_WARN([lupdate tool is required to update Qt translations.]) - fi - if test "$LCONVERT" = ""; then - AC_MSG_WARN([lconvert tool is required to update Qt translations.]) - fi - ],[ - bitcoin_enable_qt=no - ]) - if test $bitcoin_enable_qt = "yes"; then - AC_MSG_RESULT([$bitcoin_enable_qt ($qt_lib_prefix)]) - else - AC_MSG_RESULT([$bitcoin_enable_qt]) - fi - - AC_SUBST(QT_PIE_FLAGS) - AC_SUBST(QT_INCLUDES) - AC_SUBST(QT_LIBS) - AC_SUBST(QT_LDFLAGS) - AC_SUBST(QT_DBUS_INCLUDES) - AC_SUBST(QT_TEST_INCLUDES) - AC_SUBST(QT_SELECT, qt5) - AC_SUBST(MOC_DEFS) -]) - -dnl All macros below are internal and should _not_ be used from configure.ac. - -dnl Internal. Check if the linked version of Qt was built statically. -dnl -dnl _BITCOIN_QT_IS_STATIC -dnl --------------------- -dnl -dnl Requires: INCLUDES and LIBS must be populated as necessary. -dnl Output: bitcoin_cv_static_qt=yes|no -AC_DEFUN([_BITCOIN_QT_IS_STATIC],[ - AC_CACHE_CHECK(for static Qt, bitcoin_cv_static_qt,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <QtCore/qconfig.h> - #ifndef QT_VERSION - # include <QtCore/qglobal.h> - #endif - ]], - [[ - #if !defined(QT_STATIC) - choke - #endif - ]])], - [bitcoin_cv_static_qt=yes], - [bitcoin_cv_static_qt=no]) - ]) -]) - -dnl Internal. Check if the link-requirements for a static plugin are met. -dnl -dnl _BITCOIN_QT_CHECK_STATIC_PLUGIN(PLUGIN, LIBRARIES) -dnl -------------------------------------------------- -dnl -dnl Requires: INCLUDES and LIBS must be populated as necessary. -dnl Inputs: $1: A static plugin name. -dnl Inputs: $2: The libraries that resolve $1. -dnl Output: QT_LIBS is prepended or configure exits. -AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_PLUGIN], [ - AC_MSG_CHECKING([for $1 ($2)]) - CHECK_STATIC_PLUGINS_TEMP_LIBS="$LIBS" - LIBS="$2${qt_lib_suffix} $QT_LIBS $LIBS" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - #include <QtPlugin> - Q_IMPORT_PLUGIN($1) - ]])], - [AC_MSG_RESULT([yes]); QT_LIBS="$2${qt_lib_suffix} $QT_LIBS"], - [AC_MSG_RESULT([no]); BITCOIN_QT_FAIL([$1 not found.])]) - LIBS="$CHECK_STATIC_PLUGINS_TEMP_LIBS" -]) - -dnl Internal. Check Qt static libs with PKG_CHECK_MODULES. -dnl -dnl _BITCOIN_QT_CHECK_STATIC_LIBS -dnl ----------------------------- -dnl -dnl Outputs: QT_LIBS is prepended. -AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_LIBS], [ - PKG_CHECK_MODULES([QT_ACCESSIBILITY], [${qt_lib_prefix}AccessibilitySupport${qt_lib_suffix}], [QT_LIBS="$QT_ACCESSIBILITY_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_DEVICEDISCOVERY], [${qt_lib_prefix}DeviceDiscoverySupport${qt_lib_suffix}], [QT_LIBS="$QT_DEVICEDISCOVERY_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_EDID], [${qt_lib_prefix}EdidSupport${qt_lib_suffix}], [QT_LIBS="$QT_EDID_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_EVENTDISPATCHER], [${qt_lib_prefix}EventDispatcherSupport${qt_lib_suffix}], [QT_LIBS="$QT_EVENTDISPATCHER_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_FB], [${qt_lib_prefix}FbSupport${qt_lib_suffix}], [QT_LIBS="$QT_FB_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_FONTDATABASE], [${qt_lib_prefix}FontDatabaseSupport${qt_lib_suffix}], [QT_LIBS="$QT_FONTDATABASE_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_THEME], [${qt_lib_prefix}ThemeSupport${qt_lib_suffix}], [QT_LIBS="$QT_THEME_LIBS $QT_LIBS"]) - if test "$TARGET_OS" = "linux"; then - PKG_CHECK_MODULES([QT_INPUT], [${qt_lib_prefix}InputSupport], [QT_LIBS="$QT_INPUT_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_SERVICE], [${qt_lib_prefix}ServiceSupport], [QT_LIBS="$QT_SERVICE_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_XCBQPA], [${qt_lib_prefix}XcbQpa], [QT_LIBS="$QT_XCBQPA_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_XKBCOMMON], [${qt_lib_prefix}XkbCommonSupport], [QT_LIBS="$QT_XKBCOMMON_LIBS $QT_LIBS"]) - elif test "$TARGET_OS" = "darwin"; then - PKG_CHECK_MODULES([QT_CLIPBOARD], [${qt_lib_prefix}ClipboardSupport${qt_lib_suffix}], [QT_LIBS="$QT_CLIPBOARD_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_GRAPHICS], [${qt_lib_prefix}GraphicsSupport${qt_lib_suffix}], [QT_LIBS="$QT_GRAPHICS_LIBS $QT_LIBS"]) - PKG_CHECK_MODULES([QT_SERVICE], [${qt_lib_prefix}ServiceSupport${qt_lib_suffix}], [QT_LIBS="$QT_SERVICE_LIBS $QT_LIBS"]) - elif test "$TARGET_OS" = "windows"; then - PKG_CHECK_MODULES([QT_WINDOWSUIAUTOMATION], [${qt_lib_prefix}WindowsUIAutomationSupport${qt_lib_suffix}], [QT_LIBS="$QT_WINDOWSUIAUTOMATION_LIBS $QT_LIBS"]) - fi -]) - -dnl Internal. Find Qt libraries using pkg-config. -dnl -dnl _BITCOIN_QT_FIND_LIBS -dnl --------------------- -dnl -dnl Outputs: All necessary QT_* variables are set. -dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. -AC_DEFUN([_BITCOIN_QT_FIND_LIBS],[ - BITCOIN_QT_CHECK([ - PKG_CHECK_MODULES([QT_CORE], [${qt_lib_prefix}Core${qt_lib_suffix} $qt_version], [QT_INCLUDES="$QT_CORE_CFLAGS $QT_INCLUDES" QT_LIBS="$QT_CORE_LIBS $QT_LIBS"], - [BITCOIN_QT_FAIL([${qt_lib_prefix}Core${qt_lib_suffix} $qt_version not found])]) - ]) - BITCOIN_QT_CHECK([ - PKG_CHECK_MODULES([QT_GUI], [${qt_lib_prefix}Gui${qt_lib_suffix} $qt_version], [QT_INCLUDES="$QT_GUI_CFLAGS $QT_INCLUDES" QT_LIBS="$QT_GUI_LIBS $QT_LIBS"], - [BITCOIN_QT_FAIL([${qt_lib_prefix}Gui${qt_lib_suffix} $qt_version not found])]) - ]) - BITCOIN_QT_CHECK([ - PKG_CHECK_MODULES([QT_WIDGETS], [${qt_lib_prefix}Widgets${qt_lib_suffix} $qt_version], [QT_INCLUDES="$QT_WIDGETS_CFLAGS $QT_INCLUDES" QT_LIBS="$QT_WIDGETS_LIBS $QT_LIBS"], - [BITCOIN_QT_FAIL([${qt_lib_prefix}Widgets${qt_lib_suffix} $qt_version not found])]) - ]) - BITCOIN_QT_CHECK([ - PKG_CHECK_MODULES([QT_NETWORK], [${qt_lib_prefix}Network${qt_lib_suffix} $qt_version], [QT_INCLUDES="$QT_NETWORK_CFLAGS $QT_INCLUDES" QT_LIBS="$QT_NETWORK_LIBS $QT_LIBS"], - [BITCOIN_QT_FAIL([${qt_lib_prefix}Network${qt_lib_suffix} $qt_version not found])]) - ]) - - BITCOIN_QT_CHECK([ - PKG_CHECK_MODULES([QT_TEST], [${qt_lib_prefix}Test${qt_lib_suffix} $qt_version], [QT_TEST_INCLUDES="$QT_TEST_CFLAGS"; have_qt_test=yes], [have_qt_test=no]) - if test "$use_dbus" != "no"; then - PKG_CHECK_MODULES([QT_DBUS], [${qt_lib_prefix}DBus $qt_version], [QT_DBUS_INCLUDES="$QT_DBUS_CFLAGS"; have_qt_dbus=yes], [have_qt_dbus=no]) - fi - ]) -]) diff --git a/build-aux/m4/bitcoin_subdir_to_include.m4 b/build-aux/m4/bitcoin_subdir_to_include.m4 deleted file mode 100644 index 736270afea..0000000000 --- a/build-aux/m4/bitcoin_subdir_to_include.m4 +++ /dev/null @@ -1,18 +0,0 @@ -dnl Copyright (c) 2013-2014 The Bitcoin Core developers -dnl Distributed under the MIT software license, see the accompanying -dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. - -dnl BITCOIN_SUBDIR_TO_INCLUDE([CPPFLAGS-VARIABLE-NAME],[SUBDIRECTORY-NAME],[HEADER-FILE]) -dnl SUBDIRECTORY-NAME must end with a path separator -AC_DEFUN([BITCOIN_SUBDIR_TO_INCLUDE],[ - if test "$2" = ""; then - AC_MSG_RESULT([default]) - else - echo "#include <$2$3.h>" >conftest.cpp - newinclpath=`${CXXCPP} ${CPPFLAGS} -M conftest.cpp 2>/dev/null | [ tr -d '\\n\\r\\\\' | sed -e 's/^.*[[:space:]:]\(\/[^[:space:]]*\)]$3[\.h[[:space:]].*$/\1/' -e t -e d`] - AC_MSG_RESULT([${newinclpath}]) - if test "${newinclpath}" != ""; then - eval "$1=\"\$$1\"' -I${newinclpath}'" - fi - fi -]) diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4 deleted file mode 100644 index 859ddaabbb..0000000000 --- a/build-aux/m4/l_atomic.m4 +++ /dev/null @@ -1,65 +0,0 @@ -dnl Copyright (c) 2015 Tim Kosse <tim.kosse@filezilla-project.org> -dnl Copying and distribution of this file, with or without modification, are -dnl permitted in any medium without royalty provided the copyright notice -dnl and this notice are preserved. This file is offered as-is, without any -dnl warranty. - -# Clang, when building for 32-bit, -# and linking against libstdc++, requires linking with -# -latomic if using the C++ atomic library. -# Can be tested with: clang++ -std=c++20 test.cpp -m32 -# -# Sourced from http://bugs.debian.org/797228 - -m4_define([_CHECK_ATOMIC_testbody], [[ - #include <atomic> - #include <cstdint> - #include <chrono> - - using namespace std::chrono_literals; - - int main() { - std::atomic<bool> lock{true}; - lock.exchange(false); - - std::atomic<std::chrono::seconds> t{0s}; - t.store(2s); - auto t1 = t.load(); - t.compare_exchange_strong(t1, 3s); - - std::atomic<double> d{}; - d.store(3.14); - auto d1 = d.load(); - - std::atomic<int64_t> a{}; - int64_t v = 5; - int64_t r = a.fetch_add(v); - return static_cast<int>(r); - } -]]) - -AC_DEFUN([CHECK_ATOMIC], [ - - AC_LANG_PUSH(C++) - TEMP_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" - - AC_MSG_CHECKING([whether std::atomic can be used without link library]) - - AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ - AC_MSG_RESULT([yes]) - ],[ - AC_MSG_RESULT([no]) - LIBS="$LIBS -latomic" - AC_MSG_CHECKING([whether std::atomic needs -latomic]) - AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ - AC_MSG_RESULT([yes]) - ],[ - AC_MSG_RESULT([no]) - AC_MSG_FAILURE([cannot figure out how to use std::atomic]) - ]) - ]) - - CXXFLAGS="$TEMP_CXXFLAGS" - AC_LANG_POP -]) diff --git a/build-aux/m4/l_socket.m4 b/build-aux/m4/l_socket.m4 deleted file mode 100644 index 38923a98fc..0000000000 --- a/build-aux/m4/l_socket.m4 +++ /dev/null @@ -1,36 +0,0 @@ -# Illumos/SmartOS requires linking with -lsocket if -# using getifaddrs & freeifaddrs - -m4_define([_CHECK_SOCKET_testbody], [[ - #include <sys/types.h> - #include <ifaddrs.h> - - int main() { - struct ifaddrs *ifaddr; - getifaddrs(&ifaddr); - freeifaddrs(ifaddr); - } -]]) - -AC_DEFUN([CHECK_SOCKET], [ - - AC_LANG_PUSH(C++) - - AC_MSG_CHECKING([whether ifaddrs funcs can be used without link library]) - - AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_SOCKET_testbody])],[ - AC_MSG_RESULT([yes]) - ],[ - AC_MSG_RESULT([no]) - LIBS="$LIBS -lsocket" - AC_MSG_CHECKING([whether getifaddrs needs -lsocket]) - AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_SOCKET_testbody])],[ - AC_MSG_RESULT([yes]) - ],[ - AC_MSG_RESULT([no]) - AC_MSG_FAILURE([cannot figure out how to use getifaddrs]) - ]) - ]) - - AC_LANG_POP -]) diff --git a/build_msvc/.gitignore b/build_msvc/.gitignore deleted file mode 100644 index b2eb9313a0..0000000000 --- a/build_msvc/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Build directories -Debug/* -Release/* -.vs -packages/* -*/Obj -*/Debug -*/Release -*/x64 -*.vcxproj.user - -# .vcxproj files that are auto-generated by the msvc-autogen.py script. -libbitcoin_cli/libbitcoin_cli.vcxproj -libbitcoin_common/libbitcoin_common.vcxproj -libbitcoin_crypto/libbitcoin_crypto.vcxproj -libbitcoin_node/libbitcoin_node.vcxproj -libbitcoin_util/libbitcoin_util.vcxproj -libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj -libbitcoin_wallet/libbitcoin_wallet.vcxproj -libbitcoin_zmq/libbitcoin_zmq.vcxproj -bench_bitcoin/bench_bitcoin.vcxproj -libtest_util/libtest_util.vcxproj - -/bitcoin_config.h -/common.init.vcxproj - -*/Win32 -libbitcoin_qt/QtGeneratedFiles/* -test_bitcoin-qt/QtGeneratedFiles/* -vcpkg_installed
\ No newline at end of file diff --git a/build_msvc/README.md b/build_msvc/README.md deleted file mode 100644 index f97c7ca59c..0000000000 --- a/build_msvc/README.md +++ /dev/null @@ -1,92 +0,0 @@ -Building Bitcoin Core with Visual Studio -======================================== - -Introduction ---------------------- -Visual Studio 2022 is minimum required to build Bitcoin Core. - -Solution and project files to build with `msbuild` or Visual Studio can be found in the `build_msvc` directory. - -To build Bitcoin Core from the command-line, it is sufficient to only install the [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/) component. - -The "Desktop development with C++" workload must be installed as well. - -Building with Visual Studio is an alternative to the Linux based [cross-compiler build](../doc/build-windows.md). - - -Prerequisites ---------------------- -To build [dependencies](../doc/dependencies.md) (except for [Qt](#qt)), -the default approach is to use the [vcpkg](https://vcpkg.io) package manager from Microsoft: - -1. [Install](https://vcpkg.io/en/getting-started.html) vcpkg. - -2. By default, vcpkg makes both `release` and `debug` builds for each package. -To save build time and disk space, one could skip `debug` builds (example uses PowerShell): -```powershell - -Add-Content -Path "vcpkg\triplets\x64-windows-static.cmake" -Value "set(VCPKG_BUILD_TYPE release)" -``` - -Qt ---------------------- -To build Bitcoin Core with the GUI, a static build of Qt is required. - -1. Download a single ZIP archive of Qt source code from https://download.qt.io/official_releases/qt/ (e.g., [`qt-everywhere-opensource-src-5.15.11.zip`](https://download.qt.io/official_releases/qt/5.15/5.15.11/single/qt-everywhere-opensource-src-5.15.11.zip)), and expand it into a dedicated folder. The following instructions assume that this folder is `C:\dev\qt-source`. - -> 💡 **Tip:** If you use the default path with "Extract All" for the Qt source code zip file, and end up with something like `C:\dev\qt-everywhere-opensource-src-5.15.11\qt-everywhere-src-5.15.11`, you are likely to encounter a "path too long" error when building. To fix the problem move the source files to a shorter path such as the recommended `C:\dev\qt-source`. - -2. Open "x64 Native Tools Command Prompt for VS 2022", and input the following commands: -```cmd -cd C:\dev\qt-source -mkdir build -cd build -..\configure -release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml -prefix C:\Qt_static -nmake -nmake install -``` - -One could speed up building with [`jom`](https://wiki.qt.io/Jom), a replacement for `nmake` which makes use of all CPU cores. - -To build Bitcoin Core without Qt, unload or disable the `bitcoin-qt`, `libbitcoin_qt` and `test_bitcoin-qt` projects. - - -Building ---------------------- -1. Use Python to generate `*.vcxproj` for the Visual Studio 2022 toolchain from Makefile: - -```cmd -python build_msvc\msvc-autogen.py -``` - -2. An optional step is to adjust the settings in the `build_msvc` directory and the `common.init.vcxproj` file. This project file contains settings that are common to all projects such as the runtime library version and target Windows SDK version. The Qt directories can also be set. To specify a non-default path to a static Qt package directory, use the `QTBASEDIR` environment variable. - -3. To build from the command-line with the Visual Studio toolchain use: - -```cmd -msbuild build_msvc\bitcoin.sln -property:Configuration=Release -maxCpuCount -verbosity:minimal -``` - -Alternatively, open the `build_msvc/bitcoin.sln` file in Visual Studio. - -Security ---------------------- -[Base address randomization](https://learn.microsoft.com/en-us/cpp/build/reference/dynamicbase-use-address-space-layout-randomization) is used to make Bitcoin Core more secure. When building Bitcoin using the `build_msvc` process base address randomization can be disabled by editing `common.init.vcproj` to change `RandomizedBaseAddress` from `true` to `false` and then rebuilding the project. - -To check if `bitcoind` has `RandomizedBaseAddress` enabled or disabled run - -``` -.\dumpbin.exe /headers src/bitcoind.exe -``` - -If is it enabled then in the output `Dynamic base` will be listed in the `DLL characteristics` under `OPTIONAL HEADER VALUES` as shown below - -``` - 8160 DLL characteristics - High Entropy Virtual Addresses - Dynamic base - NX compatible - Terminal Server Aware -``` - -This may not disable all stack randomization as versions of windows employ additional stack randomization protections. These protections must be turned off in the OS configuration. diff --git a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in deleted file mode 100644 index 972d6d05d7..0000000000 --- a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{1125654E-E1B2-4431-8B5C-62EA9A2FEECB}</ProjectGuid> - </PropertyGroup> - <PropertyGroup> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - <ClCompile Include="..\..\src\bench\coin_selection.cpp" /> - <ClCompile Include="..\..\src\bench\wallet_balance.cpp" /> - <ClCompile Include="..\..\src\bench\wallet_create.cpp" /> - <ClCompile Include="..\..\src\bench\wallet_create_tx.cpp" /> - <ClCompile Include="..\..\src\bench\wallet_ismine.cpp" /> - <ClCompile Include="..\..\src\bench\wallet_loading.cpp" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_node\libbitcoin_node.vcxproj"> - <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> - <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj"> - <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> - <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> - </ProjectReference> - <ProjectReference Include="..\libtest_util\libtest_util.vcxproj"> - <Project>{1e065f03-3566-47d0-8fa9-daa72b084e7d}</Project> - </ProjectReference> - </ItemGroup> - <Target Name="RawBenchHeaderGen" BeforeTargets="PrepareForBuild"> - <PropertyGroup> - <ErrorText>There was an error executing the raw bench header generation task.</ErrorText> - </PropertyGroup> - <ItemGroup> - <RawBenchFile Include="..\..\src\bench\data\*.raw" /> - </ItemGroup> - <HeaderFromHexdump RawFilePath="%(RawBenchFile.FullPath)" HeaderFilePath="%(RawBenchFile.FullPath).h" SourceHeader="static unsigned const char %(RawBenchFile.Filename)_raw[] = {" SourceFooter="};" /> - </Target> - <Import Label="hexdumpTarget" Project="..\msbuild\tasks\hexdump.targets" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project>
\ No newline at end of file diff --git a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj b/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj deleted file mode 100644 index 738884fb41..0000000000 --- a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{0B2D7431-F876-4A58-87BF-F748338CD3BF}</ProjectGuid> - </PropertyGroup> - <PropertyGroup> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\bitcoin-cli.cpp" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj"> - <Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/bitcoin-qt/bitcoin-qt.vcxproj b/build_msvc/bitcoin-qt/bitcoin-qt.vcxproj deleted file mode 100644 index ff98d37cf8..0000000000 --- a/build_msvc/bitcoin-qt/bitcoin-qt.vcxproj +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <Import Project="..\common.qt.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{7E99172D-7FF2-4CB6-B736-AC9B76ED412A}</ProjectGuid> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\qt\main.cpp" /> - <ClCompile Include="..\..\src\init\bitcoin-qt.cpp" /> - <ResourceCompile Include="..\..\src\qt\res\bitcoin-qt-res.rc" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj"> - <Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_qt\libbitcoin_qt.vcxproj"> - <Project>{2b4abff8-d1fd-4845-88c9-1f3c0a6512bf}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_node\libbitcoin_node.vcxproj"> - <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> - <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj"> - <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project> - </ProjectReference> - <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> - <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - </ItemGroup> - - <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> - <ClCompile> - <AdditionalIncludeDirectories>$(QtIncludes);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - <Link> - <SubSystem>Windows</SubSystem> - <AdditionalDependencies>$(QtReleaseLibraries);%(AdditionalDependencies)</AdditionalDependencies> - <AdditionalOptions>/LTCG:OFF</AdditionalOptions> - </Link> - <ResourceCompile> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ResourceCompile> - </ItemDefinitionGroup> - - <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> - <ClCompile> - <AdditionalIncludeDirectories>$(QtIncludes);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - <Link> - <AdditionalDependencies>$(QtDebugLibraries);%(AdditionalDependencies)</AdditionalDependencies> - </Link> - <ResourceCompile> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ResourceCompile> - </ItemDefinitionGroup> - - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> -</Project> diff --git a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj deleted file mode 100644 index 52585b98f9..0000000000 --- a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\bitcoin-tx.cpp" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/bitcoin-util/bitcoin-util.vcxproj b/build_msvc/bitcoin-util/bitcoin-util.vcxproj deleted file mode 100644 index 4ea27fe439..0000000000 --- a/build_msvc/bitcoin-util/bitcoin-util.vcxproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{57A04EC9-542A-4E40-83D0-AC3BE1F36805}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\bitcoin-util.cpp" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj deleted file mode 100644 index 56d88d6a44..0000000000 --- a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{84DE8790-EDE3-4483-81AC-C32F15E861F4}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\bitcoin-wallet.cpp" /> - <ClCompile Include="..\..\src\init\bitcoin-wallet.cpp"> - <ObjectFileName>$(IntDir)init_bitcoin-wallet.obj</ObjectFileName> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> - <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj"> - <Project>{f91ac55e-6f5e-4c58-9ac5-b40db7deef93}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/bitcoin.sln b/build_msvc/bitcoin.sln deleted file mode 100644 index 9fd6395f59..0000000000 --- a/build_msvc/bitcoin.sln +++ /dev/null @@ -1,168 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.452 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_consensus", "libbitcoin_consensus\libbitcoin_consensus.vcxproj", "{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoind", "bitcoind\bitcoind.vcxproj", "{D4513DDF-6013-44DC-ADCC-12EAF6D1F038}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_util", "libbitcoin_util\libbitcoin_util.vcxproj", "{B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_common", "libbitcoin_common\libbitcoin_common.vcxproj", "{7C87E378-DF58-482E-AA2F-1BC129BC19CE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_crypto", "libbitcoin_crypto\libbitcoin_crypto.vcxproj", "{6190199C-6CF4-4DAD-BFBD-93FA72A760C1}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_node", "libbitcoin_node\libbitcoin_node.vcxproj", "{460FEE33-1FE1-483F-B3BF-931FF8E969A5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libunivalue", "libunivalue\libunivalue.vcxproj", "{5724BA7D-A09A-4BA8-800B-C4C1561B3D69}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_wallet", "libbitcoin_wallet\libbitcoin_wallet.vcxproj", "{93B86837-B543-48A5-A89B-7C87ABB77DF2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_zmq", "libbitcoin_zmq\libbitcoin_zmq.vcxproj", "{792D487F-F14C-49FC-A9DE-3FC150F31C3F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_bitcoin", "test_bitcoin\test_bitcoin.vcxproj", "{A56B73DB-D46D-4882-8374-1FE3FFA08F07}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_cli", "libbitcoin_cli\libbitcoin_cli.vcxproj", "{0667528C-D734-4009-ADF9-C0D6C4A5A5A6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-cli", "bitcoin-cli\bitcoin-cli.vcxproj", "{0B2D7431-F876-4A58-87BF-F748338CD3BF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_bitcoin", "bench_bitcoin\bench_bitcoin.vcxproj", "{1125654E-E1B2-4431-8B5C-62EA9A2FEECB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-tx", "bitcoin-tx\bitcoin-tx.vcxproj", "{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-util", "bitcoin-util\bitcoin-util.vcxproj", "{57A04EC9-542A-4E40-83D0-AC3BE1F36805}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-wallet", "bitcoin-wallet\bitcoin-wallet.vcxproj", "{84DE8790-EDE3-4483-81AC-C32F15E861F4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_wallet_tool", "libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj", "{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsecp256k1", "libsecp256k1\libsecp256k1.vcxproj", "{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libleveldb", "libleveldb\libleveldb.vcxproj", "{18430FEF-6B61-4C53-B396-718E02850F1B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_qt", "libbitcoin_qt\libbitcoin_qt.vcxproj", "{2B4ABFF8-D1FD-4845-88C9-1F3C0A6512BF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-qt", "bitcoin-qt\bitcoin-qt.vcxproj", "{7E99172D-7FF2-4CB6-B736-AC9B76ED412A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtest_util", "libtest_util\libtest_util.vcxproj", "{868474FD-35F6-4400-8EED-30A33E7521D4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_bitcoin-qt", "test_bitcoin-qt\test_bitcoin-qt.vcxproj", "{51201D5E-D939-4854-AE9D-008F03FF518E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libminisketch", "libminisketch\libminisketch.vcxproj", "{542007E3-BE0D-4B0D-A6B0-AA8813E2558D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fuzz", "fuzz\fuzz.vcxproj", "{AFCEE6C1-89FB-49AB-A694-BA580A59E2D8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2B384FA8-9EE1-4544-93CB-0D733C25E8CE}.Debug|x64.ActiveCfg = Debug|x64 - {2B384FA8-9EE1-4544-93CB-0D733C25E8CE}.Debug|x64.Build.0 = Debug|x64 - {2B384FA8-9EE1-4544-93CB-0D733C25E8CE}.Release|x64.ActiveCfg = Release|x64 - {2B384FA8-9EE1-4544-93CB-0D733C25E8CE}.Release|x64.Build.0 = Release|x64 - {D4513DDF-6013-44DC-ADCC-12EAF6D1F038}.Debug|x64.ActiveCfg = Debug|x64 - {D4513DDF-6013-44DC-ADCC-12EAF6D1F038}.Debug|x64.Build.0 = Debug|x64 - {D4513DDF-6013-44DC-ADCC-12EAF6D1F038}.Release|x64.ActiveCfg = Release|x64 - {D4513DDF-6013-44DC-ADCC-12EAF6D1F038}.Release|x64.Build.0 = Release|x64 - {B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}.Debug|x64.ActiveCfg = Debug|x64 - {B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}.Debug|x64.Build.0 = Debug|x64 - {B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}.Release|x64.ActiveCfg = Release|x64 - {B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}.Release|x64.Build.0 = Release|x64 - {7C87E378-DF58-482E-AA2F-1BC129BC19CE}.Debug|x64.ActiveCfg = Debug|x64 - {7C87E378-DF58-482E-AA2F-1BC129BC19CE}.Debug|x64.Build.0 = Debug|x64 - {7C87E378-DF58-482E-AA2F-1BC129BC19CE}.Release|x64.ActiveCfg = Release|x64 - {7C87E378-DF58-482E-AA2F-1BC129BC19CE}.Release|x64.Build.0 = Release|x64 - {6190199C-6CF4-4DAD-BFBD-93FA72A760C1}.Debug|x64.ActiveCfg = Debug|x64 - {6190199C-6CF4-4DAD-BFBD-93FA72A760C1}.Debug|x64.Build.0 = Debug|x64 - {6190199C-6CF4-4DAD-BFBD-93FA72A760C1}.Release|x64.ActiveCfg = Release|x64 - {6190199C-6CF4-4DAD-BFBD-93FA72A760C1}.Release|x64.Build.0 = Release|x64 - {460FEE33-1FE1-483F-B3BF-931FF8E969A5}.Debug|x64.ActiveCfg = Debug|x64 - {460FEE33-1FE1-483F-B3BF-931FF8E969A5}.Debug|x64.Build.0 = Debug|x64 - {460FEE33-1FE1-483F-B3BF-931FF8E969A5}.Release|x64.ActiveCfg = Release|x64 - {460FEE33-1FE1-483F-B3BF-931FF8E969A5}.Release|x64.Build.0 = Release|x64 - {5724BA7D-A09A-4BA8-800B-C4C1561B3D69}.Debug|x64.ActiveCfg = Debug|x64 - {5724BA7D-A09A-4BA8-800B-C4C1561B3D69}.Debug|x64.Build.0 = Debug|x64 - {5724BA7D-A09A-4BA8-800B-C4C1561B3D69}.Release|x64.ActiveCfg = Release|x64 - {5724BA7D-A09A-4BA8-800B-C4C1561B3D69}.Release|x64.Build.0 = Release|x64 - {93B86837-B543-48A5-A89B-7C87ABB77DF2}.Debug|x64.ActiveCfg = Debug|x64 - {93B86837-B543-48A5-A89B-7C87ABB77DF2}.Debug|x64.Build.0 = Debug|x64 - {93B86837-B543-48A5-A89B-7C87ABB77DF2}.Release|x64.ActiveCfg = Release|x64 - {93B86837-B543-48A5-A89B-7C87ABB77DF2}.Release|x64.Build.0 = Release|x64 - {792D487F-F14C-49FC-A9DE-3FC150F31C3F}.Debug|x64.ActiveCfg = Debug|x64 - {792D487F-F14C-49FC-A9DE-3FC150F31C3F}.Debug|x64.Build.0 = Debug|x64 - {792D487F-F14C-49FC-A9DE-3FC150F31C3F}.Release|x64.ActiveCfg = Release|x64 - {792D487F-F14C-49FC-A9DE-3FC150F31C3F}.Release|x64.Build.0 = Release|x64 - {A56B73DB-D46D-4882-8374-1FE3FFA08F07}.Debug|x64.ActiveCfg = Debug|x64 - {A56B73DB-D46D-4882-8374-1FE3FFA08F07}.Debug|x64.Build.0 = Debug|x64 - {A56B73DB-D46D-4882-8374-1FE3FFA08F07}.Release|x64.ActiveCfg = Release|x64 - {A56B73DB-D46D-4882-8374-1FE3FFA08F07}.Release|x64.Build.0 = Release|x64 - {0667528C-D734-4009-ADF9-C0D6C4A5A5A6}.Debug|x64.ActiveCfg = Debug|x64 - {0667528C-D734-4009-ADF9-C0D6C4A5A5A6}.Debug|x64.Build.0 = Debug|x64 - {0667528C-D734-4009-ADF9-C0D6C4A5A5A6}.Release|x64.ActiveCfg = Release|x64 - {0667528C-D734-4009-ADF9-C0D6C4A5A5A6}.Release|x64.Build.0 = Release|x64 - {0B2D7431-F876-4A58-87BF-F748338CD3BF}.Debug|x64.ActiveCfg = Debug|x64 - {0B2D7431-F876-4A58-87BF-F748338CD3BF}.Debug|x64.Build.0 = Debug|x64 - {0B2D7431-F876-4A58-87BF-F748338CD3BF}.Release|x64.ActiveCfg = Release|x64 - {0B2D7431-F876-4A58-87BF-F748338CD3BF}.Release|x64.Build.0 = Release|x64 - {1125654E-E1B2-4431-8B5C-62EA9A2FEECB}.Debug|x64.ActiveCfg = Debug|x64 - {1125654E-E1B2-4431-8B5C-62EA9A2FEECB}.Debug|x64.Build.0 = Debug|x64 - {1125654E-E1B2-4431-8B5C-62EA9A2FEECB}.Release|x64.ActiveCfg = Release|x64 - {1125654E-E1B2-4431-8B5C-62EA9A2FEECB}.Release|x64.Build.0 = Release|x64 - {D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Debug|x64.ActiveCfg = Debug|x64 - {D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Debug|x64.Build.0 = Debug|x64 - {D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x64.ActiveCfg = Release|x64 - {D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x64.Build.0 = Release|x64 - {57A04EC9-542A-4E40-83D0-AC3BE1F36805}.Debug|x64.ActiveCfg = Debug|x64 - {57A04EC9-542A-4E40-83D0-AC3BE1F36805}.Debug|x64.Build.0 = Debug|x64 - {57A04EC9-542A-4E40-83D0-AC3BE1F36805}.Release|x64.ActiveCfg = Release|x64 - {57A04EC9-542A-4E40-83D0-AC3BE1F36805}.Release|x64.Build.0 = Release|x64 - {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x64.ActiveCfg = Debug|x64 - {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x64.Build.0 = Debug|x64 - {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x64.ActiveCfg = Release|x64 - {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x64.Build.0 = Release|x64 - {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x64.ActiveCfg = Debug|x64 - {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x64.Build.0 = Debug|x64 - {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x64.ActiveCfg = Release|x64 - {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x64.Build.0 = Release|x64 - {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x64.ActiveCfg = Debug|x64 - {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x64.Build.0 = Debug|x64 - {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x64.ActiveCfg = Release|x64 - {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x64.Build.0 = Release|x64 - {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x64.ActiveCfg = Debug|x64 - {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x64.Build.0 = Debug|x64 - {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x64.ActiveCfg = Release|x64 - {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x64.Build.0 = Release|x64 - {2B4ABFF8-D1FD-4845-88C9-1F3C0A6512BF}.Debug|x64.ActiveCfg = Debug|x64 - {2B4ABFF8-D1FD-4845-88C9-1F3C0A6512BF}.Debug|x64.Build.0 = Debug|x64 - {2B4ABFF8-D1FD-4845-88C9-1F3C0A6512BF}.Release|x64.ActiveCfg = Release|x64 - {2B4ABFF8-D1FD-4845-88C9-1F3C0A6512BF}.Release|x64.Build.0 = Release|x64 - {7E99172D-7FF2-4CB6-B736-AC9B76ED412A}.Debug|x64.ActiveCfg = Debug|x64 - {7E99172D-7FF2-4CB6-B736-AC9B76ED412A}.Debug|x64.Build.0 = Debug|x64 - {7E99172D-7FF2-4CB6-B736-AC9B76ED412A}.Release|x64.ActiveCfg = Release|x64 - {7E99172D-7FF2-4CB6-B736-AC9B76ED412A}.Release|x64.Build.0 = Release|x64 - {868474FD-35F6-4400-8EED-30A33E7521D4}.Debug|x64.ActiveCfg = Debug|x64 - {868474FD-35F6-4400-8EED-30A33E7521D4}.Debug|x64.Build.0 = Debug|x64 - {868474FD-35F6-4400-8EED-30A33E7521D4}.Release|x64.ActiveCfg = Release|x64 - {868474FD-35F6-4400-8EED-30A33E7521D4}.Release|x64.Build.0 = Release|x64 - {51201D5E-D939-4854-AE9D-008F03FF518E}.Debug|x64.ActiveCfg = Debug|x64 - {51201D5E-D939-4854-AE9D-008F03FF518E}.Debug|x64.Build.0 = Debug|x64 - {51201D5E-D939-4854-AE9D-008F03FF518E}.Release|x64.ActiveCfg = Release|x64 - {51201D5E-D939-4854-AE9D-008F03FF518E}.Release|x64.Build.0 = Release|x64 - {542007E3-BE0D-4B0D-A6B0-AA8813E2558D}.Debug|x64.ActiveCfg = Debug|x64 - {542007E3-BE0D-4B0D-A6B0-AA8813E2558D}.Debug|x64.Build.0 = Debug|x64 - {542007E3-BE0D-4B0D-A6B0-AA8813E2558D}.Release|x64.ActiveCfg = Release|x64 - {542007E3-BE0D-4B0D-A6B0-AA8813E2558D}.Release|x64.Build.0 = Release|x64 - {AFCEE6C1-89FB-49AB-A694-BA580A59E2D8}.Debug|x64.ActiveCfg = Debug|x64 - {AFCEE6C1-89FB-49AB-A694-BA580A59E2D8}.Debug|x64.Build.0 = Debug|x64 - {AFCEE6C1-89FB-49AB-A694-BA580A59E2D8}.Release|x64.ActiveCfg = Release|x64 - {AFCEE6C1-89FB-49AB-A694-BA580A59E2D8}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {58AAB032-7274-49BD-845E-5EF4DBB69B70} - EndGlobalSection -EndGlobal diff --git a/build_msvc/bitcoin_config.h.in b/build_msvc/bitcoin_config.h.in deleted file mode 100644 index 2d6df92286..0000000000 --- a/build_msvc/bitcoin_config.h.in +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_BITCOIN_CONFIG_H -#define BITCOIN_BITCOIN_CONFIG_H - -/* Version Build */ -#define CLIENT_VERSION_BUILD $ - -/* Version is release */ -#define CLIENT_VERSION_IS_RELEASE $ - -/* Major version */ -#define CLIENT_VERSION_MAJOR $ - -/* Minor version */ -#define CLIENT_VERSION_MINOR $ - -/* Copyright holder(s) before %s replacement */ -#define COPYRIGHT_HOLDERS "The %s developers" - -/* Copyright holder(s) */ -#define COPYRIGHT_HOLDERS_FINAL "The Bitcoin Core developers" - -/* Replacement for %s in copyright holders string */ -#define COPYRIGHT_HOLDERS_SUBSTITUTION "Bitcoin Core" - -/* Copyright year */ -#define COPYRIGHT_YEAR $ - -/* Define to 1 to enable wallet functions */ -#define ENABLE_WALLET 1 - -/* Define to 1 to enable BDB wallet */ -#define USE_BDB 1 - -/* Define to 1 to enable SQLite wallet */ -#define USE_SQLITE 1 - -/* Define this symbol to enable ZMQ functions */ -#define ENABLE_ZMQ 1 - -/* Define to 1 if you have the declaration of `fork', and to 0 if you don't. - */ -#define HAVE_DECL_FORK 0 - -/* Define to 1 if you have the declaration of `setsid', and to 0 if you don't. - */ -#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" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "Bitcoin Core" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING $ - -/* Define to the home page for this package. */ -#define PACKAGE_URL "https://bitcoincore.org/" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION $ - -/* Define this symbol if the minimal qt platform exists */ -#define QT_QPA_PLATFORM_MINIMAL 1 - -/* 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 - before these macros were defined. */ - -/* ::wsystem is available */ -#define HAVE_SYSTEM 1 - -#endif // !WINAPI_FAMILY || WINAPI_FAMILY_DESKTOP_APP - -#endif //BITCOIN_BITCOIN_CONFIG_H diff --git a/build_msvc/bitcoind/bitcoind.vcxproj b/build_msvc/bitcoind/bitcoind.vcxproj deleted file mode 100644 index 63337ca6a7..0000000000 --- a/build_msvc/bitcoind/bitcoind.vcxproj +++ /dev/null @@ -1,92 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{D4513DDF-6013-44DC-ADCC-12EAF6D1F038}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\bitcoind.cpp" /> - <ClCompile Include="..\..\src\init\bitcoind.cpp"> - <ObjectFileName>$(IntDir)init_bitcoind.obj</ObjectFileName> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_node\libbitcoin_node.vcxproj"> - <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> - <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj"> - <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> - <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> - </ProjectReference> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Label="ReplaceInFile" Project="..\msbuild\tasks\replaceinfile.targets" /> - <PropertyGroup> - <ConfigIniIn>..\..\test\config.ini.in</ConfigIniIn> - <ConfigIniOut>..\..\test\config.ini</ConfigIniOut> - </PropertyGroup> - <Target Name="AfterBuild"> - <Copy SourceFiles="$(ConfigIniIn)" DestinationFiles="$(ConfigIniOut)" ></Copy> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@PACKAGE_NAME@" By="Bitcoin Core"></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@PACKAGE_BUGREPORT@" By="https://github.com/bitcoin/bitcoin/issues"></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@abs_top_srcdir@" By="..\.." ToFullPath="true"></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@abs_top_builddir@" By="..\.." ToFullPath="true"></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@EXEEXT@" By=".exe"></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@ENABLE_WALLET_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@USE_BDB_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@USE_SQLITE_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@BUILD_BITCOIN_CLI_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@BUILD_BITCOIN_UTIL_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@BUILD_BITCOIN_WALLET_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@BUILD_BITCOIND_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@ENABLE_FUZZ_BINARY_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@ENABLE_ZMQ_TRUE@" By=""></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@ENABLE_EXTERNAL_SIGNER_TRUE@" By="#"></ReplaceInFile> - <ReplaceInFile FilePath="$(ConfigIniOut)" - Replace="@ENABLE_USDT_TRACEPOINTS_TRUE@" By="#"></ReplaceInFile> - </Target> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/common.init.vcxproj.in b/build_msvc/common.init.vcxproj.in deleted file mode 100644 index 6468abcd06..0000000000 --- a/build_msvc/common.init.vcxproj.in +++ /dev/null @@ -1,103 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> -<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - - <PropertyGroup Label="Globals"> - <VCProjectVersion>16.0</VCProjectVersion> - <UseNativeEnvironment>true</UseNativeEnvironment> - </PropertyGroup> - - <PropertyGroup Label="Vcpkg"> - <VcpkgEnabled>true</VcpkgEnabled> - <VcpkgEnableManifest>true</VcpkgEnableManifest> - <VcpkgManifestInstall>true</VcpkgManifestInstall> - <VcpkgUseStatic>true</VcpkgUseStatic> - <VcpkgAutoLink>true</VcpkgAutoLink> - <VcpkgConfiguration>$(Configuration)</VcpkgConfiguration> - <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet> - </PropertyGroup> - - <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' and !Exists('$(WindowsSdkDir)\DesignTime\CommonConfiguration\Neutral\Windows.props')"> - <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</WindowsTargetPlatformVersion_10> - <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</WindowsTargetPlatformVersion_10> - <!-- Sometimes the version in the registry has to .0 suffix, and sometimes it doesn't. Check and add it --> - <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' != '' and !$(WindowsTargetPlatformVersion_10.EndsWith('.0'))">$(WindowsTargetPlatformVersion_10).0</WindowsTargetPlatformVersion_10> - <WindowsTargetPlatformVersion>$(WindowsTargetPlatformVersion_10)</WindowsTargetPlatformVersion> - </PropertyGroup> - - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Release|x64"> - <Configuration>Release</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Debug|x64"> - <Configuration>Debug</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - </ItemGroup> - - <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> - <LinkIncremental>false</LinkIncremental> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>@TOOLSET@</PlatformToolset> - <CharacterSet>Unicode</CharacterSet> - <GenerateManifest>No</GenerateManifest> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> - <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - - <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> - <LinkIncremental>true</LinkIncremental> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>@TOOLSET@</PlatformToolset> - <CharacterSet>Unicode</CharacterSet> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> - <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - -<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> - <ClCompile> - <Optimization>MaxSpeed</Optimization> - <WholeProgramOptimization>false</WholeProgramOptimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - <DebugInformationFormat>None</DebugInformationFormat> - </ClCompile> - <Link> - <EnableCOMDATFolding>false</EnableCOMDATFolding> - <OptimizeReferences>false</OptimizeReferences> - <AdditionalOptions>/LTCG:OFF</AdditionalOptions> - </Link> - </ItemDefinitionGroup> - - <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> - <ClCompile> - <Optimization>Disabled</Optimization> - <WholeProgramOptimization>false</WholeProgramOptimization> - <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <SDLCheck>true</SDLCheck> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - </ItemDefinitionGroup> - - <ItemDefinitionGroup> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - <AdditionalOptions>/utf-8 /Zc:preprocessor /Zc:__cplusplus /std:c++20 %(AdditionalOptions)</AdditionalOptions> - <DisableSpecificWarnings>4018;4244;4267;4715;4805</DisableSpecificWarnings> - <TreatWarningAsError>true</TreatWarningAsError> - <PreprocessorDefinitions>_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;SECP256K1_STATIC;ZMQ_STATIC;NOMINMAX;WIN32;_CRT_SECURE_NO_WARNINGS;_CONSOLE;_WIN32_WINNT=0x0601;_WIN32_IE=0x0501;WIN32_LEAN_AND_MEAN;PROVIDE_FUZZ_MAIN_FUNCTION;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..\..\src;..\..\src\minisketch\include;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <AdditionalDependencies>Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> - <RandomizedBaseAddress>true</RandomizedBaseAddress> - </Link> - </ItemDefinitionGroup> - <Import Project="common.init.vcxproj.user" Condition="Exists('common.init.vcxproj.user')" /> -</Project> diff --git a/build_msvc/common.qt.init.vcxproj b/build_msvc/common.qt.init.vcxproj deleted file mode 100644 index dabbec707f..0000000000 --- a/build_msvc/common.qt.init.vcxproj +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - - <PropertyGroup Label="QtGlobals"> - <QtBaseDir Condition="'$(QTBASEDIR)' == ''">C:\Qt_static</QtBaseDir> - <QtPluginsLibraryDir>$(QtBaseDir)\plugins</QtPluginsLibraryDir> - <QtLibraryDir>$(QtBaseDir)\lib</QtLibraryDir> - <QtIncludeDir>$(QtBaseDir)\include</QtIncludeDir> - <QtIncludes>$(QtIncludeDir);$(QtIncludeDir)\QtNetwork;$(QtIncludeDir)\QtCore;$(QtIncludeDir)\QtWidgets;$(QtIncludeDir)\QtGui;</QtIncludes> - <GeneratedFilesOutDir>.\QtGeneratedFiles\qt</GeneratedFilesOutDir> - <QtToolsDir>$(QtBaseDir)\bin</QtToolsDir> - <QtReleaseLibraries>$(QtPluginsLibraryDir)\platforms\qminimal.lib;$(QtPluginsLibraryDir)\platforms\qwindows.lib;$(QtPluginsLibraryDir)\styles\qwindowsvistastyle.lib;$(QtLibraryDir)\Qt5WindowsUIAutomationSupport.lib;$(QtLibraryDir)\qtfreetype.lib;$(QtLibraryDir)\qtharfbuzz.lib;$(QtLibraryDir)\qtlibpng.lib;$(QtLibraryDir)\qtpcre2.lib;$(QtLibraryDir)\Qt5AccessibilitySupport.lib;$(QtLibraryDir)\Qt5Core.lib;$(QtLibraryDir)\Qt5Concurrent.lib;$(QtLibraryDir)\Qt5EventDispatcherSupport.lib;$(QtLibraryDir)\Qt5FontDatabaseSupport.lib;$(QtLibraryDir)\Qt5Gui.lib;$(QtLibraryDir)\Qt5Network.lib;$(QtLibraryDir)\Qt5PlatformCompositorSupport.lib;$(QtLibraryDir)\Qt5ThemeSupport.lib;$(QtLibraryDir)\Qt5Widgets.lib;$(QtLibraryDir)\Qt5WinExtras.lib;$(QtLibraryDir)\qtmain.lib;Wtsapi32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtReleaseLibraries> - <QtDebugLibraries>$(QtPluginsLibraryDir)\platforms\qwindowsd.lib;$(QtPluginsLibraryDir)\platforms\qminimald.lib;$(QtPluginsLibraryDir)\styles\qwindowsvistastyled.lib;$(QtLibraryDir)\*d.lib;Wtsapi32.lib;crypt32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtDebugLibraries> - </PropertyGroup> - - <ItemDefinitionGroup> - <ClCompile> - <PreprocessorDefinitions>QT_NO_KEYWORDS;QT_USE_QSTRINGBUILDER;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ClCompile> - </ItemDefinitionGroup> - -</Project> diff --git a/build_msvc/common.vcxproj b/build_msvc/common.vcxproj deleted file mode 100644 index 270c75e8a7..0000000000 --- a/build_msvc/common.vcxproj +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> -<PropertyGroup><BuildDependsOn>$(BuildDependsOn);CopyBuildArtifacts</BuildDependsOn></PropertyGroup> - <Target Name="CopyBuildArtifacts" Condition="'$(ConfigurationType)' != 'StaticLibrary'"> - <ItemGroup> - <BuildArtifacts Include="$(OutDir)$(TargetName)$(TargetExt)"></BuildArtifacts> - <BuildArtifacts Include="$(OutDir)$(TargetName).pdb" Condition="Exists('$(OutDir)$(TargetName).pdb')"></BuildArtifacts> - </ItemGroup> - <Copy SourceFiles="@(BuildArtifacts)" SkipUnchangedFiles="true" DestinationFolder="..\..\src\" Condition="'$(OutDir)' != ''"></Copy> - </Target> - <Import Project="common.vcxproj.user" Condition="Exists('common.vcxproj.user')" /> -</Project> diff --git a/build_msvc/fuzz/fuzz.vcxproj b/build_msvc/fuzz/fuzz.vcxproj deleted file mode 100644 index 7c72703c93..0000000000 --- a/build_msvc/fuzz/fuzz.vcxproj +++ /dev/null @@ -1,85 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{AFCEE6C1-89FB-49AB-A694-BA580A59E2D8}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\test\fuzz\*.cpp" /> - <ClCompile Include="..\..\src\test\fuzz\util\descriptor.cpp"> - <ObjectFileName>$(IntDir)test_fuzz_util_descriptor.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\test\fuzz\util\mempool.cpp"> - <ObjectFileName>$(IntDir)test_fuzz_util_mempool.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\test\fuzz\util\net.cpp"> - <ObjectFileName>$(IntDir)test_fuzz_util_net.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\wallet\test\fuzz\coincontrol.cpp"> - <ObjectFileName>$(IntDir)wallet_test_fuzz_coincontrol.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\wallet\test\fuzz\coinselection.cpp"> - <ObjectFileName>$(IntDir)wallet_test_fuzz_coinselection.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\wallet\test\fuzz\fees.cpp"> - <ObjectFileName>$(IntDir)wallet_test_fuzz_fees.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\wallet\test\fuzz\notifications.cpp"> - <ObjectFileName>$(IntDir)wallet_test_fuzz_notifications.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\wallet\test\fuzz\parse_iso8601.cpp"> - <ObjectFileName>$(IntDir)wallet_test_fuzz_parse_iso8601.obj</ObjectFileName> - </ClCompile> - <ClCompile Include="..\..\src\wallet\test\fuzz\scriptpubkeyman.cpp"> - <ObjectFileName>$(IntDir)wallet_test_fuzz_scriptpubkeyman.obj</ObjectFileName> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libminisketch\libminisketch.vcxproj"> - <Project>{542007e3-be0d-4b0d-a6b0-aa8813e2558d}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj"> - <Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_node\libbitcoin_node.vcxproj"> - <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> - <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj"> - <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project> - </ProjectReference> - <ProjectReference Include="..\libtest_util\libtest_util.vcxproj"> - <Project>{1e065f03-3566-47d0-8fa9-daa72b084e7d}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> - <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> - </ProjectReference> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in b/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in deleted file mode 100644 index 620df72a2f..0000000000 --- a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{0667528C-D734-4009-ADF9-C0D6C4A5A5A6}</ProjectGuid> - </PropertyGroup> - <PropertyGroup> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in deleted file mode 100644 index b47d62b295..0000000000 --- a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{7C87E378-DF58-482E-AA2F-1BC129BC19CE}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj deleted file mode 100644 index a34ef41d16..0000000000 --- a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\arith_uint256.cpp" /> - <ClCompile Include="..\..\src\consensus\merkle.cpp" /> - <ClCompile Include="..\..\src\consensus\tx_check.cpp" /> - <ClCompile Include="..\..\src\hash.cpp" /> - <ClCompile Include="..\..\src\primitives\block.cpp" /> - <ClCompile Include="..\..\src\primitives\transaction.cpp" /> - <ClCompile Include="..\..\src\pubkey.cpp" /> - <ClCompile Include="..\..\src\script\interpreter.cpp" /> - <ClCompile Include="..\..\src\script\script.cpp" /> - <ClCompile Include="..\..\src\script\script_error.cpp" /> - <ClCompile Include="..\..\src\uint256.cpp" /> - <ClCompile Include="..\..\src\util\strencodings.cpp" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project>
\ No newline at end of file diff --git a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in b/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in deleted file mode 100644 index 32cb75bf87..0000000000 --- a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{6190199C-6CF4-4DAD-BFBD-93FA72A760C1}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libbitcoin_node/libbitcoin_node.vcxproj.in b/build_msvc/libbitcoin_node/libbitcoin_node.vcxproj.in deleted file mode 100644 index 58e90dbaeb..0000000000 --- a/build_msvc/libbitcoin_node/libbitcoin_node.vcxproj.in +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{460FEE33-1FE1-483F-B3BF-931FF8E969A5}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - <ClCompile Include="..\..\src\wallet\init.cpp"> - <ObjectFileName>$(IntDir)wallet_init.obj</ObjectFileName> - </ClCompile> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project>
\ No newline at end of file diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj deleted file mode 100644 index 9f9dc9d5fa..0000000000 --- a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj +++ /dev/null @@ -1,224 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <Import Project="..\common.qt.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{2B4ABFF8-D1FD-4845-88C9-1F3C0A6512BF}</ProjectGuid> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\qt\addressbookpage.cpp" /> - <ClCompile Include="..\..\src\qt\addresstablemodel.cpp" /> - <ClCompile Include="..\..\src\qt\askpassphrasedialog.cpp" /> - <ClCompile Include="..\..\src\qt\bantablemodel.cpp" /> - <ClCompile Include="..\..\src\qt\bitcoin.cpp" /> - <ClCompile Include="..\..\src\qt\bitcoinaddressvalidator.cpp" /> - <ClCompile Include="..\..\src\qt\bitcoinamountfield.cpp" /> - <ClCompile Include="..\..\src\qt\bitcoingui.cpp" /> - <ClCompile Include="..\..\src\qt\bitcoinstrings.cpp" /> - <ClCompile Include="..\..\src\qt\bitcoinunits.cpp" /> - <ClCompile Include="..\..\src\qt\clientmodel.cpp" /> - <ClCompile Include="..\..\src\qt\coincontroldialog.cpp" /> - <ClCompile Include="..\..\src\qt\coincontroltreewidget.cpp" /> - <ClCompile Include="..\..\src\qt\createwalletdialog.cpp" /> - <ClCompile Include="..\..\src\qt\csvmodelwriter.cpp" /> - <ClCompile Include="..\..\src\qt\editaddressdialog.cpp" /> - <ClCompile Include="..\..\src\qt\guiutil.cpp" /> - <ClCompile Include="..\..\src\qt\initexecutor.cpp" /> - <ClCompile Include="..\..\src\qt\intro.cpp" /> - <ClCompile Include="..\..\src\qt\modaloverlay.cpp" /> - <ClCompile Include="..\..\src\qt\networkstyle.cpp" /> - <ClCompile Include="..\..\src\qt\notificator.cpp" /> - <ClCompile Include="..\..\src\qt\openuridialog.cpp" /> - <ClCompile Include="..\..\src\qt\optionsdialog.cpp" /> - <ClCompile Include="..\..\src\qt\optionsmodel.cpp" /> - <ClCompile Include="..\..\src\qt\overviewpage.cpp" /> - <ClCompile Include="..\..\src\qt\paymentserver.cpp" /> - <ClCompile Include="..\..\src\qt\peertablemodel.cpp" /> - <ClCompile Include="..\..\src\qt\peertablesortproxy.cpp" /> - <ClCompile Include="..\..\src\qt\platformstyle.cpp" /> - <ClCompile Include="..\..\src\qt\psbtoperationsdialog.cpp" /> - <ClCompile Include="..\..\src\qt\qrimagewidget.cpp" /> - <ClCompile Include="..\..\src\qt\qvalidatedlineedit.cpp" /> - <ClCompile Include="..\..\src\qt\qvaluecombobox.cpp" /> - <ClCompile Include="..\..\src\qt\receivecoinsdialog.cpp" /> - <ClCompile Include="..\..\src\qt\receiverequestdialog.cpp" /> - <ClCompile Include="..\..\src\qt\recentrequeststablemodel.cpp" /> - <ClCompile Include="..\..\src\qt\rpcconsole.cpp" /> - <ClCompile Include="..\..\src\qt\sendcoinsdialog.cpp" /> - <ClCompile Include="..\..\src\qt\sendcoinsentry.cpp" /> - <ClCompile Include="..\..\src\qt\signverifymessagedialog.cpp" /> - <ClCompile Include="..\..\src\qt\splashscreen.cpp" /> - <ClCompile Include="..\..\src\qt\trafficgraphwidget.cpp" /> - <ClCompile Include="..\..\src\qt\transactiondesc.cpp" /> - <ClCompile Include="..\..\src\qt\transactiondescdialog.cpp" /> - <ClCompile Include="..\..\src\qt\transactionfilterproxy.cpp" /> - <ClCompile Include="..\..\src\qt\transactionoverviewwidget.cpp" /> - <ClCompile Include="..\..\src\qt\transactionrecord.cpp" /> - <ClCompile Include="..\..\src\qt\transactiontablemodel.cpp" /> - <ClCompile Include="..\..\src\qt\transactionview.cpp" /> - <ClCompile Include="..\..\src\qt\utilitydialog.cpp" /> - <ClCompile Include="..\..\src\qt\walletcontroller.cpp" /> - <ClCompile Include="..\..\src\qt\walletframe.cpp" /> - <ClCompile Include="..\..\src\qt\walletmodel.cpp" /> - <ClCompile Include="..\..\src\qt\walletmodeltransaction.cpp" /> - <ClCompile Include="..\..\src\qt\walletview.cpp" /> - <ClCompile Include="..\..\src\qt\winshutdownmonitor.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_addressbookpage.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_addresstablemodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_askpassphrasedialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_bantablemodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_bitcoin.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_bitcoinaddressvalidator.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_bitcoinamountfield.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_bitcoingui.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_bitcoinunits.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_clientmodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_coincontroldialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_coincontroltreewidget.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_createwalletdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_csvmodelwriter.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_editaddressdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_guiutil.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_initexecutor.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_intro.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_modaloverlay.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_networkstyle.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_notificator.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_openuridialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_optionsdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_optionsmodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_overviewpage.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_paymentserver.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_peertablemodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_peertablesortproxy.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_platformstyle.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_psbtoperationsdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_qrimagewidget.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_qvalidatedlineedit.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_qvaluecombobox.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_receivecoinsdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_receiverequestdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_recentrequeststablemodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_rpcconsole.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_sendcoinsdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_sendcoinsentry.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_signverifymessagedialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_splashscreen.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_trafficgraphwidget.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiondesc.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiondescdialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionfilterproxy.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionoverviewwidget.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionrecord.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiontablemodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionview.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_utilitydialog.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_walletcontroller.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_walletframe.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_walletmodel.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_walletmodeltransaction.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_walletview.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_winshutdownmonitor.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\rcc\qrc_bitcoin.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\rcc\qrc_bitcoin_locale.cpp" /> - </ItemGroup> - - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <PreprocessorDefinitions>_AMD64_;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(QtIncludes);$(GeneratedFilesOutDir)\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - </ItemDefinitionGroup> - - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <PreprocessorDefinitions>_AMD64_;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(QtIncludes);$(GeneratedFilesOutDir)\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - </ItemDefinitionGroup> - - <ItemGroup> - <QT_MOC Include="..\..\src\qt\bitcoinamountfield.cpp" /> - <QT_MOC Include="..\..\src\qt\intro.cpp" /> - <QT_MOC Include="..\..\src\qt\overviewpage.cpp" /> - <QT_MOC Include="..\..\src\qt\rpcconsole.cpp" /> - <MocHeaderFiles Include="..\..\src\qt\*.h" /> - <ResourceTemplates Include="..\..\src\qt\*.qrc" /> - <UiFormFiles Include="..\..\src\qt\forms\*.ui" /> - <TranslationFiles Include="..\..\src\qt\locale\*.ts" /> - </ItemGroup> - - <Target Name="moccode" Inputs="@(QT_MOC)" Outputs="@(QT_MOC->'$(GeneratedFilesOutDir)\%(Filename).moc')"> - <PropertyGroup> - <ErrorText>There was an error executing the libbitcoin_qt moc code include generation task.</ErrorText> - </PropertyGroup> - <MakeDir Directories="$(GeneratedFilesOutDir)" /> - <Exec Command="echo Performing libbitcoin_qt moc code include generation task, output path $(GeneratedFilesOutDir)." /> - <Exec Command="echo $(QtToolsDir)\moc.exe $(MOC_DEFINES) "%(QT_MOC.Identity)" -o $(GeneratedFilesOutDir)\%(Filename).moc." /> - <Exec Command="$(QtToolsDir)\moc.exe $(MOC_DEFINES) "%(QT_MOC.Identity)" -o $(GeneratedFilesOutDir)\%(Filename).moc" /> - </Target> - - <Target Name="mocheader" Inputs="@(MocHeaderFiles)" Outputs="@(MocHeaderFiles->'$(GeneratedFilesOutDir)\moc\moc_%(Filename).cpp')"> - <PropertyGroup> - <ErrorText>There was an error executing the libbitcoin_qt moc header generation task.</ErrorText> - </PropertyGroup> - <Exec Command="echo Performing libbitcoin_qt moc header generation task, output path $(GeneratedFilesOutDir)\moc." /> - <Exec Command="echo $(QtToolsDir)\moc.exe $(MOC_DEFINES) "%(MocHeaderFiles.Identity)" -o $(GeneratedFilesOutDir)\moc\moc_%(Filename).cpp." /> - <MakeDir Directories="$(GeneratedFilesOutDir)\moc\" /> - <Exec Command="$(QtToolsDir)\moc.exe $(MOC_DEFINES) "%(MocHeaderFiles.Identity)" -o $(GeneratedFilesOutDir)\moc\moc_%(Filename).cpp" /> - </Target> - - <Target Name="forms" Inputs="@(UiFormFiles)" Outputs="@(UiFormFiles->'$(GeneratedFilesOutDir)\forms\ui_%(Filename).h')"> - <PropertyGroup> - <ErrorText>There was an error executing the libbitcoin_qt forms header generation task.</ErrorText> - </PropertyGroup> - <Exec Command="echo Performing libbitcoin_qt forms header generation task, output path $(GeneratedFilesOutDir)\forms." /> - <MakeDir Directories="$(GeneratedFilesOutDir)\forms\" /> - <Exec Command="$(QtToolsDir)\uic.exe "%(UiFormFiles.Identity)" -o $(GeneratedFilesOutDir)\forms\ui_%(Filename).h" /> - </Target> - - <Target Name="translation" Inputs="@(TranslationFiles)" Outputs="@(TranslationFiles->'..\..\src\qt\locale\%(Filename).qm')"> - <PropertyGroup> - <ErrorText>There was an error executing the libbitcoin_qt translation file generation task.</ErrorText> - </PropertyGroup> - <Exec Command="echo Performing libbitcoin_qt translation file generation task." /> - <Exec Command="$(QtToolsDir)\lrelease.exe "%(TranslationFiles.Identity)" -qm ..\..\src\qt\locale\%(Filename).qm" /> - </Target> - - <Target Name="resource" Inputs="@(ResourceTemplates)" Outputs="@(ResourceTemplates->'$(GeneratedFilesOutDir)\rcc\qrc_%(Filename).cpp')" DependsOnTargets="translation"> - <PropertyGroup> - <ErrorText>There was an error executing the libbitcoin_qt resource code generation task.</ErrorText> - </PropertyGroup> - <Exec Command="echo Performing libbitcoin_qt resource code generation task, output path $(GeneratedFilesOutDir)\rcc." /> - <MakeDir Directories="$(GeneratedFilesOutDir)\rcc\" /> - <Exec Command="$(QtToolsDir)\rcc.exe --verbose --name %(Filename) "%(ResourceTemplates.Identity)" -o $(GeneratedFilesOutDir)\rcc\qrc_%(Filename).cpp" /> - </Target> - - <Target Name="qtclean"> - <Exec Command="echo Clean libbitcoin_qt generated files from $(GeneratedFilesOutDir)." /> - <RemoveDir Directories="$(GeneratedFilesOutDir)\forms;$(GeneratedFilesOutDir)\moc;$(GeneratedFilesOutDir)\rcc;" /> - <RemoveDir Directories="$(GeneratedFilesOutDir)" /> - </Target> - - <PropertyGroup> - <BuildDependsOn> - moccode; - mocheader; - forms; - translation; - resource; - $(BuildDependsOn); - </BuildDependsOn> - </PropertyGroup> - <PropertyGroup> - <CleanDependsOn> - qtclean; - $(CleanDependsOn); - </CleanDependsOn> - </PropertyGroup> - -</Project> diff --git a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in deleted file mode 100644 index adf4fa0354..0000000000 --- a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in b/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in deleted file mode 100644 index 613d5c7199..0000000000 --- a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{93B86837-B543-48A5-A89B-7C87ABB77DF2}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\wallet\bdb.cpp" /> - <ClCompile Include="..\..\src\wallet\salvage.cpp" /> - <ClCompile Include="..\..\src\wallet\sqlite.cpp" /> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in deleted file mode 100644 index 1a6b7b6b92..0000000000 --- a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in b/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in deleted file mode 100644 index e86eea81e6..0000000000 --- a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{792D487F-F14C-49FC-A9DE-3FC150F31C3F}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libleveldb/libleveldb.vcxproj b/build_msvc/libleveldb/libleveldb.vcxproj deleted file mode 100644 index eacfbb2641..0000000000 --- a/build_msvc/libleveldb/libleveldb.vcxproj +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{18430FEF-6B61-4C53-B396-718E02850F1B}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\leveldb\db\builder.cc" /> - <ClCompile Include="..\..\src\leveldb\db\c.cc" /> - <ClCompile Include="..\..\src\leveldb\db\dbformat.cc" /> - <ClCompile Include="..\..\src\leveldb\db\db_impl.cc" /> - <ClCompile Include="..\..\src\leveldb\db\db_iter.cc" /> - <ClCompile Include="..\..\src\leveldb\db\dumpfile.cc" /> - <ClCompile Include="..\..\src\leveldb\db\filename.cc" /> - <ClCompile Include="..\..\src\leveldb\db\log_reader.cc" /> - <ClCompile Include="..\..\src\leveldb\db\log_writer.cc" /> - <ClCompile Include="..\..\src\leveldb\db\memtable.cc" /> - <ClCompile Include="..\..\src\leveldb\db\repair.cc" /> - <ClCompile Include="..\..\src\leveldb\db\table_cache.cc" /> - <ClCompile Include="..\..\src\leveldb\db\version_edit.cc" /> - <ClCompile Include="..\..\src\leveldb\db\version_set.cc" /> - <ClCompile Include="..\..\src\leveldb\db\write_batch.cc" /> - <ClCompile Include="..\..\src\leveldb\helpers\memenv\memenv.cc" /> - <ClCompile Include="..\..\src\leveldb\table\block.cc" /> - <ClCompile Include="..\..\src\leveldb\table\block_builder.cc" /> - <ClCompile Include="..\..\src\leveldb\table\filter_block.cc" /> - <ClCompile Include="..\..\src\leveldb\table\format.cc" /> - <ClCompile Include="..\..\src\leveldb\table\iterator.cc" /> - <ClCompile Include="..\..\src\leveldb\table\merger.cc" /> - <ClCompile Include="..\..\src\leveldb\table\table.cc" /> - <ClCompile Include="..\..\src\leveldb\table\table_builder.cc" /> - <ClCompile Include="..\..\src\leveldb\table\two_level_iterator.cc" /> - <ClCompile Include="..\..\src\leveldb\util\arena.cc" /> - <ClCompile Include="..\..\src\leveldb\util\bloom.cc" /> - <ClCompile Include="..\..\src\leveldb\util\cache.cc" /> - <ClCompile Include="..\..\src\leveldb\util\coding.cc" /> - <ClCompile Include="..\..\src\leveldb\util\comparator.cc" /> - <ClCompile Include="..\..\src\leveldb\util\crc32c.cc" /> - <ClCompile Include="..\..\src\leveldb\util\env.cc" /> - <ClCompile Include="..\..\src\leveldb\util\env_windows.cc" /> - <ClCompile Include="..\..\src\leveldb\util\filter_policy.cc" /> - <ClCompile Include="..\..\src\leveldb\util\hash.cc" /> - <ClCompile Include="..\..\src\leveldb\util\histogram.cc" /> - <ClCompile Include="..\..\src\leveldb\util\logging.cc" /> - <ClCompile Include="..\..\src\leveldb\util\options.cc" /> - <ClCompile Include="..\..\src\leveldb\util\status.cc" /> - </ItemGroup> - <ItemDefinitionGroup> - <ClCompile> - <PreprocessorDefinitions>HAVE_CRC32C=0;HAVE_SNAPPY=0;LEVELDB_IS_BIG_ENDIAN=0;_UNICODE;UNICODE;_CRT_NONSTDC_NO_DEPRECATE;LEVELDB_PLATFORM_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <DisableSpecificWarnings>4244;4267;4722</DisableSpecificWarnings> - <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - </ItemDefinitionGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libminisketch/libminisketch.vcxproj b/build_msvc/libminisketch/libminisketch.vcxproj deleted file mode 100644 index 60e57caa57..0000000000 --- a/build_msvc/libminisketch/libminisketch.vcxproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{542007E3-BE0D-4B0D-A6B0-AA8813E2558D}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\minisketch\src\minisketch.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_1byte.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_2bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_3bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_4bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_5bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_6bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_7bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\clmul_8bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_1byte.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_2bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_3bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_4bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_5bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_6bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_7bytes.cpp" /> - <ClCompile Include="..\..\src\minisketch\src\fields\generic_8bytes.cpp" /> - </ItemGroup> - <ItemDefinitionGroup> - <ClCompile> - <DisableSpecificWarnings>4060;4065;4146;4244;4267</DisableSpecificWarnings> - <PreprocessorDefinitions>HAVE_CLMUL;DISABLE_DEFAULT_FIELDS;ENABLE_FIELD_32;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ClCompile> - </ItemDefinitionGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj deleted file mode 100644 index 7ea4b96534..0000000000 --- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\secp256k1\src\precomputed_ecmult.c" /> - <ClCompile Include="..\..\src\secp256k1\src\precomputed_ecmult_gen.c" /> - <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c" /> - </ItemGroup> - <ItemDefinitionGroup> - <ClCompile> - <PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;ENABLE_MODULE_ELLSWIFT;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <UndefinePreprocessorDefinitions>USE_ASM_X86_64;%(UndefinePreprocessorDefinitions)</UndefinePreprocessorDefinitions> - <AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <DisableSpecificWarnings>4146;4244;4267</DisableSpecificWarnings> - </ClCompile> - </ItemDefinitionGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libtest_util/libtest_util.vcxproj.in b/build_msvc/libtest_util/libtest_util.vcxproj.in deleted file mode 100644 index 64cfa82dcc..0000000000 --- a/build_msvc/libtest_util/libtest_util.vcxproj.in +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{868474FD-35F6-4400-8EED-30A33E7521D4}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\wallet\test\util.cpp" /> -@SOURCE_FILES@ - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/libunivalue/libunivalue.vcxproj b/build_msvc/libunivalue/libunivalue.vcxproj deleted file mode 100644 index 0f13a57241..0000000000 --- a/build_msvc/libunivalue/libunivalue.vcxproj +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{5724BA7D-A09A-4BA8-800B-C4C1561B3D69}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\univalue\lib\univalue.cpp" /> - <ClCompile Include="..\..\src\univalue\lib\univalue_get.cpp" /> - <ClCompile Include="..\..\src\univalue\lib\univalue_read.cpp" /> - <ClCompile Include="..\..\src\univalue\lib\univalue_write.cpp" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/msbuild/tasks/hexdump.targets b/build_msvc/msbuild/tasks/hexdump.targets deleted file mode 100644 index 12868a9874..0000000000 --- a/build_msvc/msbuild/tasks/hexdump.targets +++ /dev/null @@ -1,53 +0,0 @@ -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <UsingTask - TaskName="HeaderFromHexdump" - TaskFactory="CodeTaskFactory" - AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" > - <ParameterGroup> - <RawFilePath Required="true" /> - <HeaderFilePath Required="true" /> - <SourceHeader Required="true" /> - <SourceFooter Required="true" /> - </ParameterGroup> - <Task> - <Using Namespace="System"/> - <Using Namespace="System.IO"/> - <Code Type="Fragment" Language="cs"> -<![CDATA[ -Log.LogMessage("msbuild inline hexdump task for " + RawFilePath + "."); -if(File.Exists(RawFilePath) == false) { - Log.LogError("hexdump task could not locate " + RawFilePath + "."); -} -else { - FileInfo inFileInfo = new FileInfo(RawFilePath); - FileInfo outFileInfo = new FileInfo(HeaderFilePath); - - if (outFileInfo.Exists == false || inFileInfo.LastWriteTime > outFileInfo.LastWriteTime) - { - using (Stream inStm = File.OpenRead(RawFilePath)) - { - using (StreamWriter sw = new StreamWriter(HeaderFilePath)) - { - sw.WriteLine(SourceHeader); - int count = 0; - int rawChar = inStm.ReadByte(); - while(rawChar != -1) - { - sw.Write("0x{0:x2}, ", rawChar); - count++; - if(count % 8 == 0) - { - sw.WriteLine(); - } - rawChar = inStm.ReadByte(); - } - sw.WriteLine(SourceFooter); - } - } - } -} -]]> - </Code> - </Task> - </UsingTask> -</Project>
\ No newline at end of file diff --git a/build_msvc/msbuild/tasks/replaceinfile.targets b/build_msvc/msbuild/tasks/replaceinfile.targets deleted file mode 100644 index 2ccb8b30e0..0000000000 --- a/build_msvc/msbuild/tasks/replaceinfile.targets +++ /dev/null @@ -1,35 +0,0 @@ -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <UsingTask - TaskName="ReplaceInFile" - TaskFactory="CodeTaskFactory" - AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" > - <ParameterGroup> - <FilePath Required="true" /> - <Replace Required="true" /> - <By Required="false" /> - <ToFullPath Required="false" /> - </ParameterGroup> - <Task> - <Using Namespace="System"/> - <Using Namespace="System.IO"/> - <Code Type="Fragment" Language="cs"> -<![CDATA[ -if(File.Exists(FilePath) == false) { - Log.LogError("replaceinfile task could not locate " + FilePath + "."); -} -else { - var data = File.ReadAllText(FilePath); - var by = By; - if (ToFullPath == "true") - { - by = Path.GetFullPath(by); - } - data = data.Replace(Replace, by); - Log.LogMessage("Replace '" + Replace + "' by '" + by + "' in " + FilePath); - File.WriteAllText(FilePath, data, new System.Text.UTF8Encoding(false)); -} -]]> - </Code> - </Task> - </UsingTask> -</Project>
\ No newline at end of file diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py deleted file mode 100755 index 9484f0cb89..0000000000 --- a/build_msvc/msvc-autogen.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2016-2022 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -import re -import argparse -from shutil import copyfile - -SOURCE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'src')) -DEFAULT_PLATFORM_TOOLSET = R'v143' - -libs = [ - 'libbitcoin_cli', - 'libbitcoin_common', - 'libbitcoin_crypto', - 'libbitcoin_node', - 'libbitcoin_util', - 'libbitcoin_wallet_tool', - 'libbitcoin_wallet', - 'libbitcoin_zmq', - 'bench_bitcoin', - 'libtest_util', -] - -ignore_list = [ -] - -lib_sources = {} - - -def parse_makefile(makefile): - with open(makefile, 'r', encoding='utf-8') as file: - current_lib = '' - for line in file.read().splitlines(): - if current_lib: - source = line.split()[0] - if source.endswith('.cpp') and not source.startswith('$') and source not in ignore_list: - source_filename = source.replace('/', '\\') - object_filename = source.replace('/', '_')[:-4] + ".obj" - lib_sources[current_lib].append((source_filename, object_filename)) - if not line.endswith('\\'): - current_lib = '' - continue - for lib in libs: - _lib = lib.replace('-', '_') - if re.search(_lib + '.*_SOURCES \\= \\\\', line): - current_lib = lib - lib_sources[current_lib] = [] - break - -def parse_config_into_btc_config(): - def find_between( s, first, last ): - try: - start = s.index( first ) + len( first ) - end = s.index( last, start ) - return s[start:end] - except ValueError: - return "" - - config_info = [] - with open(os.path.join(SOURCE_DIR,'../configure.ac'), encoding="utf8") as f: - for line in f: - if line.startswith("define"): - config_info.append(find_between(line, "(_", ")")) - - config_info = [c for c in config_info if not c.startswith("COPYRIGHT_HOLDERS")] - - config_dict = dict(item.split(", ") for item in config_info) - config_dict["PACKAGE_VERSION"] = f"\"{config_dict['CLIENT_VERSION_MAJOR']}.{config_dict['CLIENT_VERSION_MINOR']}.{config_dict['CLIENT_VERSION_BUILD']}\"" - version = config_dict["PACKAGE_VERSION"].strip('"') - config_dict["PACKAGE_STRING"] = f"\"Bitcoin Core {version}\"" - - with open(os.path.join(SOURCE_DIR,'../build_msvc/bitcoin_config.h.in'), "r", encoding="utf8") as template_file: - template = template_file.readlines() - - for index, line in enumerate(template): - header = "" - if line.startswith("#define"): - header = line.split(" ")[1] - if header in config_dict: - template[index] = line.replace("$", f"{config_dict[header]}") - - with open(os.path.join(SOURCE_DIR,'../build_msvc/bitcoin_config.h'), "w", encoding="utf8") as btc_config: - btc_config.writelines(template) - -def set_properties(vcxproj_filename, placeholder, content): - with open(vcxproj_filename + '.in', 'r', encoding='utf-8') as vcxproj_in_file: - with open(vcxproj_filename, 'w', encoding='utf-8') as vcxproj_file: - vcxproj_file.write(vcxproj_in_file.read().replace(placeholder, content)) - -def main(): - parser = argparse.ArgumentParser(description='Bitcoin-core msbuild configuration initialiser.') - parser.add_argument('-toolset', nargs='?', default=DEFAULT_PLATFORM_TOOLSET, - help='Optionally sets the msbuild platform toolset, e.g. v143 for Visual Studio 2022.' - ' default is %s.'%DEFAULT_PLATFORM_TOOLSET) - args = parser.parse_args() - set_properties(os.path.join(SOURCE_DIR, '../build_msvc/common.init.vcxproj'), '@TOOLSET@', args.toolset) - - for makefile_name in os.listdir(SOURCE_DIR): - if 'Makefile' in makefile_name: - parse_makefile(os.path.join(SOURCE_DIR, makefile_name)) - for key, value in lib_sources.items(): - vcxproj_filename = os.path.abspath(os.path.join(os.path.dirname(__file__), key, key + '.vcxproj')) - content = '' - for source_filename, object_filename in value: - content += ' <ClCompile Include="..\\..\\src\\' + source_filename + '">\n' - content += ' <ObjectFileName>$(IntDir)' + object_filename + '</ObjectFileName>\n' - content += ' </ClCompile>\n' - set_properties(vcxproj_filename, '@SOURCE_FILES@\n', content) - parse_config_into_btc_config() - copyfile(os.path.join(SOURCE_DIR,'../build_msvc/bitcoin_config.h'), os.path.join(SOURCE_DIR, 'config/bitcoin-config.h')) - -if __name__ == '__main__': - main() diff --git a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj deleted file mode 100644 index 7b4b73ca21..0000000000 --- a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj +++ /dev/null @@ -1,124 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <Import Project="..\common.qt.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{51201D5E-D939-4854-AE9D-008F03FF518E}</ProjectGuid> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\init\bitcoin-qt.cpp" /> - <ClCompile Include="..\..\src\qt\test\addressbooktests.cpp" /> - <ClCompile Include="..\..\src\qt\test\apptests.cpp" /> - <ClCompile Include="..\..\src\qt\test\optiontests.cpp" /> - <ClCompile Include="..\..\src\qt\test\rpcnestedtests.cpp" /> - <ClCompile Include="..\..\src\qt\test\test_main.cpp" /> - <ClCompile Include="..\..\src\qt\test\uritests.cpp" /> - <ClCompile Include="..\..\src\qt\test\util.cpp" /> - <ClCompile Include="..\..\src\qt\test\wallettests.cpp" /> - <ClCompile Include="..\..\src\wallet\test\wallet_test_fixture.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_addressbooktests.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_apptests.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_optiontests.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_rpcnestedtests.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_uritests.cpp" /> - <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_wallettests.cpp" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj"> - <Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_qt\libbitcoin_qt.vcxproj"> - <Project>{2b4abff8-d1fd-4845-88c9-1f3c0a6512bf}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_node\libbitcoin_node.vcxproj"> - <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> - <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj"> - <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project> - </ProjectReference> - <ProjectReference Include="..\libtest_util\libtest_util.vcxproj"> - <Project>{1e065f03-3566-47d0-8fa9-daa72b084e7d}</Project> - </ProjectReference> - <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> - <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - </ItemGroup> - - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - - <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> - <ClCompile> - <AdditionalIncludeDirectories>..\libbitcoin_qt\$(GeneratedFilesOutDir)\..\;$(QtIncludeDir)\QtTest;$(QtIncludes);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - <Link> - <AdditionalDependencies>$(QtLibraryDir)\Qt5Test.lib;$(QtReleaseLibraries);%(AdditionalDependencies)</AdditionalDependencies> - <AdditionalOptions>/LTCG:OFF</AdditionalOptions> - </Link> - </ItemDefinitionGroup> - - <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> - <ClCompile> - <AdditionalIncludeDirectories>..\libbitcoin_qt\$(GeneratedFilesOutDir)\..\;$(QtIncludeDir)\QtTest;$(QtIncludes);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - <Link> - <AdditionalDependencies>$(QtDebugLibraries);%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <MocTestFiles Include="..\..\src\qt\test\addressbooktests.h" /> - <MocTestFiles Include="..\..\src\qt\test\apptests.h" /> - <MocTestFiles Include="..\..\src\qt\test\optiontests.h" /> - <MocTestFiles Include="..\..\src\qt\test\rpcnestedtests.h" /> - <MocTestFiles Include="..\..\src\qt\test\uritests.h" /> - <MocTestFiles Include="..\..\src\qt\test\wallettests.h" /> - </ItemGroup> - <Target Name="moccode" Inputs="@(MocTestFiles)" Outputs="@(MocTestFiles->'$(GeneratedFilesOutDir)\moc\moc_%(Filename).cpp')"> - <PropertyGroup> - <ErrorText>There was an error executing the test_bitcoin-qt moc code generation task.</ErrorText> - </PropertyGroup> - <Exec Command="echo Performing test_bitcoin-qt moc generation task, output path $(GeneratedFilesOutDir)\moc." /> - <MakeDir Directories="$(GeneratedFilesOutDir)\moc\" /> - <Exec Command="$(QtToolsDir)\moc.exe $(MOC_DEFINES) "%(MocTestFiles.Identity)" -o $(GeneratedFilesOutDir)\moc\moc_%(Filename).cpp" /> - </Target> - <Target Name="QtTestCleanGeneratedFiles"> - <Exec Command="echo Clean test_bitcoin-qt generated files from $(GeneratedFilesOutDir)." /> - <RemoveDir Directories="$(GeneratedFilesOutDir)\moc\*" /> - <RemoveDir Directories="$(GeneratedFilesOutDir)\moc" /> - </Target> - <PropertyGroup> - <BuildDependsOn> - moccode; - $(BuildDependsOn); - </BuildDependsOn> - </PropertyGroup> - <PropertyGroup> - <CleanDependsOn> - QtTestCleanGeneratedFiles; - $(CleanDependsOn); - </CleanDependsOn> - </PropertyGroup> -</Project> diff --git a/build_msvc/test_bitcoin/test_bitcoin.vcxproj b/build_msvc/test_bitcoin/test_bitcoin.vcxproj deleted file mode 100644 index b5aa58057f..0000000000 --- a/build_msvc/test_bitcoin/test_bitcoin.vcxproj +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\common.init.vcxproj" /> - <PropertyGroup Label="Globals"> - <ProjectGuid>{A56B73DB-D46D-4882-8374-1FE3FFA08F07}</ProjectGuid> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> - </PropertyGroup> - <ItemGroup> - <ClCompile Include="..\..\src\test\*_properties.cpp" /> - <ClCompile Include="..\..\src\test\*_tests.cpp" Exclude="..\..\src\test\ipc_tests.cpp" /> - <ClCompile Include="..\..\src\test\gen\*_gen.cpp" /> - <ClCompile Include="..\..\src\test\main.cpp" /> - <ClCompile Include="..\..\src\test\util\*.cpp" /> - <ClCompile Include="..\..\src\wallet\test\*_fixture.cpp" /> - <ClCompile Include="..\..\src\wallet\test\*_tests.cpp" /> - <ClCompile Include="..\..\src\wallet\test\util.cpp" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\libminisketch\libminisketch.vcxproj"> - <Project>{542007e3-be0d-4b0d-a6b0-aa8813e2558d}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj"> - <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj"> - <Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> - <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> - <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_node\libbitcoin_node.vcxproj"> - <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> - <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> - <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> - </ProjectReference> - <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj"> - <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project> - </ProjectReference> - <ProjectReference Include="..\libtest_util\libtest_util.vcxproj"> - <Project>{1e065f03-3566-47d0-8fa9-daa72b084e7d}</Project> - </ProjectReference> - <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> - <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> - </ProjectReference> - <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> - <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> - </ProjectReference> - <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> - <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> - </ProjectReference> - </ItemGroup> - <Target Name="RawBenchHeaderGen" BeforeTargets="PrepareForBuild"> - <PropertyGroup> - <ErrorText>There was an error executing the JSON test header generation task.</ErrorText> - </PropertyGroup> - <ItemGroup> - <JsonTestFile Include="..\..\src\test\data\*.json" /> - <RawTestFile Include="..\..\src\test\data\*.raw" /> - </ItemGroup> - <HeaderFromHexdump RawFilePath="%(RawTestFile.FullPath)" HeaderFilePath="%(RawTestFile.FullPath).h" SourceHeader="static unsigned const char %(RawTestFile.Filename)_raw[] = {" SourceFooter="};" /> - <HeaderFromHexdump RawFilePath="%(JsonTestFile.FullPath)" HeaderFilePath="%(JsonTestFile.FullPath).h" SourceHeader="#include <string>
namespace json_tests{ static const std::string %(JsonTestFile.Filename){" SourceFooter="};}" /> - </Target> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <Import Label="hexdumpTarget" Project="..\msbuild\tasks\hexdump.targets" /> - <Import Project="..\common.vcxproj" /> -</Project> diff --git a/build_msvc/vcpkg.json b/build_msvc/vcpkg.json deleted file mode 100644 index b2c406ae12..0000000000 --- a/build_msvc/vcpkg.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "bitcoin-core", - "version-string": "1", - "dependencies": [ - "berkeleydb", - "boost-date-time", - "boost-multi-index", - "boost-signals2", - "boost-test", - "libevent", - "sqlite3", - "zeromq" - ], - "builtin-baseline": "9edb1b8e590cc086563301d735cae4b6e732d2d2", - "overrides": [ - { - "name": "libevent", - "version": "2.1.12#7" - } - ] -} diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh index 87e3a8fa9b..d899c0c67a 100755 --- a/ci/lint/04_install.sh +++ b/ci/lint/04_install.sh @@ -1,25 +1,26 @@ #!/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: -# - automake pkg-config libtool (for lint_includes_build_config) # - curl/xz-utils (to install shellcheck) # - git (used in many lint scripts) # - gpg (used by verify-commits) -${CI_RETRY_EXE} apt-get install -y automake pkg-config libtool curl xz-utils git gpg +${CI_RETRY_EXE} apt-get install -y curl xz-utils git gpg 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 +29,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 +39,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}" @@ -47,10 +48,10 @@ fi ${CI_RETRY_EXE} pip3 install \ codespell==2.2.6 \ - flake8==6.1.0 \ 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 +59,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.sh b/ci/test/00_setup_env.sh index b9e6818afb..021d5e1597 100755 --- a/ci/test/00_setup_env.sh +++ b/ci/test/00_setup_env.sh @@ -53,20 +53,18 @@ export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false} export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1} # See man 7 debconf export DEBIAN_FRONTEND=noninteractive -export CCACHE_MAXSIZE=${CCACHE_MAXSIZE:-100M} +export CCACHE_MAXSIZE=${CCACHE_MAXSIZE:-500M} export CCACHE_TEMPDIR=${CCACHE_TEMPDIR:-/tmp/.ccache-temp} export CCACHE_COMPRESS=${CCACHE_COMPRESS:-1} # The cache dir. # This folder exists only on the ci guest, and on the ci host as a volume. -export CCACHE_DIR=${CCACHE_DIR:-$BASE_SCRATCH_DIR/.ccache} +export CCACHE_DIR="${CCACHE_DIR:-$BASE_SCRATCH_DIR/ccache}" # Folder where the build result is put (bin and lib). export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out} -# Folder where the build is done (dist and out-of-tree build). -export BASE_BUILD_DIR=${BASE_BUILD_DIR:-$BASE_SCRATCH_DIR/build} # The folder for previous release binaries. # This folder exists only on the ci guest, and on the ci host as a volume. export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/prev_releases} -export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps bison e2fsprogs cmake} +export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential pkg-config curl ca-certificates ccache python3 rsync git procps bison e2fsprogs cmake} export GOAL=${GOAL:-install} export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_SCRATCH_DIR}/qa-assets} export CI_RETRY_EXE=${CI_RETRY_EXE:-"retry --"} diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh index 396e782959..749ae86cb2 100755 --- a/ci/test/00_setup_env_arm.sh +++ b/ci/test/00_setup_env_arm.sh @@ -17,4 +17,4 @@ export RUN_FUNCTIONAL_TESTS=false export GOAL="install" # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" # This could be removed once the ABI change warning does not show up by default -export BITCOIN_CONFIG="--enable-reduce-exports CXXFLAGS='-Wno-psabi -Wno-error=maybe-uninitialized'" +export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DCMAKE_CXX_FLAGS='-Wno-psabi -Wno-error=maybe-uninitialized'" diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh index 5f8391c5da..5604004d3a 100755 --- a/ci/test/00_setup_env_i686_centos.sh +++ b/ci/test/00_setup_env_i686_centos.sh @@ -9,9 +9,9 @@ export LC_ALL=C.UTF-8 export HOST=i686-pc-linux-gnu export CONTAINER_NAME=ci_i686_centos export CI_IMAGE_NAME_TAG="quay.io/centos/amd64:stream9" -export CI_BASE_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison util-linux e2fsprogs cmake" +export CI_BASE_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison util-linux e2fsprogs cmake" export PIP_PACKAGES="pyzmq" export GOAL="install" export NO_WERROR=1 # Suppress error: #warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform [-Werror=cpp] -export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports" +export BITCOIN_CONFIG="-DWITH_ZMQ=ON -DBUILD_GUI=ON -DREDUCE_EXPORTS=ON" export CONFIG_SHELL="/bin/dash" diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh index f6463438d3..5810ae8639 100755 --- a/ci/test/00_setup_env_i686_multiprocess.sh +++ b/ci/test/00_setup_env_i686_multiprocess.sh @@ -13,6 +13,11 @@ export PACKAGES="llvm clang g++-multilib" export DEP_OPTS="DEBUG=1 MULTIPROCESS=1" export GOAL="install" export TEST_RUNNER_EXTRA="--v2transport" -export BITCOIN_CONFIG="--enable-debug CC='clang -m32' CXX='clang++ -m32' \ -CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS='-Wno-error=documentation'" +export BITCOIN_CONFIG="\ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_C_COMPILER='clang;-m32' \ + -DCMAKE_CXX_COMPILER='clang++;-m32' \ + -DCMAKE_CXX_FLAGS='-Wno-error=documentation' \ + -DAPPEND_CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' \ +" export BITCOIND=bitcoin-node # Used in functional tests diff --git a/ci/test/00_setup_env_mac_cross.sh b/ci/test/00_setup_env_mac_cross.sh index 31c4bff6ae..6a1e116a54 100755 --- a/ci/test/00_setup_env_mac_cross.sh +++ b/ci/test/00_setup_env_mac_cross.sh @@ -9,12 +9,12 @@ export LC_ALL=C.UTF-8 export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks} export CONTAINER_NAME=ci_macos_cross -export CI_IMAGE_NAME_TAG="docker.io/ubuntu:22.04" +export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04" export HOST=x86_64-apple-darwin -export PACKAGES="zip" +export PACKAGES="clang lld llvm zip" export XCODE_VERSION=15.0 export XCODE_BUILD_ID=15A240d export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export GOAL="deploy" -export BITCOIN_CONFIG="--with-gui --enable-reduce-exports" +export BITCOIN_CONFIG="-DBUILD_GUI=ON -DREDUCE_EXPORTS=ON" diff --git a/ci/test/00_setup_env_mac_native.sh b/ci/test/00_setup_env_mac_native.sh index c47f13f96e..45d644d9ca 100755 --- a/ci/test/00_setup_env_mac_native.sh +++ b/ci/test/00_setup_env_mac_native.sh @@ -6,14 +6,13 @@ export LC_ALL=C.UTF-8 -export HOST=x86_64-apple-darwin # Homebrew's python@3.12 is marked as externally managed (PEP 668). # Therefore, `--break-system-packages` is needed. export PIP_PACKAGES="--break-system-packages zmq" export GOAL="install" -export BITCOIN_CONFIG="--with-gui --with-miniupnpc --with-natpmp --enable-reduce-exports" +export CMAKE_GENERATOR="Ninja" +export BITCOIN_CONFIG="-DBUILD_GUI=ON -DWITH_ZMQ=ON -DWITH_MINIUPNPC=ON -DREDUCE_EXPORTS=ON" export CI_OS_NAME="macos" export NO_DEPENDS=1 export OSX_SDK="" -export CCACHE_MAXSIZE=400M export RUN_FUZZ_TESTS=true diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh index 668e9ecc8a..dc84ef49a4 100755 --- a/ci/test/00_setup_env_native_asan.sh +++ b/ci/test/00_setup_env_native_asan.sh @@ -7,8 +7,10 @@ export LC_ALL=C.UTF-8 export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04" -# Only install BCC tracing packages in Cirrus CI. -if [[ "${CIRRUS_CI}" == "true" ]]; then + +# Only install BCC tracing packages in CI. Container has to match the host for BCC to work. +if [[ "${INSTALL_BCC_TRACING_TOOLS}" == "true" ]]; then + # Required for USDT functional tests to run BPFCC_PACKAGE="bpfcc-tools linux-headers-$(uname --kernel-release)" export CI_CONTAINER_CAP="--privileged -v /sys/kernel:/sys/kernel:rw" else @@ -17,10 +19,16 @@ 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 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 \ -CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' \ ---with-sanitizers=address,float-divide-by-zero,integer,undefined \ -CC='clang-18 -ftrivial-auto-var-init=pattern' CXX='clang++-18 -ftrivial-auto-var-init=pattern'" +export BITCOIN_CONFIG="\ + -DWITH_USDT=ON -DWITH_ZMQ=ON -DWITH_BDB=ON -DWARN_INCOMPATIBLE_BDB=OFF -DBUILD_GUI=ON \ + -DSANITIZERS=address,float-divide-by-zero,integer,undefined \ + -DCMAKE_C_COMPILER=clang-18 \ + -DCMAKE_CXX_COMPILER=clang++-18 \ + -DCMAKE_C_FLAGS='-ftrivial-auto-var-init=pattern' \ + -DCMAKE_CXX_FLAGS='-ftrivial-auto-var-init=pattern -Wno-error=deprecated-declarations' \ + -DAPPEND_CXXFLAGS='-std=c++23' \ + -DAPPEND_CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' \ +" diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh index f50561f875..1aa2487045 100755 --- a/ci/test/00_setup_env_native_fuzz.sh +++ b/ci/test/00_setup_env_native_fuzz.sh @@ -15,7 +15,12 @@ export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true export GOAL="install" export CI_CONTAINER_CAP="--cap-add SYS_PTRACE" # If run with (ASan + LSan), the container needs access to ptrace (https://github.com/google/sanitizers/issues/764) -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,float-divide-by-zero,integer \ -CC='clang-18 -ftrivial-auto-var-init=pattern' CXX='clang++-18 -ftrivial-auto-var-init=pattern'" -export CCACHE_MAXSIZE=200M +export BITCOIN_CONFIG="\ + -DBUILD_FOR_FUZZING=ON \ + -DSANITIZERS=fuzzer,address,undefined,float-divide-by-zero,integer \ + -DCMAKE_C_COMPILER=clang-18 \ + -DCMAKE_CXX_COMPILER=clang++-18 \ + -DCMAKE_C_FLAGS='-ftrivial-auto-var-init=pattern' \ + -DCMAKE_CXX_FLAGS='-ftrivial-auto-var-init=pattern' \ +" export LLVM_SYMBOLIZER_PATH="/usr/bin/llvm-symbolizer-18" diff --git a/ci/test/00_setup_env_native_fuzz_with_msan.sh b/ci/test/00_setup_env_native_fuzz_with_msan.sh index f1c358082d..cfdbc8c014 100755 --- a/ci/test/00_setup_env_native_fuzz_with_msan.sh +++ b/ci/test/00_setup_env_native_fuzz_with_msan.sh @@ -17,10 +17,17 @@ export PACKAGES="ninja-build" # BDB generates false-positives and will be removed in future export DEP_OPTS="DEBUG=1 NO_BDB=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'" export GOAL="install" +# Setting CMAKE_{C,CXX}_FLAGS_DEBUG flags to an empty string ensures that the flags set in MSAN_FLAGS remain unaltered. # _FORTIFY_SOURCE is not compatible with MSAN. -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE -U_FORTIFY_SOURCE'" +export BITCOIN_CONFIG="\ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_C_FLAGS_DEBUG='' \ + -DCMAKE_CXX_FLAGS_DEBUG='' \ + -DBUILD_FOR_FUZZING=ON \ + -DSANITIZERS=fuzzer,memory \ + -DAPPEND_CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE -U_FORTIFY_SOURCE' \ +" export USE_MEMORY_SANITIZER="true" export RUN_UNIT_TESTS="false" export RUN_FUNCTIONAL_TESTS="false" export RUN_FUZZ_TESTS=true -export CCACHE_MAXSIZE=250M diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh index bf4d1573e3..c65c05bff9 100755 --- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh +++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh @@ -15,5 +15,10 @@ export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true export FUZZ_TESTS_CONFIG="--valgrind" export GOAL="install" -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang-16 CXX=clang++-16" -export CCACHE_MAXSIZE=200M +export BITCOIN_CONFIG="\ + -DBUILD_FOR_FUZZING=ON \ + -DSANITIZERS=fuzzer \ + -DCMAKE_C_COMPILER=clang-16 \ + -DCMAKE_CXX_COMPILER=clang++-16 \ +" +export LLVM_SYMBOLIZER_PATH="/usr/bin/llvm-symbolizer-16" diff --git a/ci/test/00_setup_env_native_msan.sh b/ci/test/00_setup_env_native_msan.sh index dd465cac2e..c6b3d68be6 100755 --- a/ci/test/00_setup_env_native_msan.sh +++ b/ci/test/00_setup_env_native_msan.sh @@ -17,8 +17,14 @@ export PACKAGES="ninja-build" # BDB generates false-positives and will be removed in future export DEP_OPTS="DEBUG=1 NO_BDB=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'" export GOAL="install" +# Setting CMAKE_{C,CXX}_FLAGS_DEBUG flags to an empty string ensures that the flags set in MSAN_FLAGS remain unaltered. # _FORTIFY_SOURCE is not compatible with MSAN. -export BITCOIN_CONFIG="--with-sanitizers=memory CPPFLAGS='-U_FORTIFY_SOURCE'" +export BITCOIN_CONFIG="\ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_C_FLAGS_DEBUG='' \ + -DCMAKE_CXX_FLAGS_DEBUG='' \ + -DSANITIZERS=memory \ + -DAPPEND_CPPFLAGS='-U_FORTIFY_SOURCE' \ +" export USE_MEMORY_SANITIZER="true" export RUN_FUNCTIONAL_TESTS="false" -export CCACHE_MAXSIZE=250M diff --git a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh index 6425120afb..3d5d1b7745 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:bookworm" +# Use minimum supported python3.10 (or best-effort 3.11) 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" +export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_UTIL_CHAINSTATE=ON -DBUILD_KERNEL_LIB=ON -DBUILD_SHARED_LIBS=ON" diff --git a/ci/test/00_setup_env_native_previous_releases.sh b/ci/test/00_setup_env_native_previous_releases.sh index 9da3b18999..717eb67a28 100755 --- a/ci/test/00_setup_env_native_previous_releases.sh +++ b/ci/test/00_setup_env_native_previous_releases.sh @@ -8,13 +8,20 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_previous_releases export CI_IMAGE_NAME_TAG="docker.io/ubuntu:22.04" -# Use minimum supported python3.9 (or best effort 3.10) and gcc-11, see doc/dependencies.md +# Use minimum supported python3.10 and gcc-11, see doc/dependencies.md export PACKAGES="gcc-11 g++-11 python3-zmq" -export DEP_OPTS="NO_UPNP=1 NO_NATPMP=1 DEBUG=1 CC=gcc-11 CXX=g++-11" +export DEP_OPTS="NO_UPNP=1 DEBUG=1 CC=gcc-11 CXX=g++-11" export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash export RUN_UNIT_TESTS_SEQUENTIAL="true" export RUN_UNIT_TESTS="false" export GOAL="install" export DOWNLOAD_PREVIOUS_RELEASES="true" -export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --enable-debug \ -CFLAGS=\"-g0 -O2 -funsigned-char\" CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS=\"-g0 -O2 -funsigned-char\"" +export BITCOIN_CONFIG="\ + -DWITH_ZMQ=ON -DBUILD_GUI=ON -DREDUCE_EXPORTS=ON \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_C_FLAGS='-funsigned-char' \ + -DCMAKE_C_FLAGS_DEBUG='-g0 -O2' \ + -DCMAKE_CXX_FLAGS='-funsigned-char' \ + -DCMAKE_CXX_FLAGS_DEBUG='-g0 -O2' \ + -DAPPEND_CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' \ +" diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh index 5f422bbdb6..cc1dea09cb 100755 --- a/ci/test/00_setup_env_native_tidy.sh +++ b/ci/test/00_setup_env_native_tidy.sh @@ -9,12 +9,19 @@ export LC_ALL=C.UTF-8 export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04" export CONTAINER_NAME=ci_native_tidy export TIDY_LLVM_V="18" -export PACKAGES="clang-${TIDY_LLVM_V} libclang-${TIDY_LLVM_V}-dev llvm-${TIDY_LLVM_V}-dev libomp-${TIDY_LLVM_V}-dev clang-tidy-${TIDY_LLVM_V} jq bear libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev qtbase5-dev qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev" +export PACKAGES="clang-${TIDY_LLVM_V} libclang-${TIDY_LLVM_V}-dev llvm-${TIDY_LLVM_V}-dev libomp-${TIDY_LLVM_V}-dev clang-tidy-${TIDY_LLVM_V} jq libevent-dev libboost-dev libminiupnpc-dev libzmq3-dev systemtap-sdt-dev qtbase5-dev qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev" export NO_DEPENDS=1 export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=false +export RUN_CHECK_DEPS=true export RUN_TIDY=true export GOAL="install" -export BITCOIN_CONFIG="CC=clang-${TIDY_LLVM_V} CXX=clang++-${TIDY_LLVM_V} --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'" -export CCACHE_MAXSIZE=200M +export BITCOIN_CONFIG="\ + -DWITH_ZMQ=ON -DBUILD_GUI=ON -DBUILD_BENCH=ON -DWITH_MINIUPNPC=ON -DWITH_USDT=ON -DWITH_BDB=ON -DWARN_INCOMPATIBLE_BDB=OFF \ + -DENABLE_HARDENING=OFF \ + -DCMAKE_C_COMPILER=clang-${TIDY_LLVM_V} \ + -DCMAKE_CXX_COMPILER=clang++-${TIDY_LLVM_V} \ + -DCMAKE_C_FLAGS_RELWITHDEBINFO='-O0 -g0' \ + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO='-O0 -g0' \ +" diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh index 3fcaa8c6c6..9c2da778b4 100755 --- a/ci/test/00_setup_env_native_tsan.sh +++ b/ci/test/00_setup_env_native_tsan.sh @@ -11,4 +11,5 @@ 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="-DWITH_ZMQ=ON -DSANITIZERS=thread \ +-DAPPEND_CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES'" diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh index ebef590c0a..3c5622cd02 100755 --- a/ci/test/00_setup_env_native_valgrind.sh +++ b/ci/test/00_setup_env_native_valgrind.sh @@ -8,9 +8,14 @@ export LC_ALL=C.UTF-8 export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04" export CONTAINER_NAME=ci_native_valgrind -export PACKAGES="valgrind clang-16 llvm-16 libclang-rt-16-dev python3-zmq libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev" +export PACKAGES="valgrind clang-16 llvm-16 libclang-rt-16-dev python3-zmq libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libsqlite3-dev" export USE_VALGRIND=1 export NO_DEPENDS=1 export TEST_RUNNER_EXTRA="--exclude feature_init,rpc_bind,feature_bind_extra" # feature_init excluded for now, see https://github.com/bitcoin/bitcoin/issues/30011 ; bind tests excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547 export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang-16 CXX=clang++-16" # TODO enable GUI +# TODO enable GUI +export BITCOIN_CONFIG="\ + -DWITH_ZMQ=ON -DWITH_BDB=ON -DWITH_MINIUPNPC=ON -DWARN_INCOMPATIBLE_BDB=OFF -DBUILD_GUI=OFF \ + -DCMAKE_C_COMPILER=clang-16 \ + -DCMAKE_CXX_COMPILER=clang++-16 \ +" diff --git a/ci/test/00_setup_env_s390x.sh b/ci/test/00_setup_env_s390x.sh index 2fd94e253c..eb12bc6fd1 100755 --- a/ci/test/00_setup_env_s390x.sh +++ b/ci/test/00_setup_env_s390x.sh @@ -13,4 +13,4 @@ export CI_IMAGE_NAME_TAG="docker.io/s390x/ubuntu:24.04" export TEST_RUNNER_EXTRA="--exclude rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547 export RUN_FUNCTIONAL_TESTS=true export GOAL="install" -export BITCOIN_CONFIG="--enable-reduce-exports" +export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON" diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh index bf80d5d435..15b9e407b6 100755 --- a/ci/test/00_setup_env_win64.sh +++ b/ci/test/00_setup_env_win64.sh @@ -16,4 +16,5 @@ export GOAL="deploy" # Prior to 11.0.0, the mingw-w64 headers were missing noreturn attributes, causing warnings when # cross-compiling for Windows. https://sourceforge.net/p/mingw-w64/bugs/306/ # https://github.com/mingw-w64/mingw-w64/commit/1690994f515910a31b9fb7c7bd3a52d4ba987abe -export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests CXXFLAGS='-Wno-return-type -Wno-error=maybe-uninitialized -Wno-error=array-bounds'" +export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_GUI_TESTS=OFF \ +-DCMAKE_CXX_FLAGS='-Wno-error=return-type -Wno-error=maybe-uninitialized -Wno-error=array-bounds'" diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh index f16321ba55..72e3985a51 100755 --- a/ci/test/01_base_install.sh +++ b/ci/test/01_base_install.sh @@ -15,6 +15,8 @@ if [ "$(git config --global ${CFG_DONE})" == "true" ]; then exit 0 fi +MAKEJOBS="-j$( nproc )" # Use nproc, because MAKEJOBS is the default in docker image builds. + if [ -n "$DPKG_ADD_ARCH" ]; then dpkg --add-architecture "$DPKG_ADD_ARCH" fi @@ -36,7 +38,7 @@ if [ -n "$PIP_PACKAGES" ]; then fi if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then - ${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-18.1.3" /msan/llvm-project + ${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-19.1.0" /msan/llvm-project cmake -G Ninja -B /msan/clang_build/ \ -DLLVM_ENABLE_PROJECTS="clang" \ @@ -45,7 +47,7 @@ if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then -DLLVM_ENABLE_RUNTIMES="compiler-rt;libcxx;libcxxabi;libunwind" \ -S /msan/llvm-project/llvm - ninja -C /msan/clang_build/ "-j$( nproc )" # Use nproc, because MAKEJOBS is the default in docker image builds + ninja -C /msan/clang_build/ "$MAKEJOBS" ninja -C /msan/clang_build/ install-runtimes update-alternatives --install /usr/bin/clang++ clang++ /msan/clang_build/bin/clang++ 100 @@ -64,13 +66,17 @@ if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then -DLIBCXX_HARDENING_MODE=debug \ -S /msan/llvm-project/runtimes - ninja -C /msan/cxx_build/ "-j$( nproc )" # Use nproc, because MAKEJOBS is the default in docker image builds + ninja -C /msan/cxx_build/ "$MAKEJOBS" + + # Clear no longer needed source folder + du -sh /msan/llvm-project + rm -rf /msan/llvm-project fi if [[ "${RUN_TIDY}" == "true" ]]; then ${CI_RETRY_EXE} git clone --depth=1 https://github.com/include-what-you-use/include-what-you-use -b clang_"${TIDY_LLVM_V}" /include-what-you-use cmake -B /iwyu-build/ -G 'Unix Makefiles' -DCMAKE_PREFIX_PATH=/usr/lib/llvm-"${TIDY_LLVM_V}" -S /include-what-you-use - make -C /iwyu-build/ install "-j$( nproc )" # Use nproc, because MAKEJOBS is the default in docker image builds + make -C /iwyu-build/ install "$MAKEJOBS" fi mkdir -p "${DEPENDS_DIR}/SDKs" "${DEPENDS_DIR}/sdk-sources" diff --git a/ci/test/02_run_container.sh b/ci/test/02_run_container.sh index 86bb856d17..9069fba156 100755 --- a/ci/test/02_run_container.sh +++ b/ci/test/02_run_container.sh @@ -15,19 +15,59 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then python3 -c 'import os; [print(f"{key}={value}") for key, value in os.environ.items() if "\n" not in value and "HOME" != key and "PATH" != key and "USER" != key]' | tee "/tmp/env-$USER-$CONTAINER_NAME" # System-dependent env vars must be kept as is. So read them from the container. docker run --rm "${CI_IMAGE_NAME_TAG}" bash -c "env | grep --extended-regexp '^(HOME|PATH|USER)='" | tee --append "/tmp/env-$USER-$CONTAINER_NAME" + + # Env vars during the build can not be changed. For example, a modified + # $MAKEJOBS is ignored in the build process. Use --cpuset-cpus as an + # approximation to respect $MAKEJOBS somewhat, if cpuset is available. + MAYBE_CPUSET="" + if [ "$HAVE_CGROUP_CPUSET" ]; then + MAYBE_CPUSET="--cpuset-cpus=$( python3 -c "import random;P=$( nproc );M=min(P,int('$MAKEJOBS'.lstrip('-j')));print(','.join(map(str,sorted(random.sample(range(P),M)))))" )" + fi echo "Creating $CI_IMAGE_NAME_TAG container to run in" + + # shellcheck disable=SC2086 DOCKER_BUILDKIT=1 docker build \ --file "${BASE_READ_ONLY_DIR}/ci/test_imagefile" \ --build-arg "CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG}" \ --build-arg "FILE_ENV=${FILE_ENV}" \ + $MAYBE_CPUSET \ --label="${CI_IMAGE_LABEL}" \ --tag="${CONTAINER_NAME}" \ "${BASE_READ_ONLY_DIR}" + docker volume create "${CONTAINER_NAME}_ccache" || true docker volume create "${CONTAINER_NAME}_depends" || true docker volume create "${CONTAINER_NAME}_depends_sources" || true docker volume create "${CONTAINER_NAME}_previous_releases" || true + CI_CCACHE_MOUNT="type=volume,src=${CONTAINER_NAME}_ccache,dst=$CCACHE_DIR" + CI_DEPENDS_MOUNT="type=volume,src=${CONTAINER_NAME}_depends,dst=$DEPENDS_DIR/built" + CI_DEPENDS_SOURCES_MOUNT="type=volume,src=${CONTAINER_NAME}_depends_sources,dst=$DEPENDS_DIR/sources" + CI_PREVIOUS_RELEASES_MOUNT="type=volume,src=${CONTAINER_NAME}_previous_releases,dst=$PREVIOUS_RELEASES_DIR" + + if [ "$DANGER_CI_ON_HOST_CACHE_FOLDERS" ]; then + # ensure the directories exist + mkdir -p "${CCACHE_DIR}" + mkdir -p "${DEPENDS_DIR}/built" + mkdir -p "${DEPENDS_DIR}/sources" + mkdir -p "${PREVIOUS_RELEASES_DIR}" + + CI_CCACHE_MOUNT="type=bind,src=${CCACHE_DIR},dst=$CCACHE_DIR" + CI_DEPENDS_MOUNT="type=bind,src=${DEPENDS_DIR}/built,dst=$DEPENDS_DIR/built" + CI_DEPENDS_SOURCES_MOUNT="type=bind,src=${DEPENDS_DIR}/sources,dst=$DEPENDS_DIR/sources" + CI_PREVIOUS_RELEASES_MOUNT="type=bind,src=${PREVIOUS_RELEASES_DIR},dst=$PREVIOUS_RELEASES_DIR" + fi + + if [ "$DANGER_CI_ON_HOST_CCACHE_FOLDER" ]; then + if [ ! -d "${CCACHE_DIR}" ]; then + echo "Error: Directory '${CCACHE_DIR}' must be created in advance." + exit 1 + fi + CI_CCACHE_MOUNT="type=bind,src=${CCACHE_DIR},dst=${CCACHE_DIR}" + fi + + docker network create --ipv6 --subnet 1111:1111::/112 ci-ip6net || true + if [ -n "${RESTART_CI_DOCKER_BEFORE_RUN}" ] ; then echo "Restart docker before run to stop and clear all containers started with --rm" podman container rm --force --all # Similar to "systemctl restart docker" @@ -48,12 +88,13 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then # shellcheck disable=SC2086 CI_CONTAINER_ID=$(docker run --cap-add LINUX_IMMUTABLE $CI_CONTAINER_CAP --rm --interactive --detach --tty \ --mount "type=bind,src=$BASE_READ_ONLY_DIR,dst=$BASE_READ_ONLY_DIR,readonly" \ - --mount "type=volume,src=${CONTAINER_NAME}_ccache,dst=$CCACHE_DIR" \ - --mount "type=volume,src=${CONTAINER_NAME}_depends,dst=$DEPENDS_DIR/built" \ - --mount "type=volume,src=${CONTAINER_NAME}_depends_sources,dst=$DEPENDS_DIR/sources" \ - --mount "type=volume,src=${CONTAINER_NAME}_previous_releases,dst=$PREVIOUS_RELEASES_DIR" \ + --mount "${CI_CCACHE_MOUNT}" \ + --mount "${CI_DEPENDS_MOUNT}" \ + --mount "${CI_DEPENDS_SOURCES_MOUNT}" \ + --mount "${CI_PREVIOUS_RELEASES_MOUNT}" \ --env-file /tmp/env-$USER-$CONTAINER_NAME \ --name "$CONTAINER_NAME" \ + --network ci-ip6net \ "$CONTAINER_NAME") export CI_CONTAINER_ID export CI_EXEC_CMD_PREFIX="docker exec ${CI_CONTAINER_ID}" diff --git a/ci/test/03_test_script.sh b/ci/test/03_test_script.sh index 71d9ad7f72..6eab4f7467 100755 --- a/ci/test/03_test_script.sh +++ b/ci/test/03_test_script.sh @@ -8,17 +8,16 @@ export LC_ALL=C.UTF-8 set -ex -export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1" +export ASAN_OPTIONS="detect_leaks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1" export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan" export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:halt_on_error=1" export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1" +echo "Number of available processing units: $(nproc)" if [ "$CI_OS_NAME" == "macos" ]; then top -l 1 -s 0 | awk ' /PhysMem/ {print}' - echo "Number of CPUs: $(sysctl -n hw.logicalcpu)" else free -m -h - echo "Number of CPUs (nproc): $(nproc)" echo "System info: $(uname --kernel-name --kernel-release)" lscpu fi @@ -30,6 +29,10 @@ df -h # Tests that run natively guess the host export HOST=${HOST:-$("$BASE_ROOT_DIR/depends/config.guess")} +echo "=== BEGIN env ===" +env +echo "=== END env ===" + ( # compact->outputs[i].file_size is uninitialized memory, so reading it is UB. # The statistic bytes_written is only used for logging, which is disabled in @@ -54,7 +57,7 @@ EOF ) if [ "$RUN_FUZZ_TESTS" = "true" ]; then - export DIR_FUZZ_IN=${DIR_QA_ASSETS}/fuzz_seed_corpus/ + export DIR_FUZZ_IN=${DIR_QA_ASSETS}/fuzz_corpora/ if [ ! -d "$DIR_FUZZ_IN" ]; then ${CI_RETRY_EXE} git clone --depth=1 https://github.com/bitcoin-core/qa-assets "${DIR_QA_ASSETS}" fi @@ -99,51 +102,37 @@ if [ "$DOWNLOAD_PREVIOUS_RELEASES" = "true" ]; then test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" fi -BITCOIN_CONFIG_ALL="--disable-dependency-tracking" +BITCOIN_CONFIG_ALL="-DBUILD_BENCH=ON -DBUILD_FUZZ_BINARY=ON" if [ -z "$NO_DEPENDS" ]; then - BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} CONFIG_SITE=$DEPENDS_DIR/$HOST/share/config.site" + BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} -DCMAKE_TOOLCHAIN_FILE=$DEPENDS_DIR/$HOST/toolchain.cmake" fi if [ -z "$NO_WERROR" ]; then - BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-werror" + BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} -DWERROR=ON" fi ccache --zero-stats PRINT_CCACHE_STATISTICS="ccache --version | head -n 1 && ccache --show-stats" -BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --prefix=$BASE_OUTDIR" - -if [ -n "$CONFIG_SHELL" ]; then - "$CONFIG_SHELL" -c "./autogen.sh" -else - ./autogen.sh -fi - +# Folder where the build is done. +BASE_BUILD_DIR=${BASE_BUILD_DIR:-$BASE_SCRATCH_DIR/build-$HOST} mkdir -p "${BASE_BUILD_DIR}" cd "${BASE_BUILD_DIR}" -bash -c "${BASE_ROOT_DIR}/configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || ( (cat config.log) && false) - -make distdir VERSION="$HOST" - -cd "${BASE_BUILD_DIR}/bitcoin-$HOST" - -bash -c "./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || ( (cat config.log) && false) +BITCOIN_CONFIG_ALL="$BITCOIN_CONFIG_ALL -DENABLE_EXTERNAL_SIGNER=ON -DCMAKE_INSTALL_PREFIX=$BASE_OUTDIR" if [[ "${RUN_TIDY}" == "true" ]]; then - MAYBE_BEAR="bear --config src/.bear-tidy-config" - MAYBE_TOKEN="--" + BITCOIN_CONFIG_ALL="$BITCOIN_CONFIG_ALL -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" fi -bash -c "${MAYBE_BEAR} ${MAYBE_TOKEN} make $MAKEJOBS $GOAL" || ( echo "Build failure. Verbose build follows." && make "$GOAL" V=1 ; false ) +bash -c "cmake -S $BASE_ROOT_DIR $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( (cat $(cmake -P "${BASE_ROOT_DIR}/ci/test/GetCMakeLogFiles.cmake")) && false)" + +bash -c "cmake --build . $MAKEJOBS --target all $GOAL" || ( echo "Build failure. Verbose build follows." && cmake --build . --target all "$GOAL" --verbose ; false ) bash -c "${PRINT_CCACHE_STATISTICS}" du -sh "${DEPENDS_DIR}"/*/ du -sh "${PREVIOUS_RELEASES_DIR}" if [[ $HOST = *-mingw32 ]]; then - # Generate all binaries, so that they can be wrapped - make "$MAKEJOBS" -C src/secp256k1 VERBOSE=1 - make "$MAKEJOBS" -C src minisketch/test.exe VERBOSE=1 "${BASE_ROOT_DIR}/ci/test/wrap-wine.sh" fi @@ -151,8 +140,12 @@ if [ -n "$USE_VALGRIND" ]; then "${BASE_ROOT_DIR}/ci/test/wrap-valgrind.sh" fi +if [ "$RUN_CHECK_DEPS" = "true" ]; then + "${BASE_ROOT_DIR}/contrib/devtools/check-deps.sh" . +fi + if [ "$RUN_UNIT_TESTS" = "true" ]; then - DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" make "${MAKEJOBS}" check VERBOSE=1 + DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" CTEST_OUTPUT_ON_FAILURE=ON ctest "${MAKEJOBS}" --timeout $(( TEST_RUNNER_TIMEOUT_FACTOR * 60 )) fi if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then @@ -160,8 +153,9 @@ if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then fi if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then - # shellcheck disable=SC2086 - LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/functional/test_runner.py --ci "${MAKEJOBS}" --tmpdirprefix "${BASE_SCRATCH_DIR}"/test_runner/ --ansi --combinedlogslen=99999999 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" ${TEST_RUNNER_EXTRA} --quiet --failfast + # parses TEST_RUNNER_EXTRA as an array which allows for multiple arguments such as TEST_RUNNER_EXTRA='--exclude "rpc_bind.py --ipv6"' + eval "TEST_RUNNER_EXTRA=($TEST_RUNNER_EXTRA)" + LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/functional/test_runner.py --ci "${MAKEJOBS}" --tmpdirprefix "${BASE_SCRATCH_DIR}"/test_runner/ --ansi --combinedlogslen=99999999 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA[@]}" --quiet --failfast fi if [ "${RUN_TIDY}" = "true" ]; then @@ -170,22 +164,20 @@ if [ "${RUN_TIDY}" = "true" ]; then cmake --build /tidy-build --target bitcoin-tidy-tests "$MAKEJOBS" set -eo pipefail - cd "${BASE_BUILD_DIR}/bitcoin-$HOST/src/" + cd "${BASE_BUILD_DIR}/src/" if ! ( run-clang-tidy-"${TIDY_LLVM_V}" -quiet -load="/tidy-build/libbitcoin-tidy.so" "${MAKEJOBS}" | tee tmp.tidy-out.txt ); then grep -C5 "error: " tmp.tidy-out.txt echo "^^^ ⚠️ Failure generated from clang-tidy" false fi - # Filter out files by regex here, because regex may not be - # accepted in src/.bear-tidy-config # Filter out: # * qt qrc and moc generated files - jq 'map(select(.file | test("src/qt/qrc_.*\\.cpp$|/moc_.*\\.cpp$") | not))' ../compile_commands.json > tmp.json - mv tmp.json ../compile_commands.json - cd "${BASE_BUILD_DIR}/bitcoin-$HOST/" + jq 'map(select(.file | test("src/qt/qrc_.*\\.cpp$|/moc_.*\\.cpp$") | not))' "${BASE_BUILD_DIR}/compile_commands.json" > tmp.json + mv tmp.json "${BASE_BUILD_DIR}/compile_commands.json" + cd "${BASE_ROOT_DIR}" python3 "/include-what-you-use/iwyu_tool.py" \ - -p . "${MAKEJOBS}" \ - -- -Xiwyu --cxx17ns -Xiwyu --mapping_file="${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp" \ + -p "${BASE_BUILD_DIR}" "${MAKEJOBS}" \ + -- -Xiwyu --cxx17ns -Xiwyu --mapping_file="${BASE_ROOT_DIR}/contrib/devtools/iwyu/bitcoin.core.imp" \ -Xiwyu --max_line_length=160 \ 2>&1 | tee /tmp/iwyu_ci.out cd "${BASE_ROOT_DIR}/src" diff --git a/ci/test/GetCMakeLogFiles.cmake b/ci/test/GetCMakeLogFiles.cmake new file mode 100644 index 0000000000..80f71dcf63 --- /dev/null +++ b/ci/test/GetCMakeLogFiles.cmake @@ -0,0 +1,11 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.26) + set(log_files "CMakeFiles/CMakeConfigureLog.yaml") +else() + set(log_files "CMakeFiles/CMakeOutput.log CMakeFiles/CMakeError.log") +endif() + +execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${log_files}) diff --git a/ci/test/wrap-wine.sh b/ci/test/wrap-wine.sh index 90e53887bc..a0d32a93a3 100755 --- a/ci/test/wrap-wine.sh +++ b/ci/test/wrap-wine.sh @@ -6,7 +6,7 @@ export LC_ALL=C.UTF-8 -for b_name in {"${BASE_OUTDIR}/bin"/*,src/secp256k1/*tests,src/minisketch/test{,-verify},src/univalue/{test_json,unitester,object}}.exe; do +for b_name in {"${BASE_OUTDIR}/bin"/*,src/univalue/{test_json,unitester,object}}.exe; do # shellcheck disable=SC2044 for b in $(find "${BASE_ROOT_DIR}" -executable -type f -name "$(basename "$b_name")"); do if (file "$b" | grep "Windows"); then diff --git a/cmake/bitcoin-build-config.h.in b/cmake/bitcoin-build-config.h.in new file mode 100644 index 0000000000..094eb8040a --- /dev/null +++ b/cmake/bitcoin-build-config.h.in @@ -0,0 +1,153 @@ +// Copyright (c) 2023-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/license/mit/. + +#ifndef BITCOIN_CONFIG_H +#define BITCOIN_CONFIG_H + +/* Version Build */ +#define CLIENT_VERSION_BUILD @CLIENT_VERSION_BUILD@ + +/* Version is release */ +#define CLIENT_VERSION_IS_RELEASE @CLIENT_VERSION_IS_RELEASE@ + +/* Major version */ +#define CLIENT_VERSION_MAJOR @CLIENT_VERSION_MAJOR@ + +/* Minor version */ +#define CLIENT_VERSION_MINOR @CLIENT_VERSION_MINOR@ + +/* Copyright holder(s) before %s replacement */ +#define COPYRIGHT_HOLDERS "@COPYRIGHT_HOLDERS@" + +/* Copyright holder(s) */ +#define COPYRIGHT_HOLDERS_FINAL "@COPYRIGHT_HOLDERS_FINAL@" + +/* Replacement for %s in copyright holders string */ +#define COPYRIGHT_HOLDERS_SUBSTITUTION "@PACKAGE_NAME@" + +/* Copyright year */ +#define COPYRIGHT_YEAR @COPYRIGHT_YEAR@ + +/* Define this symbol to build code that uses ARMv8 SHA-NI intrinsics */ +#cmakedefine ENABLE_ARM_SHANI 1 + +/* Define this symbol to build code that uses AVX2 intrinsics */ +#cmakedefine ENABLE_AVX2 1 + +/* Define if external signer support is enabled */ +#cmakedefine ENABLE_EXTERNAL_SIGNER 1 + +/* Define this symbol to build code that uses SSE4.1 intrinsics */ +#cmakedefine ENABLE_SSE41 1 + +/* Define to 1 to enable tracepoints for Userspace, Statically Defined Tracing + */ +#cmakedefine ENABLE_TRACING 1 + +/* Define to 1 to enable wallet functions. */ +#cmakedefine ENABLE_WALLET 1 + +/* Define this symbol to build code that uses x86 SHA-NI intrinsics */ +#cmakedefine ENABLE_X86_SHANI 1 + +/* Define to 1 if you have the declaration of `fork', and to 0 if you don't. + */ +#cmakedefine01 HAVE_DECL_FORK + +/* Define to 1 if you have the declaration of `freeifaddrs', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_FREEIFADDRS + +/* Define to 1 if you have the declaration of `getifaddrs', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_GETIFADDRS + +/* Define to 1 if you have the declaration of `pipe2', and to 0 if you don't. + */ +#cmakedefine01 HAVE_DECL_PIPE2 + +/* Define to 1 if you have the declaration of `setsid', and to 0 if you don't. + */ +#cmakedefine01 HAVE_DECL_SETSID + +/* Define this symbol if evhttp_connection_get_peer expects const char** */ +#cmakedefine HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR 1 + +/* Define to 1 if fdatasync is available. */ +#cmakedefine HAVE_FDATASYNC 1 + +/* Define this symbol if the BSD getentropy system call is available with + sys/random.h */ +#cmakedefine HAVE_GETENTROPY_RAND 1 + +/* Define this symbol if the Linux getrandom function call is available */ +#cmakedefine HAVE_GETRANDOM 1 + +/* Define this symbol if you have malloc_info */ +#cmakedefine HAVE_MALLOC_INFO 1 + +/* Define this symbol if you have mallopt with M_ARENA_MAX */ +#cmakedefine HAVE_MALLOPT_ARENA_MAX 1 + +/* Define to 1 if O_CLOEXEC flag is available. */ +#cmakedefine01 HAVE_O_CLOEXEC + +/* Define this symbol if you have posix_fallocate */ +#cmakedefine HAVE_POSIX_FALLOCATE 1 + +/* Define this symbol if platform supports unix domain sockets */ +#cmakedefine HAVE_SOCKADDR_UN 1 + +/* Define this symbol to build code that uses getauxval */ +#cmakedefine HAVE_STRONG_GETAUXVAL 1 + +/* Define this symbol if the BSD sysctl() is available */ +#cmakedefine HAVE_SYSCTL 1 + +/* Define this symbol if the BSD sysctl(KERN_ARND) is available */ +#cmakedefine HAVE_SYSCTL_ARND 1 + +/* Define to 1 if std::system or ::wsystem is available. */ +#cmakedefine HAVE_SYSTEM 1 + +/* Define to 1 if you have the <sys/prctl.h> header file. */ +#cmakedefine HAVE_SYS_PRCTL_H 1 + +/* Define to 1 if you have the <sys/resources.h> header file. */ +#cmakedefine HAVE_SYS_RESOURCES_H 1 + +/* Define to 1 if you have the <sys/vmmeter.h> header file. */ +#cmakedefine HAVE_SYS_VMMETER_H 1 + +/* Define to 1 if you have the <vm/vm_param.h> header file. */ +#cmakedefine HAVE_VM_VM_PARAM_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "@PROJECT_HOMEPAGE_URL@" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "@PACKAGE_VERSION@" + +/* Define to 1 if strerror_r returns char *. */ +#cmakedefine STRERROR_R_CHAR_P 1 + +/* Define if BDB support should be compiled in */ +#cmakedefine USE_BDB 1 + +/* Define if dbus support should be compiled in */ +#cmakedefine USE_DBUS 1 + +/* Define if QR support should be compiled in */ +#cmakedefine USE_QRCODE 1 + +/* Define if sqlite support should be compiled in */ +#cmakedefine USE_SQLITE 1 + +#endif //BITCOIN_CONFIG_H diff --git a/cmake/ccache.cmake b/cmake/ccache.cmake new file mode 100644 index 0000000000..099aa66411 --- /dev/null +++ b/cmake/ccache.cmake @@ -0,0 +1,36 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +if(NOT MSVC) + find_program(CCACHE_EXECUTABLE ccache) + if(CCACHE_EXECUTABLE) + execute_process( + COMMAND readlink -f ${CMAKE_CXX_COMPILER} + OUTPUT_VARIABLE compiler_resolved_link + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(CCACHE_EXECUTABLE STREQUAL compiler_resolved_link AND NOT WITH_CCACHE) + list(APPEND configure_warnings + "Disabling ccache was attempted using -DWITH_CCACHE=${WITH_CCACHE}, but ccache masquerades as the compiler." + ) + set(WITH_CCACHE ON) + elseif(WITH_CCACHE) + list(APPEND CMAKE_C_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE}) + list(APPEND CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE}) + endif() + else() + set(WITH_CCACHE OFF) + endif() + if(WITH_CCACHE) + try_append_cxx_flags("-fdebug-prefix-map=A=B" TARGET core_interface SKIP_LINK + IF_CHECK_PASSED "-fdebug-prefix-map=${PROJECT_SOURCE_DIR}=." + ) + try_append_cxx_flags("-fmacro-prefix-map=A=B" TARGET core_interface SKIP_LINK + IF_CHECK_PASSED "-fmacro-prefix-map=${PROJECT_SOURCE_DIR}=." + ) + endif() +endif() + +mark_as_advanced(CCACHE_EXECUTABLE) diff --git a/cmake/cov_tool_wrapper.sh.in b/cmake/cov_tool_wrapper.sh.in new file mode 100644 index 0000000000..f6b7ff3419 --- /dev/null +++ b/cmake/cov_tool_wrapper.sh.in @@ -0,0 +1,5 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +exec @COV_TOOL@ "$@" diff --git a/cmake/crc32c.cmake b/cmake/crc32c.cmake new file mode 100644 index 0000000000..16fde7f95d --- /dev/null +++ b/cmake/crc32c.cmake @@ -0,0 +1,123 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# This file is part of the transition from Autotools to CMake. Once CMake +# support has been merged we should switch to using the upstream CMake +# buildsystem. + +include(CheckCXXSourceCompiles) + +# Check for __builtin_prefetch support in the compiler. +check_cxx_source_compiles(" + int main() { + char data = 0; + const char* address = &data; + __builtin_prefetch(address, 0, 0); + return 0; + } + " HAVE_BUILTIN_PREFETCH +) + +# Check for _mm_prefetch support in the compiler. +check_cxx_source_compiles(" + #if defined(_MSC_VER) + #include <intrin.h> + #else + #include <xmmintrin.h> + #endif + + int main() { + char data = 0; + const char* address = &data; + _mm_prefetch(address, _MM_HINT_NTA); + return 0; + } + " HAVE_MM_PREFETCH +) + +# Check for SSE4.2 support in the compiler. +if(MSVC) + set(SSE42_CXXFLAGS /arch:AVX) +else() + set(SSE42_CXXFLAGS -msse4.2) +endif() +check_cxx_source_compiles_with_flags("${SSE42_CXXFLAGS}" " + #include <cstdint> + #if defined(_MSC_VER) + #include <intrin.h> + #elif defined(__GNUC__) && defined(__SSE4_2__) + #include <nmmintrin.h> + #endif + + int main() { + uint64_t l = 0; + l = _mm_crc32_u8(l, 0); + l = _mm_crc32_u32(l, 0); + l = _mm_crc32_u64(l, 0); + return l; + } + " HAVE_SSE42 +) + +# Check for ARMv8 w/ CRC and CRYPTO extensions support in the compiler. +set(ARM64_CRC_CXXFLAGS -march=armv8-a+crc+crypto) +check_cxx_source_compiles_with_flags("${ARM64_CRC_CXXFLAGS}" " + #include <arm_acle.h> + #include <arm_neon.h> + + int main() { + #ifdef __aarch64__ + __crc32cb(0, 0); __crc32ch(0, 0); __crc32cw(0, 0); __crc32cd(0, 0); + vmull_p64(0, 0); + #else + #error crc32c library does not support hardware acceleration on 32-bit ARM + #endif + return 0; + } + " HAVE_ARM64_CRC32C +) + +add_library(crc32c_common INTERFACE) +target_compile_definitions(crc32c_common INTERFACE + HAVE_BUILTIN_PREFETCH=$<BOOL:${HAVE_BUILTIN_PREFETCH}> + HAVE_MM_PREFETCH=$<BOOL:${HAVE_MM_PREFETCH}> + HAVE_STRONG_GETAUXVAL=$<BOOL:${HAVE_STRONG_GETAUXVAL}> + BYTE_ORDER_BIG_ENDIAN=$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},BIG_ENDIAN> + HAVE_SSE42=$<BOOL:${HAVE_SSE42}> + HAVE_ARM64_CRC32C=$<BOOL:${HAVE_ARM64_CRC32C}> +) +target_link_libraries(crc32c_common INTERFACE + core_interface +) + +add_library(crc32c STATIC EXCLUDE_FROM_ALL + ${PROJECT_SOURCE_DIR}/src/crc32c/src/crc32c.cc + ${PROJECT_SOURCE_DIR}/src/crc32c/src/crc32c_portable.cc +) +target_include_directories(crc32c + PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/crc32c/include> +) +target_link_libraries(crc32c PRIVATE crc32c_common) +set_target_properties(crc32c PROPERTIES EXPORT_COMPILE_COMMANDS OFF) + +if(HAVE_SSE42) + add_library(crc32c_sse42 STATIC EXCLUDE_FROM_ALL + ${PROJECT_SOURCE_DIR}/src/crc32c/src/crc32c_sse42.cc + ) + target_compile_options(crc32c_sse42 PRIVATE ${SSE42_CXXFLAGS}) + target_link_libraries(crc32c_sse42 PRIVATE crc32c_common) + set_target_properties(crc32c_sse42 PROPERTIES EXPORT_COMPILE_COMMANDS OFF) + target_link_libraries(crc32c PRIVATE crc32c_sse42) +endif() + +if(HAVE_ARM64_CRC32C) + add_library(crc32c_arm64 STATIC EXCLUDE_FROM_ALL + ${PROJECT_SOURCE_DIR}/src/crc32c/src/crc32c_arm64.cc + ) + target_compile_options(crc32c_arm64 PRIVATE ${ARM64_CRC_CXXFLAGS}) + target_link_libraries(crc32c_arm64 PRIVATE crc32c_common) + set_target_properties(crc32c_arm64 PROPERTIES EXPORT_COMPILE_COMMANDS OFF) + target_link_libraries(crc32c PRIVATE crc32c_arm64) +endif() diff --git a/cmake/introspection.cmake b/cmake/introspection.cmake new file mode 100644 index 0000000000..29c93869a7 --- /dev/null +++ b/cmake/introspection.cmake @@ -0,0 +1,227 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include(CheckCXXSourceCompiles) +include(CheckCXXSymbolExists) +include(CheckIncludeFileCXX) + +# The following HAVE_{HEADER}_H variables go to the bitcoin-build-config.h header. +check_include_file_cxx(sys/prctl.h HAVE_SYS_PRCTL_H) +check_include_file_cxx(sys/resources.h HAVE_SYS_RESOURCES_H) +check_include_file_cxx(sys/vmmeter.h HAVE_SYS_VMMETER_H) +check_include_file_cxx(vm/vm_param.h HAVE_VM_VM_PARAM_H) + +check_cxx_symbol_exists(O_CLOEXEC "fcntl.h" HAVE_O_CLOEXEC) +check_cxx_symbol_exists(fdatasync "unistd.h" HAVE_FDATASYNC) +check_cxx_symbol_exists(fork "unistd.h" HAVE_DECL_FORK) +check_cxx_symbol_exists(pipe2 "unistd.h" HAVE_DECL_PIPE2) +check_cxx_symbol_exists(setsid "unistd.h" HAVE_DECL_SETSID) + +check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H) +check_include_file_cxx(ifaddrs.h HAVE_IFADDRS_H) +if(HAVE_SYS_TYPES_H AND HAVE_IFADDRS_H) + include(TestAppendRequiredLibraries) + test_append_socket_library(core_interface) +endif() + +include(TestAppendRequiredLibraries) +test_append_atomic_library(core_interface) + +check_cxx_symbol_exists(std::system "cstdlib" HAVE_STD_SYSTEM) +check_cxx_symbol_exists(::_wsystem "stdlib.h" HAVE__WSYSTEM) +if(HAVE_STD_SYSTEM OR HAVE__WSYSTEM) + set(HAVE_SYSTEM 1) +endif() + +check_cxx_source_compiles(" + #include <string.h> + + int main() + { + char buf[100]; + char* p{strerror_r(0, buf, sizeof buf)}; + (void)p; + } + " STRERROR_R_CHAR_P +) + +# Check for malloc_info (for memory statistics information in getmemoryinfo). +check_cxx_symbol_exists(malloc_info "malloc.h" HAVE_MALLOC_INFO) + +# Check for mallopt(M_ARENA_MAX) (to set glibc arenas). +check_cxx_source_compiles(" + #include <malloc.h> + + int main() + { + mallopt(M_ARENA_MAX, 1); + } + " HAVE_MALLOPT_ARENA_MAX +) + +# Check for posix_fallocate(). +check_cxx_source_compiles(" + // same as in src/util/fs_helpers.cpp + #ifdef __linux__ + #ifdef _POSIX_C_SOURCE + #undef _POSIX_C_SOURCE + #endif + #define _POSIX_C_SOURCE 200112L + #endif // __linux__ + #include <fcntl.h> + + int main() + { + return posix_fallocate(0, 0, 0); + } + " HAVE_POSIX_FALLOCATE +) + +# Check for strong getauxval() support in the system headers. +check_cxx_source_compiles(" + #include <sys/auxv.h> + + int main() + { + getauxval(AT_HWCAP); + } + " HAVE_STRONG_GETAUXVAL +) + +# Check for UNIX sockets. +check_cxx_source_compiles(" + #include <sys/socket.h> + #include <sys/un.h> + + int main() + { + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + } + " HAVE_SOCKADDR_UN +) + +# Check for different ways of gathering OS randomness: +# - Linux getrandom() +check_cxx_source_compiles(" + #include <sys/random.h> + + int main() + { + getrandom(nullptr, 32, 0); + } + " HAVE_GETRANDOM +) + +# - BSD getentropy() +check_cxx_source_compiles(" + #include <sys/random.h> + + int main() + { + getentropy(nullptr, 32); + } + " HAVE_GETENTROPY_RAND +) + + +# - BSD sysctl() +check_cxx_source_compiles(" + #include <sys/types.h> + #include <sys/sysctl.h> + + #ifdef __linux__ + #error Don't use sysctl on Linux, it's deprecated even when it works + #endif + + int main() + { + sysctl(nullptr, 2, nullptr, nullptr, nullptr, 0); + } + " HAVE_SYSCTL +) + +# - BSD sysctl(KERN_ARND) +check_cxx_source_compiles(" + #include <sys/types.h> + #include <sys/sysctl.h> + + #ifdef __linux__ + #error Don't use sysctl on Linux, it's deprecated even when it works + #endif + + int main() + { + static int name[2] = {CTL_KERN, KERN_ARND}; + sysctl(name, 2, nullptr, nullptr, nullptr, 0); + } + " HAVE_SYSCTL_ARND +) + +if(NOT MSVC) + include(CheckSourceCompilesAndLinks) + + # Check for SSE4.1 intrinsics. + set(SSE41_CXXFLAGS -msse4.1) + check_cxx_source_compiles_with_flags("${SSE41_CXXFLAGS}" " + #include <immintrin.h> + + int main() + { + __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); + } + " HAVE_SSE41 + ) + set(ENABLE_SSE41 ${HAVE_SSE41}) + + # Check for AVX2 intrinsics. + set(AVX2_CXXFLAGS -mavx -mavx2) + check_cxx_source_compiles_with_flags("${AVX2_CXXFLAGS}" " + #include <immintrin.h> + + int main() + { + __m256i l = _mm256_set1_epi32(0); + return _mm256_extract_epi32(l, 7); + } + " HAVE_AVX2 + ) + set(ENABLE_AVX2 ${HAVE_AVX2}) + + # Check for x86 SHA-NI intrinsics. + set(X86_SHANI_CXXFLAGS -msse4 -msha) + check_cxx_source_compiles_with_flags("${X86_SHANI_CXXFLAGS}" " + #include <immintrin.h> + + int main() + { + __m128i i = _mm_set1_epi32(0); + __m128i j = _mm_set1_epi32(1); + __m128i k = _mm_set1_epi32(2); + return _mm_extract_epi32(_mm_sha256rnds2_epu32(i, j, k), 0); + } + " HAVE_X86_SHANI + ) + set(ENABLE_X86_SHANI ${HAVE_X86_SHANI}) + + # Check for ARMv8 SHA-NI intrinsics. + set(ARM_SHANI_CXXFLAGS -march=armv8-a+crypto) + check_cxx_source_compiles_with_flags("${ARM_SHANI_CXXFLAGS}" " + #include <arm_neon.h> + + int main() + { + uint32x4_t a, b, c; + vsha256h2q_u32(a, b, c); + vsha256hq_u32(a, b, c); + vsha256su0q_u32(a, b); + vsha256su1q_u32(a, b, c); + } + " HAVE_ARM_SHANI + ) + set(ENABLE_ARM_SHANI ${HAVE_ARM_SHANI}) +endif() diff --git a/cmake/leveldb.cmake b/cmake/leveldb.cmake new file mode 100644 index 0000000000..823a5d8e3d --- /dev/null +++ b/cmake/leveldb.cmake @@ -0,0 +1,105 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# This file is part of the transition from Autotools to CMake. Once CMake +# support has been merged we should switch to using the upstream CMake +# buildsystem. + +include(CheckCXXSymbolExists) +check_cxx_symbol_exists(F_FULLFSYNC "fcntl.h" HAVE_FULLFSYNC) + +add_library(leveldb STATIC EXCLUDE_FROM_ALL + ${PROJECT_SOURCE_DIR}/src/leveldb/db/builder.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/c.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/db_impl.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/db_iter.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/dbformat.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/dumpfile.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/filename.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/log_reader.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/log_writer.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/memtable.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/repair.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/table_cache.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/version_edit.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/version_set.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/db/write_batch.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/block.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/block_builder.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/filter_block.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/format.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/iterator.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/merger.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/table.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/table_builder.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/table/two_level_iterator.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/arena.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/bloom.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/cache.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/coding.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/comparator.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/crc32c.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/env.cc + $<$<NOT:$<BOOL:${WIN32}>>:${PROJECT_SOURCE_DIR}/src/leveldb/util/env_posix.cc> + $<$<BOOL:${WIN32}>:${PROJECT_SOURCE_DIR}/src/leveldb/util/env_windows.cc> + ${PROJECT_SOURCE_DIR}/src/leveldb/util/filter_policy.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/hash.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/histogram.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/logging.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/options.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/util/status.cc + ${PROJECT_SOURCE_DIR}/src/leveldb/helpers/memenv/memenv.cc +) + +target_compile_definitions(leveldb + PRIVATE + HAVE_SNAPPY=0 + HAVE_CRC32C=1 + HAVE_FDATASYNC=$<BOOL:${HAVE_FDATASYNC}> + HAVE_FULLFSYNC=$<BOOL:${HAVE_FULLFSYNC}> + HAVE_O_CLOEXEC=$<BOOL:${HAVE_O_CLOEXEC}> + FALLTHROUGH_INTENDED=[[fallthrough]] + LEVELDB_IS_BIG_ENDIAN=$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},BIG_ENDIAN> + $<$<NOT:$<BOOL:${WIN32}>>:LEVELDB_PLATFORM_POSIX> + $<$<BOOL:${WIN32}>:LEVELDB_PLATFORM_WINDOWS> + $<$<BOOL:${WIN32}>:_UNICODE;UNICODE> +) +if(MINGW) + target_compile_definitions(leveldb + PRIVATE + __USE_MINGW_ANSI_STDIO=1 + ) +endif() + +target_include_directories(leveldb + PRIVATE + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb> + PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb/include> +) + +add_library(nowarn_leveldb_interface INTERFACE) +if(MSVC) + target_compile_options(nowarn_leveldb_interface INTERFACE + /wd4722 + ) + target_compile_definitions(nowarn_leveldb_interface INTERFACE + _CRT_NONSTDC_NO_WARNINGS + ) +else() + target_compile_options(nowarn_leveldb_interface INTERFACE + -Wno-conditional-uninitialized + -Wno-suggest-override + ) +endif() + +target_link_libraries(leveldb PRIVATE + core_interface + nowarn_leveldb_interface + crc32c +) + +set_target_properties(leveldb PROPERTIES + EXPORT_COMPILE_COMMANDS OFF +) diff --git a/cmake/minisketch.cmake b/cmake/minisketch.cmake new file mode 100644 index 0000000000..bb93c80467 --- /dev/null +++ b/cmake/minisketch.cmake @@ -0,0 +1,91 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# Check for clmul instructions support. +if(MSVC) + set(CLMUL_CXXFLAGS) +else() + set(CLMUL_CXXFLAGS -mpclmul) +endif() +check_cxx_source_compiles_with_flags("${CLMUL_CXXFLAGS}" " + #include <immintrin.h> + #include <cstdint> + + int main() + { + __m128i a = _mm_cvtsi64_si128((uint64_t)7); + __m128i b = _mm_clmulepi64_si128(a, a, 37); + __m128i c = _mm_srli_epi64(b, 41); + __m128i d = _mm_xor_si128(b, c); + uint64_t e = _mm_cvtsi128_si64(d); + return e == 0; + } + " HAVE_CLMUL +) + +add_library(minisketch_common INTERFACE) +target_compile_definitions(minisketch_common INTERFACE + DISABLE_DEFAULT_FIELDS + ENABLE_FIELD_32 +) +if(MSVC) + target_compile_options(minisketch_common INTERFACE + /wd4060 + /wd4065 + /wd4146 + /wd4244 + /wd4267 + ) +endif() + +if(HAVE_CLMUL) + add_library(minisketch_clmul OBJECT EXCLUDE_FROM_ALL + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_1byte.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_2bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_3bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_4bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_5bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_6bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_7bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_8bytes.cpp + ) + target_compile_definitions(minisketch_clmul PUBLIC HAVE_CLMUL) + target_compile_options(minisketch_clmul PRIVATE ${CLMUL_CXXFLAGS}) + target_link_libraries(minisketch_clmul + PRIVATE + core_interface + minisketch_common + ) + set_target_properties(minisketch_clmul PROPERTIES + EXPORT_COMPILE_COMMANDS OFF + ) +endif() + +add_library(minisketch STATIC EXCLUDE_FROM_ALL + ${PROJECT_SOURCE_DIR}/src/minisketch/src/minisketch.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_1byte.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_2bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_3bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_4bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_5bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_6bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_7bytes.cpp + ${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_8bytes.cpp +) + +target_include_directories(minisketch + PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/minisketch/include> +) + +target_link_libraries(minisketch + PRIVATE + core_interface + minisketch_common + $<TARGET_NAME_IF_EXISTS:minisketch_clmul> +) + +set_target_properties(minisketch PROPERTIES + EXPORT_COMPILE_COMMANDS OFF +) diff --git a/cmake/module/AddBoostIfNeeded.cmake b/cmake/module/AddBoostIfNeeded.cmake new file mode 100644 index 0000000000..ecd0d6f2ab --- /dev/null +++ b/cmake/module/AddBoostIfNeeded.cmake @@ -0,0 +1,78 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +function(add_boost_if_needed) + #[=[ + TODO: Not all targets, which will be added in the future, require + Boost. Therefore, a proper check will be appropriate here. + + Implementation notes: + Although only Boost headers are used to build Bitcoin Core, + we still leverage a standard CMake's approach to handle + dependencies, i.e., the Boost::headers "library". + A command target_link_libraries(target PRIVATE Boost::headers) + will propagate Boost::headers usage requirements to the target. + For Boost::headers such usage requirements is an include + directory and other added INTERFACE properties. + ]=] + + # We cannot rely on find_package(Boost ...) to work properly without + # Boost_NO_BOOST_CMAKE set until we require a more recent Boost because + # upstream did not ship proper CMake files until 1.82.0. + # Until then, we rely on CMake's FindBoost module. + # See: https://cmake.org/cmake/help/latest/policy/CMP0167.html + if(POLICY CMP0167) + cmake_policy(SET CMP0167 OLD) + endif() + set(Boost_NO_BOOST_CMAKE ON) + find_package(Boost 1.73.0 REQUIRED) + mark_as_advanced(Boost_INCLUDE_DIR) + set_target_properties(Boost::headers PROPERTIES IMPORTED_GLOBAL TRUE) + target_compile_definitions(Boost::headers INTERFACE + # We don't use multi_index serialization. + BOOST_MULTI_INDEX_DISABLE_SERIALIZATION + ) + if(DEFINED VCPKG_TARGET_TRIPLET) + # Workaround for https://github.com/microsoft/vcpkg/issues/36955. + target_compile_definitions(Boost::headers INTERFACE + BOOST_NO_USER_CONFIG + ) + endif() + + # Prevent use of std::unary_function, which was removed in C++17, + # and will generate warnings with newer compilers for Boost + # older than 1.80. + # See: https://github.com/boostorg/config/pull/430. + set(CMAKE_REQUIRED_DEFINITIONS -DBOOST_NO_CXX98_FUNCTION_BASE) + set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIR}) + include(CMakePushCheckState) + cmake_push_check_state() + include(TryAppendCXXFlags) + set(CMAKE_REQUIRED_FLAGS ${working_compiler_werror_flag}) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_cxx_source_compiles(" + #include <boost/config.hpp> + " NO_DIAGNOSTICS_BOOST_NO_CXX98_FUNCTION_BASE + ) + cmake_pop_check_state() + if(NO_DIAGNOSTICS_BOOST_NO_CXX98_FUNCTION_BASE) + target_compile_definitions(Boost::headers INTERFACE + BOOST_NO_CXX98_FUNCTION_BASE + ) + else() + set(CMAKE_REQUIRED_DEFINITIONS) + endif() + + # Some package managers, such as vcpkg, vendor Boost.Test separately + # from the rest of the headers, so we have to check for it individually. + if(BUILD_TESTS AND DEFINED VCPKG_TARGET_TRIPLET) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DBOOST_TEST_NO_MAIN) + include(CheckIncludeFileCXX) + check_include_file_cxx(boost/test/included/unit_test.hpp HAVE_BOOST_INCLUDED_UNIT_TEST_H) + if(NOT HAVE_BOOST_INCLUDED_UNIT_TEST_H) + message(FATAL_ERROR "Building test_bitcoin executable requested but boost/test/included/unit_test.hpp header not available.") + endif() + endif() + +endfunction() diff --git a/cmake/module/AddWindowsResources.cmake b/cmake/module/AddWindowsResources.cmake new file mode 100644 index 0000000000..a9b4f51f73 --- /dev/null +++ b/cmake/module/AddWindowsResources.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) + +macro(add_windows_resources target rc_file) + if(WIN32) + target_sources(${target} PRIVATE ${rc_file}) + set_property(SOURCE ${rc_file} + APPEND PROPERTY COMPILE_DEFINITIONS WINDRES_PREPROC + ) + endif() +endmacro() diff --git a/cmake/module/CheckSourceCompilesAndLinks.cmake b/cmake/module/CheckSourceCompilesAndLinks.cmake new file mode 100644 index 0000000000..88c897d524 --- /dev/null +++ b/cmake/module/CheckSourceCompilesAndLinks.cmake @@ -0,0 +1,39 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) +include(CheckCXXSourceCompiles) +include(CMakePushCheckState) + +# This avoids running the linker. +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +macro(check_cxx_source_links source) + set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) + check_cxx_source_compiles("${source}" ${ARGN}) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endmacro() + +macro(check_cxx_source_compiles_with_flags flags source) + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_FLAGS ${flags}) + list(JOIN CMAKE_REQUIRED_FLAGS " " CMAKE_REQUIRED_FLAGS) + check_cxx_source_compiles("${source}" ${ARGN}) + cmake_pop_check_state() +endmacro() + +macro(check_cxx_source_links_with_flags flags source) + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_FLAGS ${flags}) + list(JOIN CMAKE_REQUIRED_FLAGS " " CMAKE_REQUIRED_FLAGS) + check_cxx_source_links("${source}" ${ARGN}) + cmake_pop_check_state() +endmacro() + +macro(check_cxx_source_links_with_libs libs source) + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_LIBRARIES "${libs}") + check_cxx_source_links("${source}" ${ARGN}) + cmake_pop_check_state() +endmacro() diff --git a/cmake/module/FindBerkeleyDB.cmake b/cmake/module/FindBerkeleyDB.cmake new file mode 100644 index 0000000000..03a3cce10c --- /dev/null +++ b/cmake/module/FindBerkeleyDB.cmake @@ -0,0 +1,133 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +#[=======================================================================[ +FindBerkeleyDB +-------------- + +Finds the Berkeley DB headers and library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides imported target ``BerkeleyDB::BerkeleyDB``, if +Berkeley DB has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +``BerkeleyDB_FOUND`` + "True" if Berkeley DB found. + +``BerkeleyDB_VERSION`` + The MAJOR.MINOR version of Berkeley DB found. + +#]=======================================================================] + +set(_BerkeleyDB_homebrew_prefix) +if(CMAKE_HOST_APPLE) + find_program(HOMEBREW_EXECUTABLE brew) + if(HOMEBREW_EXECUTABLE) + # The Homebrew package manager installs the berkeley-db* packages as + # "keg-only", which means they are not symlinked into the default prefix. + # To find such a package, the find_path() and find_library() commands + # need additional path hints that are computed by Homebrew itself. + execute_process( + COMMAND ${HOMEBREW_EXECUTABLE} --prefix berkeley-db@4 + OUTPUT_VARIABLE _BerkeleyDB_homebrew_prefix + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() +endif() + +find_path(BerkeleyDB_INCLUDE_DIR + NAMES db_cxx.h + HINTS ${_BerkeleyDB_homebrew_prefix}/include + PATH_SUFFIXES 4.8 48 db4.8 4 db4 5.3 db5.3 5 db5 +) +mark_as_advanced(BerkeleyDB_INCLUDE_DIR) +unset(_BerkeleyDB_homebrew_prefix) + +if(NOT BerkeleyDB_LIBRARY) + if(VCPKG_TARGET_TRIPLET) + # The vcpkg package manager installs the berkeleydb package with the same name + # of release and debug libraries. Therefore, the default search paths set by + # vcpkg's toolchain file cannot be used to search libraries as the debug one + # will always be found. + set(CMAKE_FIND_USE_CMAKE_PATH FALSE) + endif() + + get_filename_component(_BerkeleyDB_lib_hint "${BerkeleyDB_INCLUDE_DIR}" DIRECTORY) + + find_library(BerkeleyDB_LIBRARY_RELEASE + NAMES db_cxx-4.8 db4_cxx db48 db_cxx-5.3 db_cxx-5 db_cxx libdb48 + NAMES_PER_DIR + HINTS ${_BerkeleyDB_lib_hint} + PATH_SUFFIXES lib + ) + mark_as_advanced(BerkeleyDB_LIBRARY_RELEASE) + + find_library(BerkeleyDB_LIBRARY_DEBUG + NAMES db_cxx-4.8 db4_cxx db48 db_cxx-5.3 db_cxx-5 db_cxx libdb48 + NAMES_PER_DIR + HINTS ${_BerkeleyDB_lib_hint} + PATH_SUFFIXES debug/lib + ) + mark_as_advanced(BerkeleyDB_LIBRARY_DEBUG) + + unset(_BerkeleyDB_lib_hint) + unset(CMAKE_FIND_USE_CMAKE_PATH) + + include(SelectLibraryConfigurations) + select_library_configurations(BerkeleyDB) + # The select_library_configurations() command sets BerkeleyDB_FOUND, but we + # want the one from the find_package_handle_standard_args() command below. + unset(BerkeleyDB_FOUND) +endif() + +if(BerkeleyDB_INCLUDE_DIR) + file(STRINGS "${BerkeleyDB_INCLUDE_DIR}/db.h" _BerkeleyDB_version_strings REGEX "^#define[\t ]+DB_VERSION_(MAJOR|MINOR|PATCH)[ \t]+[0-9]+.*") + string(REGEX REPLACE ".*#define[\t ]+DB_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" _BerkeleyDB_version_major "${_BerkeleyDB_version_strings}") + string(REGEX REPLACE ".*#define[\t ]+DB_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" _BerkeleyDB_version_minor "${_BerkeleyDB_version_strings}") + string(REGEX REPLACE ".*#define[\t ]+DB_VERSION_PATCH[ \t]+([0-9]+).*" "\\1" _BerkeleyDB_version_patch "${_BerkeleyDB_version_strings}") + unset(_BerkeleyDB_version_strings) + # The MAJOR.MINOR.PATCH version will be logged in the following find_package_handle_standard_args() command. + set(_BerkeleyDB_full_version ${_BerkeleyDB_version_major}.${_BerkeleyDB_version_minor}.${_BerkeleyDB_version_patch}) + set(BerkeleyDB_VERSION ${_BerkeleyDB_version_major}.${_BerkeleyDB_version_minor}) + unset(_BerkeleyDB_version_major) + unset(_BerkeleyDB_version_minor) + unset(_BerkeleyDB_version_patch) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(BerkeleyDB + REQUIRED_VARS BerkeleyDB_LIBRARY BerkeleyDB_INCLUDE_DIR + VERSION_VAR _BerkeleyDB_full_version +) +unset(_BerkeleyDB_full_version) + +if(BerkeleyDB_FOUND AND NOT TARGET BerkeleyDB::BerkeleyDB) + add_library(BerkeleyDB::BerkeleyDB UNKNOWN IMPORTED) + set_target_properties(BerkeleyDB::BerkeleyDB PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${BerkeleyDB_INCLUDE_DIR}" + ) + if(BerkeleyDB_LIBRARY_RELEASE) + set_property(TARGET BerkeleyDB::BerkeleyDB APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE + ) + set_target_properties(BerkeleyDB::BerkeleyDB PROPERTIES + IMPORTED_LOCATION_RELEASE "${BerkeleyDB_LIBRARY_RELEASE}" + ) + endif() + if(BerkeleyDB_LIBRARY_DEBUG) + set_property(TARGET BerkeleyDB::BerkeleyDB APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(BerkeleyDB::BerkeleyDB PROPERTIES + IMPORTED_LOCATION_DEBUG "${BerkeleyDB_LIBRARY_DEBUG}" + ) + endif() +endif() diff --git a/cmake/module/FindLibevent.cmake b/cmake/module/FindLibevent.cmake new file mode 100644 index 0000000000..901a4f3bd4 --- /dev/null +++ b/cmake/module/FindLibevent.cmake @@ -0,0 +1,80 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +#[=======================================================================[ +FindLibevent +------------ + +Finds the Libevent headers and libraries. + +This is a wrapper around find_package()/pkg_check_modules() commands that: + - facilitates searching in various build environments + - prints a standard log message + +#]=======================================================================] + +# Check whether evhttp_connection_get_peer expects const char**. +# See https://github.com/libevent/libevent/commit/a18301a2bb160ff7c3ffaf5b7653c39ffe27b385 +function(check_evhttp_connection_get_peer target) + include(CMakePushCheckState) + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_LIBRARIES ${target}) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" + #include <cstdint> + #include <event2/http.h> + + int main() + { + evhttp_connection* conn = (evhttp_connection*)1; + const char* host; + uint16_t port; + evhttp_connection_get_peer(conn, &host, &port); + } + " HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR + ) + cmake_pop_check_state() + set(HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR ${HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR} PARENT_SCOPE) +endfunction() + + +include(FindPackageHandleStandardArgs) +if(VCPKG_TARGET_TRIPLET) + find_package(Libevent ${Libevent_FIND_VERSION} NO_MODULE QUIET + COMPONENTS extra + ) + find_package_handle_standard_args(Libevent + REQUIRED_VARS Libevent_DIR + VERSION_VAR Libevent_VERSION + ) + check_evhttp_connection_get_peer(libevent::extra) + add_library(libevent::libevent ALIAS libevent::extra) + mark_as_advanced(Libevent_DIR) + mark_as_advanced(_event_h) + mark_as_advanced(_event_lib) +else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(libevent QUIET + IMPORTED_TARGET + libevent>=${Libevent_FIND_VERSION} + ) + set(_libevent_required_vars libevent_LIBRARY_DIRS libevent_FOUND) + if(NOT WIN32) + pkg_check_modules(libevent_pthreads QUIET + IMPORTED_TARGET + libevent_pthreads>=${Libevent_FIND_VERSION} + ) + list(APPEND _libevent_required_vars libevent_pthreads_FOUND) + endif() + find_package_handle_standard_args(Libevent + REQUIRED_VARS ${_libevent_required_vars} + VERSION_VAR libevent_VERSION + ) + unset(_libevent_required_vars) + check_evhttp_connection_get_peer(PkgConfig::libevent) + add_library(libevent::libevent ALIAS PkgConfig::libevent) + if(NOT WIN32) + add_library(libevent::pthreads ALIAS PkgConfig::libevent_pthreads) + endif() +endif() diff --git a/cmake/module/FindMiniUPnPc.cmake b/cmake/module/FindMiniUPnPc.cmake new file mode 100644 index 0000000000..34b94f05f1 --- /dev/null +++ b/cmake/module/FindMiniUPnPc.cmake @@ -0,0 +1,84 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +if(NOT MSVC) + find_package(PkgConfig REQUIRED) + pkg_check_modules(PC_MiniUPnPc QUIET miniupnpc) +endif() + +find_path(MiniUPnPc_INCLUDE_DIR + NAMES miniupnpc/miniupnpc.h + PATHS ${PC_MiniUPnPc_INCLUDE_DIRS} +) + +if(MiniUPnPc_INCLUDE_DIR) + file( + STRINGS "${MiniUPnPc_INCLUDE_DIR}/miniupnpc/miniupnpc.h" version_strings + REGEX "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+[0-9]+" + ) + string(REGEX REPLACE "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+([0-9]+)" "\\1" MiniUPnPc_API_VERSION "${version_strings}") + + # The minimum supported miniUPnPc API version is set to 17. This excludes + # versions with known vulnerabilities. + if(MiniUPnPc_API_VERSION GREATER_EQUAL 17) + set(MiniUPnPc_API_VERSION_OK TRUE) + endif() +endif() + +if(MSVC) + cmake_path(GET MiniUPnPc_INCLUDE_DIR PARENT_PATH MiniUPnPc_IMPORTED_PATH) + find_library(MiniUPnPc_LIBRARY_DEBUG + NAMES miniupnpc PATHS ${MiniUPnPc_IMPORTED_PATH}/debug/lib + NO_DEFAULT_PATH + ) + find_library(MiniUPnPc_LIBRARY_RELEASE + NAMES miniupnpc PATHS ${MiniUPnPc_IMPORTED_PATH}/lib + NO_DEFAULT_PATH + ) + set(MiniUPnPc_required MiniUPnPc_IMPORTED_PATH) +else() + find_library(MiniUPnPc_LIBRARY + NAMES miniupnpc + PATHS ${PC_MiniUPnPc_LIBRARY_DIRS} + ) + set(MiniUPnPc_required MiniUPnPc_LIBRARY) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MiniUPnPc + REQUIRED_VARS ${MiniUPnPc_required} MiniUPnPc_INCLUDE_DIR MiniUPnPc_API_VERSION_OK +) + +if(MiniUPnPc_FOUND AND NOT TARGET MiniUPnPc::MiniUPnPc) + add_library(MiniUPnPc::MiniUPnPc UNKNOWN IMPORTED) + set_target_properties(MiniUPnPc::MiniUPnPc PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${MiniUPnPc_INCLUDE_DIR}" + ) + if(MSVC) + if(MiniUPnPc_LIBRARY_DEBUG) + set_property(TARGET MiniUPnPc::MiniUPnPc APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(MiniUPnPc::MiniUPnPc PROPERTIES + IMPORTED_LOCATION_DEBUG "${MiniUPnPc_LIBRARY_DEBUG}" + ) + endif() + if(MiniUPnPc_LIBRARY_RELEASE) + set_property(TARGET MiniUPnPc::MiniUPnPc APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(MiniUPnPc::MiniUPnPc PROPERTIES + IMPORTED_LOCATION_RELEASE "${MiniUPnPc_LIBRARY_RELEASE}" + ) + endif() + else() + set_target_properties(MiniUPnPc::MiniUPnPc PROPERTIES + IMPORTED_LOCATION "${MiniUPnPc_LIBRARY}" + ) + endif() + set_property(TARGET MiniUPnPc::MiniUPnPc PROPERTY + INTERFACE_COMPILE_DEFINITIONS USE_UPNP=1 $<$<PLATFORM_ID:Windows>:MINIUPNP_STATICLIB> + ) +endif() + +mark_as_advanced( + MiniUPnPc_INCLUDE_DIR + MiniUPnPc_LIBRARY +) diff --git a/cmake/module/FindQt.cmake b/cmake/module/FindQt.cmake new file mode 100644 index 0000000000..2e43294a99 --- /dev/null +++ b/cmake/module/FindQt.cmake @@ -0,0 +1,66 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +#[=======================================================================[ +FindQt +------ + +Finds the Qt headers and libraries. + +This is a wrapper around find_package() command that: + - facilitates searching in various build environments + - prints a standard log message + +#]=======================================================================] + +set(_qt_homebrew_prefix) +if(CMAKE_HOST_APPLE) + find_program(HOMEBREW_EXECUTABLE brew) + if(HOMEBREW_EXECUTABLE) + execute_process( + COMMAND ${HOMEBREW_EXECUTABLE} --prefix qt@${Qt_FIND_VERSION_MAJOR} + OUTPUT_VARIABLE _qt_homebrew_prefix + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() +endif() + +# Save CMAKE_FIND_ROOT_PATH_MODE_LIBRARY state. +unset(_qt_find_root_path_mode_library_saved) +if(DEFINED CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(_qt_find_root_path_mode_library_saved ${CMAKE_FIND_ROOT_PATH_MODE_LIBRARY}) +endif() + +# The Qt config files internally use find_library() calls for all +# dependencies to ensure their availability. In turn, the find_library() +# inspects the well-known locations on the file system; therefore, it must +# be able to find platform-specific system libraries, for example: +# /usr/x86_64-w64-mingw32/lib/libm.a or /usr/arm-linux-gnueabihf/lib/libm.a. +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) + +find_package(Qt${Qt_FIND_VERSION_MAJOR} ${Qt_FIND_VERSION} + COMPONENTS ${Qt_FIND_COMPONENTS} + HINTS ${_qt_homebrew_prefix} + PATH_SUFFIXES Qt${Qt_FIND_VERSION_MAJOR} # Required on OpenBSD systems. +) +unset(_qt_homebrew_prefix) + +# Restore CMAKE_FIND_ROOT_PATH_MODE_LIBRARY state. +if(DEFINED _qt_find_root_path_mode_library_saved) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ${_qt_find_root_path_mode_library_saved}) + unset(_qt_find_root_path_mode_library_saved) +else() + unset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Qt + REQUIRED_VARS Qt${Qt_FIND_VERSION_MAJOR}_DIR + VERSION_VAR Qt${Qt_FIND_VERSION_MAJOR}_VERSION +) + +foreach(component IN LISTS Qt_FIND_COMPONENTS ITEMS "") + mark_as_advanced(Qt${Qt_FIND_VERSION_MAJOR}${component}_DIR) +endforeach() diff --git a/cmake/module/FindUSDT.cmake b/cmake/module/FindUSDT.cmake new file mode 100644 index 0000000000..0ba9a58fc1 --- /dev/null +++ b/cmake/module/FindUSDT.cmake @@ -0,0 +1,64 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +#[=======================================================================[ +FindUSDT +-------- + +Finds the Userspace, Statically Defined Tracing header(s). + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides imported target ``USDT::headers``, if +USDT has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +``USDT_FOUND`` + "True" if USDT found. + +#]=======================================================================] + +find_path(USDT_INCLUDE_DIR + NAMES sys/sdt.h +) +mark_as_advanced(USDT_INCLUDE_DIR) + +if(USDT_INCLUDE_DIR) + include(CMakePushCheckState) + cmake_push_check_state(RESET) + + include(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES ${USDT_INCLUDE_DIR}) + check_cxx_source_compiles(" + #include <sys/sdt.h> + + int main() + { + DTRACE_PROBE(context, event); + int a, b, c, d, e, f, g; + DTRACE_PROBE7(context, event, a, b, c, d, e, f, g); + } + " HAVE_USDT_H + ) + + cmake_pop_check_state() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(USDT + REQUIRED_VARS USDT_INCLUDE_DIR HAVE_USDT_H +) + +if(USDT_FOUND AND NOT TARGET USDT::headers) + add_library(USDT::headers INTERFACE IMPORTED) + set_target_properties(USDT::headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${USDT_INCLUDE_DIR}" + ) + set(ENABLE_TRACING TRUE) +endif() diff --git a/cmake/module/FlagsSummary.cmake b/cmake/module/FlagsSummary.cmake new file mode 100644 index 0000000000..91d1df90d9 --- /dev/null +++ b/cmake/module/FlagsSummary.cmake @@ -0,0 +1,74 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) + +function(indent_message header content indent_num) + if(indent_num GREATER 0) + string(REPEAT " " ${indent_num} indentation) + string(REPEAT "." ${indent_num} tail) + string(REGEX REPLACE "${tail}$" "" header "${header}") + endif() + message("${indentation}${header} ${content}") +endfunction() + +# Print tools' flags on best-effort. Include the abstracted +# CMake flags that we touch ourselves. +function(print_flags_per_config config indent_num) + string(TOUPPER "${config}" config_uppercase) + + include(GetTargetInterface) + get_target_interface(definitions "${config}" core_interface COMPILE_DEFINITIONS) + indent_message("Preprocessor defined macros ..........." "${definitions}" ${indent_num}) + + string(STRIP "${CMAKE_CXX_COMPILER_ARG1} ${CMAKE_CXX_FLAGS}" combined_cxx_flags) + string(STRIP "${combined_cxx_flags} ${CMAKE_CXX_FLAGS_${config_uppercase}}" combined_cxx_flags) + string(STRIP "${combined_cxx_flags} ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION}" combined_cxx_flags) + if(CMAKE_POSITION_INDEPENDENT_CODE) + string(JOIN " " combined_cxx_flags ${combined_cxx_flags} ${CMAKE_CXX_COMPILE_OPTIONS_PIC}) + endif() + get_target_interface(core_cxx_flags "${config}" core_interface COMPILE_OPTIONS) + string(STRIP "${combined_cxx_flags} ${core_cxx_flags}" combined_cxx_flags) + string(STRIP "${combined_cxx_flags} ${APPEND_CPPFLAGS}" combined_cxx_flags) + string(STRIP "${combined_cxx_flags} ${APPEND_CXXFLAGS}" combined_cxx_flags) + indent_message("C++ compiler flags ...................." "${combined_cxx_flags}" ${indent_num}) + + string(STRIP "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${config_uppercase}}" combined_linker_flags) + string(STRIP "${combined_linker_flags} ${CMAKE_EXE_LINKER_FLAGS}" combined_linker_flags) + get_target_interface(common_link_options "${config}" core_interface LINK_OPTIONS) + string(STRIP "${combined_linker_flags} ${common_link_options}" combined_linker_flags) + if(CMAKE_CXX_LINK_PIE_SUPPORTED) + string(JOIN " " combined_linker_flags ${combined_linker_flags} ${CMAKE_CXX_LINK_OPTIONS_PIE}) + endif() + string(STRIP "${combined_linker_flags} ${APPEND_LDFLAGS}" combined_linker_flags) + indent_message("Linker flags .........................." "${combined_linker_flags}" ${indent_num}) +endfunction() + +function(flags_summary) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + list(JOIN CMAKE_CONFIGURATION_TYPES ", " configs) + message("Available build configurations ........ ${configs}") + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(default_config "Debug") + else() + list(GET CMAKE_CONFIGURATION_TYPES 0 default_config) + endif() + message("Default build configuration ........... ${default_config}") + foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES) + message("") + message("'${config}' build configuration:") + print_flags_per_config("${config}" 2) + endforeach() + else() + message("CMAKE_BUILD_TYPE ...................... ${CMAKE_BUILD_TYPE}") + print_flags_per_config("${CMAKE_BUILD_TYPE}" 0) + endif() + message("") + message([=[ +NOTE: The summary above may not exactly match the final applied build flags + if any additional CMAKE_* or environment variables have been modified. + To see the exact flags applied, build with the --verbose option. +]=]) +endfunction() diff --git a/cmake/module/GenerateHeaders.cmake b/cmake/module/GenerateHeaders.cmake new file mode 100644 index 0000000000..c69007acb6 --- /dev/null +++ b/cmake/module/GenerateHeaders.cmake @@ -0,0 +1,21 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +function(generate_header_from_json json_source_relpath) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${json_source_relpath}.h + COMMAND ${CMAKE_COMMAND} -DJSON_SOURCE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/${json_source_relpath} -DHEADER_PATH=${CMAKE_CURRENT_BINARY_DIR}/${json_source_relpath}.h -P ${PROJECT_SOURCE_DIR}/cmake/script/GenerateHeaderFromJson.cmake + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${json_source_relpath} ${PROJECT_SOURCE_DIR}/cmake/script/GenerateHeaderFromJson.cmake + VERBATIM + ) +endfunction() + +function(generate_header_from_raw raw_source_relpath raw_namespace) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${raw_source_relpath}.h + COMMAND ${CMAKE_COMMAND} -DRAW_SOURCE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/${raw_source_relpath} -DHEADER_PATH=${CMAKE_CURRENT_BINARY_DIR}/${raw_source_relpath}.h -DRAW_NAMESPACE=${raw_namespace} -P ${PROJECT_SOURCE_DIR}/cmake/script/GenerateHeaderFromRaw.cmake + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${raw_source_relpath} ${PROJECT_SOURCE_DIR}/cmake/script/GenerateHeaderFromRaw.cmake + VERBATIM + ) +endfunction() diff --git a/cmake/module/GenerateSetupNsi.cmake b/cmake/module/GenerateSetupNsi.cmake new file mode 100644 index 0000000000..3c358c5495 --- /dev/null +++ b/cmake/module/GenerateSetupNsi.cmake @@ -0,0 +1,18 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +function(generate_setup_nsi) + set(abs_top_srcdir ${PROJECT_SOURCE_DIR}) + set(abs_top_builddir ${PROJECT_BINARY_DIR}) + set(PACKAGE_URL ${PROJECT_HOMEPAGE_URL}) + set(PACKAGE_TARNAME "bitcoin") + set(BITCOIN_GUI_NAME "bitcoin-qt") + set(BITCOIN_DAEMON_NAME "bitcoind") + set(BITCOIN_CLI_NAME "bitcoin-cli") + set(BITCOIN_TX_NAME "bitcoin-tx") + set(BITCOIN_WALLET_TOOL_NAME "bitcoin-wallet") + set(BITCOIN_TEST_NAME "test_bitcoin") + set(EXEEXT ${CMAKE_EXECUTABLE_SUFFIX}) + configure_file(${PROJECT_SOURCE_DIR}/share/setup.nsi.in ${PROJECT_BINARY_DIR}/bitcoin-win64-setup.nsi USE_SOURCE_PERMISSIONS @ONLY) +endfunction() diff --git a/cmake/module/GetTargetInterface.cmake b/cmake/module/GetTargetInterface.cmake new file mode 100644 index 0000000000..1e455d456b --- /dev/null +++ b/cmake/module/GetTargetInterface.cmake @@ -0,0 +1,53 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) + +# Evaluates config-specific generator expressions in a list. +# Recognizable patterns are: +# - $<$<CONFIG:[config]>:[value]> +# - $<$<NOT:$<CONFIG:[config]>>:[value]> +function(evaluate_generator_expressions list config) + set(input ${${list}}) + set(result) + foreach(token IN LISTS input) + if(token MATCHES "\\$<\\$<CONFIG:([^>]+)>:([^>]+)>") + if(CMAKE_MATCH_1 STREQUAL config) + list(APPEND result ${CMAKE_MATCH_2}) + endif() + elseif(token MATCHES "\\$<\\$<NOT:\\$<CONFIG:([^>]+)>>:([^>]+)>") + if(NOT CMAKE_MATCH_1 STREQUAL config) + list(APPEND result ${CMAKE_MATCH_2}) + endif() + else() + list(APPEND result ${token}) + endif() + endforeach() + set(${list} ${result} PARENT_SCOPE) +endfunction() + + +# Gets target's interface properties recursively. +function(get_target_interface var config target property) + get_target_property(result ${target} INTERFACE_${property}) + if(result) + evaluate_generator_expressions(result "${config}") + list(JOIN result " " result) + else() + set(result) + endif() + + get_target_property(dependencies ${target} INTERFACE_LINK_LIBRARIES) + if(dependencies) + evaluate_generator_expressions(dependencies "${config}") + foreach(dependency IN LISTS dependencies) + if(TARGET ${dependency}) + get_target_interface(dep_result "${config}" ${dependency} ${property}) + string(STRIP "${result} ${dep_result}" result) + endif() + endforeach() + endif() + + set(${var} "${result}" PARENT_SCOPE) +endfunction() diff --git a/cmake/module/Maintenance.cmake b/cmake/module/Maintenance.cmake new file mode 100644 index 0000000000..456419b722 --- /dev/null +++ b/cmake/module/Maintenance.cmake @@ -0,0 +1,151 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) + +function(setup_split_debug_script) + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + set(OBJCOPY ${CMAKE_OBJCOPY}) + set(STRIP ${CMAKE_STRIP}) + configure_file( + contrib/devtools/split-debug.sh.in split-debug.sh + FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ + @ONLY + ) + endif() +endfunction() + +function(add_maintenance_targets) + if(NOT PYTHON_COMMAND) + return() + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(exe_format MACHO) + elseif(WIN32) + set(exe_format PE) + else() + set(exe_format ELF) + endif() + + # In CMake, the components of the compiler invocation are separated into distinct variables: + # - CMAKE_CXX_COMPILER: the full path to the compiler binary itself (e.g., /usr/bin/clang++). + # - CMAKE_CXX_COMPILER_ARG1: a string containing initial compiler options (e.g., --target=x86_64-apple-darwin -nostdlibinc). + # By concatenating these variables, we form the complete command line to be passed to a Python script via the CXX environment variable. + string(STRIP "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" cxx_compiler_command) + add_custom_target(test-security-check + COMMAND ${CMAKE_COMMAND} -E env CXX=${cxx_compiler_command} CXXFLAGS=${CMAKE_CXX_FLAGS} LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${PYTHON_COMMAND} ${PROJECT_SOURCE_DIR}/contrib/devtools/test-security-check.py TestSecurityChecks.test_${exe_format} + COMMAND ${CMAKE_COMMAND} -E env CXX=${cxx_compiler_command} CXXFLAGS=${CMAKE_CXX_FLAGS} LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${PYTHON_COMMAND} ${PROJECT_SOURCE_DIR}/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_${exe_format} + VERBATIM + ) + + foreach(target IN ITEMS bitcoind bitcoin-qt bitcoin-cli bitcoin-tx bitcoin-util bitcoin-wallet test_bitcoin bench_bitcoin) + if(TARGET ${target}) + list(APPEND executables $<TARGET_FILE:${target}>) + endif() + endforeach() + + add_custom_target(check-symbols + COMMAND ${CMAKE_COMMAND} -E echo "Running symbol and dynamic library checks..." + COMMAND ${PYTHON_COMMAND} ${PROJECT_SOURCE_DIR}/contrib/devtools/symbol-check.py ${executables} + VERBATIM + ) + + if(ENABLE_HARDENING) + add_custom_target(check-security + COMMAND ${CMAKE_COMMAND} -E echo "Checking binary security..." + COMMAND ${PYTHON_COMMAND} ${PROJECT_SOURCE_DIR}/contrib/devtools/security-check.py ${executables} + VERBATIM + ) + else() + add_custom_target(check-security) + endif() +endfunction() + +function(add_windows_deploy_target) + if(MINGW AND TARGET bitcoin-qt AND TARGET bitcoind AND TARGET bitcoin-cli AND TARGET bitcoin-tx AND TARGET bitcoin-wallet AND TARGET bitcoin-util AND TARGET test_bitcoin) + # TODO: Consider replacing this code with the CPack NSIS Generator. + # See https://cmake.org/cmake/help/latest/cpack_gen/nsis.html + include(GenerateSetupNsi) + generate_setup_nsi() + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/bitcoin-win64-setup.exe + COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/release + COMMAND ${CMAKE_STRIP} $<TARGET_FILE:bitcoin-qt> -o ${PROJECT_BINARY_DIR}/release/$<TARGET_FILE_NAME:bitcoin-qt> + COMMAND ${CMAKE_STRIP} $<TARGET_FILE:bitcoind> -o ${PROJECT_BINARY_DIR}/release/$<TARGET_FILE_NAME:bitcoind> + COMMAND ${CMAKE_STRIP} $<TARGET_FILE:bitcoin-cli> -o ${PROJECT_BINARY_DIR}/release/$<TARGET_FILE_NAME:bitcoin-cli> + COMMAND ${CMAKE_STRIP} $<TARGET_FILE:bitcoin-tx> -o ${PROJECT_BINARY_DIR}/release/$<TARGET_FILE_NAME:bitcoin-tx> + COMMAND ${CMAKE_STRIP} $<TARGET_FILE:bitcoin-wallet> -o ${PROJECT_BINARY_DIR}/release/$<TARGET_FILE_NAME:bitcoin-wallet> + COMMAND ${CMAKE_STRIP} $<TARGET_FILE:bitcoin-util> -o ${PROJECT_BINARY_DIR}/release/$<TARGET_FILE_NAME:bitcoin-util> + COMMAND ${CMAKE_STRIP} $<TARGET_FILE:test_bitcoin> -o ${PROJECT_BINARY_DIR}/release/$<TARGET_FILE_NAME:test_bitcoin> + COMMAND makensis -V2 ${PROJECT_BINARY_DIR}/bitcoin-win64-setup.nsi + VERBATIM + ) + add_custom_target(deploy DEPENDS ${PROJECT_BINARY_DIR}/bitcoin-win64-setup.exe) + endif() +endfunction() + +function(add_macos_deploy_target) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND TARGET bitcoin-qt) + set(macos_app "Bitcoin-Qt.app") + # Populate Contents subdirectory. + configure_file(${PROJECT_SOURCE_DIR}/share/qt/Info.plist.in ${macos_app}/Contents/Info.plist NO_SOURCE_PERMISSIONS) + file(CONFIGURE OUTPUT ${macos_app}/Contents/PkgInfo CONTENT "APPL????") + # Populate Contents/Resources subdirectory. + file(CONFIGURE OUTPUT ${macos_app}/Contents/Resources/empty.lproj CONTENT "") + configure_file(${PROJECT_SOURCE_DIR}/src/qt/res/icons/bitcoin.icns ${macos_app}/Contents/Resources/bitcoin.icns NO_SOURCE_PERMISSIONS COPYONLY) + file(CONFIGURE OUTPUT ${macos_app}/Contents/Resources/Base.lproj/InfoPlist.strings + CONTENT "{ CFBundleDisplayName = \"@PACKAGE_NAME@\"; CFBundleName = \"@PACKAGE_NAME@\"; }" + ) + + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt + COMMAND ${CMAKE_COMMAND} --install ${PROJECT_BINARY_DIR} --config $<CONFIG> --component GUI --prefix ${macos_app}/Contents/MacOS --strip + COMMAND ${CMAKE_COMMAND} -E rename ${macos_app}/Contents/MacOS/bin/$<TARGET_FILE_NAME:bitcoin-qt> ${macos_app}/Contents/MacOS/Bitcoin-Qt + COMMAND ${CMAKE_COMMAND} -E rm -rf ${macos_app}/Contents/MacOS/bin + VERBATIM + ) + + string(REPLACE " " "-" osx_volname ${PACKAGE_NAME}) + if(CMAKE_HOST_APPLE) + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/${osx_volname}.zip + COMMAND ${PYTHON_COMMAND} ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} ${osx_volname} -translations-dir=${QT_TRANSLATIONS_DIR} -zip + DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt + VERBATIM + ) + add_custom_target(deploydir + DEPENDS ${PROJECT_BINARY_DIR}/${osx_volname}.zip + ) + add_custom_target(deploy + DEPENDS ${PROJECT_BINARY_DIR}/${osx_volname}.zip + ) + else() + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/dist/${macos_app}/Contents/MacOS/Bitcoin-Qt + COMMAND OBJDUMP=${CMAKE_OBJDUMP} ${PYTHON_COMMAND} ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} ${osx_volname} -translations-dir=${QT_TRANSLATIONS_DIR} + DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt + VERBATIM + ) + add_custom_target(deploydir + DEPENDS ${PROJECT_BINARY_DIR}/dist/${macos_app}/Contents/MacOS/Bitcoin-Qt + ) + + find_program(ZIP_COMMAND zip REQUIRED) + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/dist/${osx_volname}.zip + WORKING_DIRECTORY dist + COMMAND ${PROJECT_SOURCE_DIR}/cmake/script/macos_zip.sh ${ZIP_COMMAND} ${osx_volname}.zip + VERBATIM + ) + add_custom_target(deploy + DEPENDS ${PROJECT_BINARY_DIR}/dist/${osx_volname}.zip + ) + endif() + add_dependencies(deploydir bitcoin-qt) + add_dependencies(deploy deploydir) + endif() +endfunction() diff --git a/cmake/module/ProcessConfigurations.cmake b/cmake/module/ProcessConfigurations.cmake new file mode 100644 index 0000000000..7e2fc0080e --- /dev/null +++ b/cmake/module/ProcessConfigurations.cmake @@ -0,0 +1,175 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) + +include(TryAppendCXXFlags) + +macro(normalize_string string) + string(REGEX REPLACE " +" " " ${string} "${${string}}") + string(STRIP "${${string}}" ${string}) +endmacro() + +function(are_flags_overridden flags_var result_var) + normalize_string(${flags_var}) + normalize_string(${flags_var}_INIT) + if(${flags_var} STREQUAL ${flags_var}_INIT) + set(${result_var} FALSE PARENT_SCOPE) + else() + set(${result_var} TRUE PARENT_SCOPE) + endif() +endfunction() + + +# Removes duplicated flags. The relative order of flags is preserved. +# If duplicates are encountered, only the last instance is preserved. +function(deduplicate_flags flags) + separate_arguments(${flags}) + list(REVERSE ${flags}) + list(REMOVE_DUPLICATES ${flags}) + list(REVERSE ${flags}) + list(JOIN ${flags} " " result) + set(${flags} "${result}" PARENT_SCOPE) +endfunction() + + +function(get_all_configs output) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + set(all_configs ${CMAKE_CONFIGURATION_TYPES}) + else() + get_property(all_configs CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS) + if(NOT all_configs) + # See https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#default-and-custom-configurations + set(all_configs Debug Release RelWithDebInfo MinSizeRel) + endif() + endif() + set(${output} "${all_configs}" PARENT_SCOPE) +endfunction() + + +#[=[ +Set the default build configuration. + +See: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations. + +On single-configuration generators, this function sets the CMAKE_BUILD_TYPE variable to +the default build configuration, which can be overridden by the user at configure time if needed. + +On multi-configuration generators, this function rearranges the CMAKE_CONFIGURATION_TYPES list, +ensuring that the default build configuration appears first while maintaining the order of the +remaining configurations. The user can choose a build configuration at build time. +]=] +function(set_default_config config) + get_all_configs(all_configs) + if(NOT ${config} IN_LIST all_configs) + message(FATAL_ERROR "The default config is \"${config}\", but must be one of ${all_configs}.") + endif() + + list(REMOVE_ITEM all_configs ${config}) + list(PREPEND all_configs ${config}) + + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + get_property(help_string CACHE CMAKE_CONFIGURATION_TYPES PROPERTY HELPSTRING) + set(CMAKE_CONFIGURATION_TYPES "${all_configs}" CACHE STRING "${help_string}" FORCE) + # Also see https://gitlab.kitware.com/cmake/cmake/-/issues/19512. + set(CMAKE_TRY_COMPILE_CONFIGURATION "${config}" PARENT_SCOPE) + else() + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "${all_configs}" + ) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to \"${config}\" as none was specified") + get_property(help_string CACHE CMAKE_BUILD_TYPE PROPERTY HELPSTRING) + set(CMAKE_BUILD_TYPE "${config}" CACHE STRING "${help_string}" FORCE) + endif() + set(CMAKE_TRY_COMPILE_CONFIGURATION "${CMAKE_BUILD_TYPE}" PARENT_SCOPE) + endif() +endfunction() + +function(remove_cxx_flag_from_all_configs flag) + get_all_configs(all_configs) + foreach(config IN LISTS all_configs) + string(TOUPPER "${config}" config_uppercase) + set(flags "${CMAKE_CXX_FLAGS_${config_uppercase}}") + separate_arguments(flags) + list(FILTER flags EXCLUDE REGEX "${flag}") + list(JOIN flags " " new_flags) + set(CMAKE_CXX_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS_${config_uppercase} "${new_flags}" + CACHE STRING + "Flags used by the CXX compiler during ${config_uppercase} builds." + FORCE + ) + endforeach() +endfunction() + +function(replace_cxx_flag_in_config config old_flag new_flag) + string(TOUPPER "${config}" config_uppercase) + string(REGEX REPLACE "(^| )${old_flag}( |$)" "\\1${new_flag}\\2" new_flags "${CMAKE_CXX_FLAGS_${config_uppercase}}") + set(CMAKE_CXX_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS_${config_uppercase} "${new_flags}" + CACHE STRING + "Flags used by the CXX compiler during ${config_uppercase} builds." + FORCE + ) +endfunction() + +set_default_config(RelWithDebInfo) + +# Redefine/adjust per-configuration flags. +target_compile_definitions(core_interface_debug INTERFACE + DEBUG + DEBUG_LOCKORDER + DEBUG_LOCKCONTENTION + RPC_DOC_CHECK + ABORT_ON_FAILED_ASSUME +) +# We leave assertions on. +if(MSVC) + remove_cxx_flag_from_all_configs(/DNDEBUG) +else() + remove_cxx_flag_from_all_configs(-DNDEBUG) + + # Adjust flags used by the CXX compiler during RELEASE builds. + # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) + replace_cxx_flag_in_config(Release -O3 -O2) + + are_flags_overridden(CMAKE_CXX_FLAGS_DEBUG cxx_flags_debug_overridden) + if(NOT cxx_flags_debug_overridden) + # Redefine flags used by the CXX compiler during DEBUG builds. + try_append_cxx_flags("-g3" RESULT_VAR compiler_supports_g3) + if(compiler_supports_g3) + replace_cxx_flag_in_config(Debug -g -g3) + endif() + unset(compiler_supports_g3) + + try_append_cxx_flags("-ftrapv" RESULT_VAR compiler_supports_ftrapv) + if(compiler_supports_ftrapv) + string(PREPEND CMAKE_CXX_FLAGS_DEBUG "-ftrapv ") + endif() + unset(compiler_supports_ftrapv) + + string(PREPEND CMAKE_CXX_FLAGS_DEBUG "-O0 ") + + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}" + CACHE STRING + "Flags used by the CXX compiler during DEBUG builds." + FORCE + ) + endif() + unset(cxx_flags_debug_overridden) +endif() + +set(CMAKE_CXX_FLAGS_COVERAGE "-g -Og --coverage") +set(CMAKE_OBJCXX_FLAGS_COVERAGE "-g -Og --coverage") +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage") +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "--coverage") +get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(is_multi_config) + if(NOT "Coverage" IN_LIST CMAKE_CONFIGURATION_TYPES) + list(APPEND CMAKE_CONFIGURATION_TYPES Coverage) + endif() +endif() diff --git a/cmake/module/TestAppendRequiredLibraries.cmake b/cmake/module/TestAppendRequiredLibraries.cmake new file mode 100644 index 0000000000..5352102c7a --- /dev/null +++ b/cmake/module/TestAppendRequiredLibraries.cmake @@ -0,0 +1,92 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) + +# Illumos/SmartOS requires linking with -lsocket if +# using getifaddrs & freeifaddrs. +# See: +# - https://github.com/bitcoin/bitcoin/pull/21486 +# - https://smartos.org/man/3socket/getifaddrs +function(test_append_socket_library target) + if (NOT TARGET ${target}) + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}() called with non-existent target \"${target}\".") + endif() + + set(check_socket_source " + #include <sys/types.h> + #include <ifaddrs.h> + + int main() { + struct ifaddrs* ifaddr; + getifaddrs(&ifaddr); + freeifaddrs(ifaddr); + } + ") + + include(CheckSourceCompilesAndLinks) + check_cxx_source_links("${check_socket_source}" IFADDR_LINKS_WITHOUT_LIBSOCKET) + if(NOT IFADDR_LINKS_WITHOUT_LIBSOCKET) + check_cxx_source_links_with_libs(socket "${check_socket_source}" IFADDR_NEEDS_LINK_TO_LIBSOCKET) + if(IFADDR_NEEDS_LINK_TO_LIBSOCKET) + target_link_libraries(${target} INTERFACE socket) + else() + message(FATAL_ERROR "Cannot figure out how to use getifaddrs/freeifaddrs.") + endif() + endif() + set(HAVE_DECL_GETIFADDRS TRUE PARENT_SCOPE) + set(HAVE_DECL_FREEIFADDRS TRUE PARENT_SCOPE) +endfunction() + +# Clang, when building for 32-bit, +# and linking against libstdc++, requires linking with +# -latomic if using the C++ atomic library. +# Can be tested with: clang++ -std=c++20 test.cpp -m32 +# +# Sourced from http://bugs.debian.org/797228 +function(test_append_atomic_library target) + if (NOT TARGET ${target}) + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}() called with non-existent target \"${target}\".") + endif() + + set(check_atomic_source " + #include <atomic> + #include <cstdint> + #include <chrono> + + using namespace std::chrono_literals; + + int main() { + std::atomic<bool> lock{true}; + lock.exchange(false); + + std::atomic<std::chrono::seconds> t{0s}; + t.store(2s); + auto t1 = t.load(); + t.compare_exchange_strong(t1, 3s); + + std::atomic<double> d{}; + d.store(3.14); + auto d1 = d.load(); + + std::atomic<int64_t> a{}; + int64_t v = 5; + int64_t r = a.fetch_add(v); + return static_cast<int>(r); + } + ") + + include(CheckSourceCompilesAndLinks) + check_cxx_source_links("${check_atomic_source}" STD_ATOMIC_LINKS_WITHOUT_LIBATOMIC) + if(STD_ATOMIC_LINKS_WITHOUT_LIBATOMIC) + return() + endif() + + check_cxx_source_links_with_libs(atomic "${check_atomic_source}" STD_ATOMIC_NEEDS_LINK_TO_LIBATOMIC) + if(STD_ATOMIC_NEEDS_LINK_TO_LIBATOMIC) + target_link_libraries(${target} INTERFACE atomic) + else() + message(FATAL_ERROR "Cannot figure out how to use std::atomic.") + endif() +endfunction() diff --git a/cmake/module/TryAppendCXXFlags.cmake b/cmake/module/TryAppendCXXFlags.cmake new file mode 100644 index 0000000000..c07455e89e --- /dev/null +++ b/cmake/module/TryAppendCXXFlags.cmake @@ -0,0 +1,125 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) +include(CheckCXXSourceCompiles) + +#[=[ +Add language-wide flags, which will be passed to all invocations of the compiler. +This includes invocations that drive compiling and those that drive linking. + +Usage examples: + + try_append_cxx_flags("-Wformat -Wformat-security" VAR warn_cxx_flags) + + + try_append_cxx_flags("-Wsuggest-override" VAR warn_cxx_flags + SOURCE "struct A { virtual void f(); }; struct B : A { void f() final; };" + ) + + + try_append_cxx_flags("-fsanitize=${SANITIZERS}" TARGET core_interface + RESULT_VAR cxx_supports_sanitizers + ) + if(NOT cxx_supports_sanitizers) + message(FATAL_ERROR "Compiler did not accept requested flags.") + endif() + + + try_append_cxx_flags("-Wunused-parameter" TARGET core_interface + IF_CHECK_PASSED "-Wno-unused-parameter" + ) + + +In configuration output, this function prints a string by the following pattern: + + -- Performing Test CXX_SUPPORTS_[flags] + -- Performing Test CXX_SUPPORTS_[flags] - Success + +]=] +function(try_append_cxx_flags flags) + cmake_parse_arguments(PARSE_ARGV 1 + TACXXF # prefix + "SKIP_LINK" # options + "TARGET;VAR;SOURCE;RESULT_VAR" # one_value_keywords + "IF_CHECK_PASSED" # multi_value_keywords + ) + + set(flags_as_string "${flags}") + separate_arguments(flags) + + string(MAKE_C_IDENTIFIER "${flags_as_string}" id_string) + string(TOUPPER "${id_string}" id_string) + + set(source "int main() { return 0; }") + if(DEFINED TACXXF_SOURCE AND NOT TACXXF_SOURCE STREQUAL source) + set(source "${TACXXF_SOURCE}") + string(SHA256 source_hash "${source}") + string(SUBSTRING ${source_hash} 0 4 source_hash_head) + string(APPEND id_string _${source_hash_head}) + endif() + + # This avoids running a linker. + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + set(CMAKE_REQUIRED_FLAGS "${flags_as_string} ${working_compiler_werror_flag}") + set(compiler_result CXX_SUPPORTS_${id_string}) + check_cxx_source_compiles("${source}" ${compiler_result}) + + if(${compiler_result}) + if(DEFINED TACXXF_IF_CHECK_PASSED) + if(DEFINED TACXXF_TARGET) + target_compile_options(${TACXXF_TARGET} INTERFACE ${TACXXF_IF_CHECK_PASSED}) + endif() + if(DEFINED TACXXF_VAR) + string(STRIP "${${TACXXF_VAR}} ${TACXXF_IF_CHECK_PASSED}" ${TACXXF_VAR}) + endif() + else() + if(DEFINED TACXXF_TARGET) + target_compile_options(${TACXXF_TARGET} INTERFACE ${flags}) + endif() + if(DEFINED TACXXF_VAR) + string(STRIP "${${TACXXF_VAR}} ${flags_as_string}" ${TACXXF_VAR}) + endif() + endif() + endif() + + if(DEFINED TACXXF_VAR) + set(${TACXXF_VAR} "${${TACXXF_VAR}}" PARENT_SCOPE) + endif() + + if(DEFINED TACXXF_RESULT_VAR) + set(${TACXXF_RESULT_VAR} "${${compiler_result}}" PARENT_SCOPE) + endif() + + if(NOT ${compiler_result} OR TACXXF_SKIP_LINK) + return() + endif() + + # This forces running a linker. + set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) + set(CMAKE_REQUIRED_FLAGS "${flags_as_string}") + set(CMAKE_REQUIRED_LINK_OPTIONS ${working_linker_werror_flag}) + set(linker_result LINKER_SUPPORTS_${id_string}) + check_cxx_source_compiles("${source}" ${linker_result}) + + if(${linker_result}) + if(DEFINED TACXXF_IF_CHECK_PASSED) + if(DEFINED TACXXF_TARGET) + target_link_options(${TACXXF_TARGET} INTERFACE ${TACXXF_IF_CHECK_PASSED}) + endif() + else() + if(DEFINED TACXXF_TARGET) + target_link_options(${TACXXF_TARGET} INTERFACE ${flags}) + endif() + endif() + else() + message(WARNING "'${flags_as_string}' fail(s) to link.") + endif() +endfunction() + +if(MSVC) + try_append_cxx_flags("/WX /options:strict" VAR working_compiler_werror_flag SKIP_LINK) +else() + try_append_cxx_flags("-Werror" VAR working_compiler_werror_flag SKIP_LINK) +endif() diff --git a/cmake/module/TryAppendLinkerFlag.cmake b/cmake/module/TryAppendLinkerFlag.cmake new file mode 100644 index 0000000000..8cbd83678d --- /dev/null +++ b/cmake/module/TryAppendLinkerFlag.cmake @@ -0,0 +1,78 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) +include(CheckCXXSourceCompiles) + +#[=[ +Usage example: + + try_append_linker_flag("-Wl,--major-subsystem-version,6" TARGET core_interface) + + +In configuration output, this function prints a string by the following pattern: + + -- Performing Test LINKER_SUPPORTS_[flag] + -- Performing Test LINKER_SUPPORTS_[flag] - Success + +]=] +function(try_append_linker_flag flag) + cmake_parse_arguments(PARSE_ARGV 1 + TALF # prefix + "" # options + "TARGET;VAR;SOURCE;RESULT_VAR" # one_value_keywords + "IF_CHECK_PASSED" # multi_value_keywords + ) + + string(MAKE_C_IDENTIFIER "${flag}" result) + string(TOUPPER "${result}" result) + string(PREPEND result LINKER_SUPPORTS_) + + set(source "int main() { return 0; }") + if(DEFINED TALF_SOURCE AND NOT TALF_SOURCE STREQUAL source) + set(source "${TALF_SOURCE}") + string(SHA256 source_hash "${source}") + string(SUBSTRING ${source_hash} 0 4 source_hash_head) + string(APPEND result _${source_hash_head}) + endif() + + # This forces running a linker. + set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) + set(CMAKE_REQUIRED_LINK_OPTIONS ${flag} ${working_linker_werror_flag}) + check_cxx_source_compiles("${source}" ${result}) + + if(${result}) + if(DEFINED TALF_IF_CHECK_PASSED) + if(DEFINED TALF_TARGET) + target_link_options(${TALF_TARGET} INTERFACE ${TALF_IF_CHECK_PASSED}) + endif() + if(DEFINED TALF_VAR) + string(STRIP "${${TALF_VAR}} ${TALF_IF_CHECK_PASSED}" ${TALF_VAR}) + endif() + else() + if(DEFINED TALF_TARGET) + target_link_options(${TALF_TARGET} INTERFACE ${flag}) + endif() + if(DEFINED TALF_VAR) + string(STRIP "${${TALF_VAR}} ${flag}" ${TALF_VAR}) + endif() + endif() + endif() + + if(DEFINED TALF_VAR) + set(${TALF_VAR} "${${TALF_VAR}}" PARENT_SCOPE) + endif() + + if(DEFINED TALF_RESULT_VAR) + set(${TALF_RESULT_VAR} "${${result}}" PARENT_SCOPE) + endif() +endfunction() + +if(MSVC) + try_append_linker_flag("/WX" VAR working_linker_werror_flag) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + try_append_linker_flag("-Wl,-fatal_warnings" VAR working_linker_werror_flag) +else() + try_append_linker_flag("-Wl,--fatal-warnings" VAR working_linker_werror_flag) +endif() diff --git a/cmake/module/WarnAboutGlobalProperties.cmake b/cmake/module/WarnAboutGlobalProperties.cmake new file mode 100644 index 0000000000..faa56a2a7f --- /dev/null +++ b/cmake/module/WarnAboutGlobalProperties.cmake @@ -0,0 +1,36 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include_guard(GLOBAL) + +# Avoid the directory-wide add_definitions() and add_compile_definitions() commands. +# Instead, prefer the target-specific target_compile_definitions() one. +get_directory_property(global_compile_definitions COMPILE_DEFINITIONS) +if(global_compile_definitions) + message(AUTHOR_WARNING "The directory's COMPILE_DEFINITIONS property is not empty: ${global_compile_definitions}") +endif() + +# Avoid the directory-wide add_compile_options() command. +# Instead, prefer the target-specific target_compile_options() one. +get_directory_property(global_compile_options COMPILE_OPTIONS) +if(global_compile_options) + message(AUTHOR_WARNING "The directory's COMPILE_OPTIONS property is not empty: ${global_compile_options}") +endif() + +# Avoid the directory-wide add_link_options() command. +# Instead, prefer the target-specific target_link_options() one. +get_directory_property(global_link_options LINK_OPTIONS) +if(global_link_options) + message(AUTHOR_WARNING "The directory's LINK_OPTIONS property is not empty: ${global_link_options}") +endif() + +# Avoid the directory-wide link_libraries() command. +# Instead, prefer the target-specific target_link_libraries() one. +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy_cxx_source.cpp "#error") +add_library(check_loose_linked_libraries OBJECT EXCLUDE_FROM_ALL ${CMAKE_CURRENT_BINARY_DIR}/dummy_cxx_source.cpp) +set_target_properties(check_loose_linked_libraries PROPERTIES EXPORT_COMPILE_COMMANDS OFF) +get_target_property(global_linked_libraries check_loose_linked_libraries LINK_LIBRARIES) +if(global_linked_libraries) + message(AUTHOR_WARNING "There are libraries linked with `link_libraries` commands: ${global_linked_libraries}") +endif() diff --git a/cmake/script/Coverage.cmake b/cmake/script/Coverage.cmake new file mode 100644 index 0000000000..72587a5eb6 --- /dev/null +++ b/cmake/script/Coverage.cmake @@ -0,0 +1,89 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include(${CMAKE_CURRENT_LIST_DIR}/CoverageInclude.cmake) + +set(functional_test_runner test/functional/test_runner.py) +if(EXTENDED_FUNCTIONAL_TESTS) + list(APPEND functional_test_runner --extended) +endif() +if(DEFINED JOBS) + list(APPEND CMAKE_CTEST_COMMAND -j ${JOBS}) + list(APPEND functional_test_runner -j ${JOBS}) +endif() + +execute_process( + COMMAND ${CMAKE_CTEST_COMMAND} --build-config Coverage + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --capture --directory src --test-name test_bitcoin --output-file test_bitcoin.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --zerocounters --directory src + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_FILTER_COMMAND} test_bitcoin.info test_bitcoin_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --add-tracefile test_bitcoin_filtered.info --output-file test_bitcoin_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --add-tracefile test_bitcoin_filtered.info --output-file test_bitcoin_coverage.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${GENHTML_COMMAND} test_bitcoin_coverage.info --output-directory test_bitcoin.coverage + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) + +execute_process( + COMMAND ${functional_test_runner} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --capture --directory src --test-name functional-tests --output-file functional_test.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --zerocounters --directory src + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_FILTER_COMMAND} functional_test.info functional_test_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --add-tracefile functional_test_filtered.info --output-file functional_test_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --add-tracefile test_bitcoin_filtered.info --add-tracefile functional_test_filtered.info --output-file total_coverage.info + COMMAND ${GREP_EXECUTABLE} "%" + COMMAND ${AWK_EXECUTABLE} "{ print substr($3,2,50) \"/\" $5 }" + OUTPUT_FILE coverage_percent.txt + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${GENHTML_COMMAND} total_coverage.info --output-directory total.coverage + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) diff --git a/cmake/script/CoverageFuzz.cmake b/cmake/script/CoverageFuzz.cmake new file mode 100644 index 0000000000..0558805394 --- /dev/null +++ b/cmake/script/CoverageFuzz.cmake @@ -0,0 +1,53 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include(${CMAKE_CURRENT_LIST_DIR}/CoverageInclude.cmake) + +if(NOT DEFINED FUZZ_CORPORA_DIR) + set(FUZZ_CORPORA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/qa-assets/fuzz_corpora) +endif() + +set(fuzz_test_runner test/fuzz/test_runner.py ${FUZZ_CORPORA_DIR}) +if(DEFINED JOBS) + list(APPEND fuzz_test_runner -j ${JOBS}) +endif() + +execute_process( + COMMAND ${fuzz_test_runner} --loglevel DEBUG + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --capture --directory src --test-name fuzz-tests --output-file fuzz.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --zerocounters --directory src + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_FILTER_COMMAND} fuzz.info fuzz_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --add-tracefile fuzz_filtered.info --output-file fuzz_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --add-tracefile fuzz_filtered.info --output-file fuzz_coverage.info + COMMAND ${GREP_EXECUTABLE} "%" + COMMAND ${AWK_EXECUTABLE} "{ print substr($3,2,50) \"/\" $5 }" + OUTPUT_FILE coverage_percent.txt + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${GENHTML_COMMAND} fuzz_coverage.info --output-directory fuzz.coverage + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) diff --git a/cmake/script/CoverageInclude.cmake.in b/cmake/script/CoverageInclude.cmake.in new file mode 100644 index 0000000000..59bf5e3af2 --- /dev/null +++ b/cmake/script/CoverageInclude.cmake.in @@ -0,0 +1,59 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +if("@CMAKE_CXX_COMPILER_ID@" STREQUAL "Clang") + find_program(LLVM_COV_EXECUTABLE llvm-cov REQUIRED) + set(COV_TOOL "${LLVM_COV_EXECUTABLE} gcov") +else() + find_program(GCOV_EXECUTABLE gcov REQUIRED) + set(COV_TOOL "${GCOV_EXECUTABLE}") +endif() + +# COV_TOOL is used to replace a placeholder. +configure_file( + cmake/cov_tool_wrapper.sh.in ${CMAKE_CURRENT_LIST_DIR}/cov_tool_wrapper.sh + FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ + @ONLY +) + +find_program(LCOV_EXECUTABLE lcov REQUIRED) +separate_arguments(LCOV_OPTS) +set(LCOV_COMMAND ${LCOV_EXECUTABLE} --gcov-tool ${CMAKE_CURRENT_LIST_DIR}/cov_tool_wrapper.sh ${LCOV_OPTS}) + +find_program(GENHTML_EXECUTABLE genhtml REQUIRED) +set(GENHTML_COMMAND ${GENHTML_EXECUTABLE} --show-details ${LCOV_OPTS}) + +find_program(GREP_EXECUTABLE grep REQUIRED) +find_program(AWK_EXECUTABLE awk REQUIRED) + +set(LCOV_FILTER_COMMAND ./filter-lcov.py) +list(APPEND LCOV_FILTER_COMMAND -p "/usr/local/") +list(APPEND LCOV_FILTER_COMMAND -p "/usr/include/") +list(APPEND LCOV_FILTER_COMMAND -p "/usr/lib/") +list(APPEND LCOV_FILTER_COMMAND -p "/usr/lib64/") +list(APPEND LCOV_FILTER_COMMAND -p "src/leveldb/") +list(APPEND LCOV_FILTER_COMMAND -p "src/crc32c/") +list(APPEND LCOV_FILTER_COMMAND -p "src/bench/") +list(APPEND LCOV_FILTER_COMMAND -p "src/crypto/ctaes") +list(APPEND LCOV_FILTER_COMMAND -p "src/minisketch") +list(APPEND LCOV_FILTER_COMMAND -p "src/secp256k1") +list(APPEND LCOV_FILTER_COMMAND -p "depends") + +execute_process( + COMMAND ${LCOV_COMMAND} --capture --initial --directory src --output-file baseline.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_FILTER_COMMAND} baseline.info baseline_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --output-file baseline_filtered.info + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND_ERROR_IS_FATAL ANY +) diff --git a/cmake/script/GenerateBuildInfo.cmake b/cmake/script/GenerateBuildInfo.cmake new file mode 100644 index 0000000000..d3ee2eb062 --- /dev/null +++ b/cmake/script/GenerateBuildInfo.cmake @@ -0,0 +1,113 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +macro(fatal_error) + message(FATAL_ERROR "\n" + "Usage:\n" + " cmake -D BUILD_INFO_HEADER_PATH=<path> [-D SOURCE_DIR=<path>] -P ${CMAKE_CURRENT_LIST_FILE}\n" + "All specified paths must be absolute ones.\n" + ) +endmacro() + +if(DEFINED BUILD_INFO_HEADER_PATH AND IS_ABSOLUTE "${BUILD_INFO_HEADER_PATH}") + if(EXISTS "${BUILD_INFO_HEADER_PATH}") + file(STRINGS ${BUILD_INFO_HEADER_PATH} INFO LIMIT_COUNT 1) + endif() +else() + fatal_error() +endif() + +if(DEFINED SOURCE_DIR) + if(IS_ABSOLUTE "${SOURCE_DIR}" AND IS_DIRECTORY "${SOURCE_DIR}") + set(WORKING_DIR ${SOURCE_DIR}) + else() + fatal_error() + endif() +else() + set(WORKING_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +set(GIT_TAG) +set(GIT_COMMIT) +if(NOT "$ENV{BITCOIN_GENBUILD_NO_GIT}" STREQUAL "1") + find_package(Git QUIET) + if(Git_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --is-inside-work-tree + WORKING_DIRECTORY ${WORKING_DIR} + OUTPUT_VARIABLE IS_INSIDE_WORK_TREE + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if(IS_INSIDE_WORK_TREE) + # Clean 'dirty' status of touched files that haven't been modified. + execute_process( + COMMAND ${GIT_EXECUTABLE} diff + WORKING_DIRECTORY ${WORKING_DIR} + OUTPUT_QUIET + ERROR_QUIET + ) + + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --abbrev=0 + WORKING_DIRECTORY ${WORKING_DIR} + OUTPUT_VARIABLE MOST_RECENT_TAG + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-list -1 ${MOST_RECENT_TAG} + WORKING_DIRECTORY ${WORKING_DIR} + OUTPUT_VARIABLE MOST_RECENT_TAG_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + WORKING_DIRECTORY ${WORKING_DIR} + OUTPUT_VARIABLE HEAD_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + execute_process( + COMMAND ${GIT_EXECUTABLE} diff-index --quiet HEAD -- + WORKING_DIRECTORY ${WORKING_DIR} + RESULT_VARIABLE IS_DIRTY + ) + + if(HEAD_COMMIT STREQUAL MOST_RECENT_TAG_COMMIT AND NOT IS_DIRTY) + # If latest commit is tagged and not dirty, then use the tag name. + set(GIT_TAG ${MOST_RECENT_TAG}) + else() + # Otherwise, generate suffix from git, i.e. string like "0e0a5173fae3-dirty". + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --short=12 HEAD + WORKING_DIRECTORY ${WORKING_DIR} + OUTPUT_VARIABLE GIT_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if(IS_DIRTY) + string(APPEND GIT_COMMIT "-dirty") + endif() + endif() + endif() + endif() +endif() + +if(GIT_TAG) + set(NEWINFO "#define BUILD_GIT_TAG \"${GIT_TAG}\"") +elseif(GIT_COMMIT) + set(NEWINFO "#define BUILD_GIT_COMMIT \"${GIT_COMMIT}\"") +else() + set(NEWINFO "// No build information available") +endif() + +# Only update the header if necessary. +if(NOT "${INFO}" STREQUAL "${NEWINFO}") + file(WRITE ${BUILD_INFO_HEADER_PATH} "${NEWINFO}\n") +endif() diff --git a/cmake/script/GenerateHeaderFromJson.cmake b/cmake/script/GenerateHeaderFromJson.cmake new file mode 100644 index 0000000000..4a3bddb323 --- /dev/null +++ b/cmake/script/GenerateHeaderFromJson.cmake @@ -0,0 +1,22 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +cmake_path(GET JSON_SOURCE_PATH STEM json_source_basename) + +file(READ ${JSON_SOURCE_PATH} hex_content HEX) +string(REGEX REPLACE "................" "\\0\n" formatted_bytes "${hex_content}") +string(REGEX REPLACE "[^\n][^\n]" "0x\\0, " formatted_bytes "${formatted_bytes}") + +set(header_content +"#include <string_view> + +namespace json_tests { +inline constexpr char detail_${json_source_basename}_bytes[] { +${formatted_bytes} +}; + +inline constexpr std::string_view ${json_source_basename}{std::begin(detail_${json_source_basename}_bytes), std::end(detail_${json_source_basename}_bytes)}; +} +") +file(WRITE ${HEADER_PATH} "${header_content}") diff --git a/cmake/script/GenerateHeaderFromRaw.cmake b/cmake/script/GenerateHeaderFromRaw.cmake new file mode 100644 index 0000000000..638876ecea --- /dev/null +++ b/cmake/script/GenerateHeaderFromRaw.cmake @@ -0,0 +1,23 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +cmake_path(GET RAW_SOURCE_PATH STEM raw_source_basename) + +file(READ ${RAW_SOURCE_PATH} hex_content HEX) +string(REGEX REPLACE "................" "\\0\n" formatted_bytes "${hex_content}") +string(REGEX REPLACE "[^\n][^\n]" "std::byte{0x\\0}, " formatted_bytes "${formatted_bytes}") + +set(header_content +"#include <cstddef> +#include <span> + +namespace ${RAW_NAMESPACE} { +inline constexpr std::byte detail_${raw_source_basename}_raw[] { +${formatted_bytes} +}; + +inline constexpr std::span ${raw_source_basename}{detail_${raw_source_basename}_raw}; +} +") +file(WRITE ${HEADER_PATH} "${header_content}") diff --git a/cmake/script/macos_zip.sh b/cmake/script/macos_zip.sh new file mode 100755 index 0000000000..cc51699dc9 --- /dev/null +++ b/cmake/script/macos_zip.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +export LC_ALL=C + +if [ -n "$SOURCE_DATE_EPOCH" ]; then + find . -exec touch -d "@$SOURCE_DATE_EPOCH" {} + +fi + +find . | sort | "$1" -X@ "$2" diff --git a/cmake/tests.cmake b/cmake/tests.cmake new file mode 100644 index 0000000000..2791329800 --- /dev/null +++ b/cmake/tests.cmake @@ -0,0 +1,15 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +if(TARGET bitcoin-util AND TARGET bitcoin-tx AND PYTHON_COMMAND) + add_test(NAME util_test_runner + COMMAND ${CMAKE_COMMAND} -E env BITCOINUTIL=$<TARGET_FILE:bitcoin-util> BITCOINTX=$<TARGET_FILE:bitcoin-tx> ${PYTHON_COMMAND} ${PROJECT_BINARY_DIR}/test/util/test_runner.py + ) +endif() + +if(PYTHON_COMMAND) + add_test(NAME util_rpcauth_test + COMMAND ${PYTHON_COMMAND} ${PROJECT_BINARY_DIR}/test/util/rpcauth-test.py + ) +endif() diff --git a/configure.ac b/configure.ac deleted file mode 100644 index a1d9e418f8..0000000000 --- a/configure.ac +++ /dev/null @@ -1,1810 +0,0 @@ -AC_PREREQ([2.69]) -define(_CLIENT_VERSION_MAJOR, 27) -define(_CLIENT_VERSION_MINOR, 99) -define(_CLIENT_VERSION_BUILD, 0) -define(_CLIENT_VERSION_RC, 0) -define(_CLIENT_VERSION_IS_RELEASE, false) -define(_COPYRIGHT_YEAR, 2024) -define(_COPYRIGHT_HOLDERS,[The %s developers]) -define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]]) -AC_INIT([Bitcoin Core],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_BUILD)m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/]) -AC_CONFIG_SRCDIR([src/validation.cpp]) -AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux/m4]) - -m4_ifndef([PKG_PROG_PKG_CONFIG], [m4_fatal([PKG_PROG_PKG_CONFIG macro not found. Please install pkg-config and re-run autogen.sh])]) -PKG_PROG_PKG_CONFIG -if test "$PKG_CONFIG" = ""; then - AC_MSG_ERROR([pkg-config not found]) -fi - -# When compiling with depends, the `PKG_CONFIG_PATH` and `PKG_CONFIG_LIBDIR` variables, -# being set in a `config.site` file, are not exported to let the `--config-cache` option -# work properly. -if test -n "$PKG_CONFIG_PATH"; then - PKG_CONFIG="env PKG_CONFIG_PATH=$PKG_CONFIG_PATH $PKG_CONFIG" -fi -if test -n "$PKG_CONFIG_LIBDIR"; then - PKG_CONFIG="env PKG_CONFIG_LIBDIR=$PKG_CONFIG_LIBDIR $PKG_CONFIG" -fi - -BITCOIN_DAEMON_NAME=bitcoind -BITCOIN_GUI_NAME=bitcoin-qt -BITCOIN_TEST_NAME=test_bitcoin -BITCOIN_CLI_NAME=bitcoin-cli -BITCOIN_TX_NAME=bitcoin-tx -BITCOIN_UTIL_NAME=bitcoin-util -BITCOIN_CHAINSTATE_NAME=bitcoin-chainstate -BITCOIN_WALLET_TOOL_NAME=bitcoin-wallet -dnl Multi Process -BITCOIN_MP_NODE_NAME=bitcoin-node -BITCOIN_MP_GUI_NAME=bitcoin-gui - -dnl Unless the user specified ARFLAGS, force it to be cr -dnl This is also the default as-of libtool 2.4.7 -AC_ARG_VAR([ARFLAGS], [Flags for the archiver, defaults to <cr> if not set]) -if test "${ARFLAGS+set}" != "set"; then - ARFLAGS="cr" -fi - -AC_CANONICAL_HOST - -AH_TOP([#ifndef BITCOIN_CONFIG_H]) -AH_TOP([#define BITCOIN_CONFIG_H]) -AH_BOTTOM([#endif //BITCOIN_CONFIG_H]) - -dnl Automake init set-up and checks -AM_INIT_AUTOMAKE([1.13 no-define subdir-objects foreign]) - -AM_MAINTAINER_MODE([enable]) - -dnl make the compilation flags quiet unless V=1 is used -AM_SILENT_RULES([yes]) - -dnl Compiler checks (here before libtool). -if test "${CXXFLAGS+set}" = "set"; then - CXXFLAGS_overridden=yes -else - CXXFLAGS_overridden=no -fi -AC_PROG_CXX - -dnl libtool overrides -case $host in - *mingw*) - dnl By default, libtool for mingw refuses to link static libs into a dll for - dnl fear of mixing pic/non-pic objects, and import/export complications. Since - dnl we have those under control, re-enable that functionality. - lt_cv_deplibs_check_method="pass_all" - - dnl Remove unwanted -DDLL_EXPORT from these variables. - dnl We do not use this macro, but system headers may export unwanted symbols - dnl if it's set. - lt_cv_prog_compiler_pic="-DPIC" - lt_cv_prog_compiler_pic_CXX="-DPIC" - ;; - *darwin*) - dnl Because it prints a verbose warning, lld fails the following check - dnl for "-Wl,-single_module" from libtool.m4: - dnl # If there is a non-empty error log, and "single_module" - dnl # appears in it, assume the flag caused a linker warning - dnl "-single_module" works fine on ld64 and lld, so just bypass the test. - dnl Failure to set this to "yes" causes libtool to use a very broken - dnl link-line for shared libs. - lt_cv_apple_cc_single_mod="yes" - ;; -esac - -dnl Require C++20 compiler (no GNU extensions) -AX_CXX_COMPILE_STDCXX([20], [noext], [mandatory]) - -dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures -dnl that we get the same -std flags for both. -m4_ifdef([AC_PROG_OBJCXX],[ -if test "${OBJCXX+set}" = ""; then - OBJCXX="${CXX}" -fi -AC_PROG_OBJCXX -]) - -dnl OpenBSD ships with 2.4.2 -LT_PREREQ([2.4.2]) -dnl Libtool init checks. -LT_INIT([pic-only win32-dll]) - -dnl Check/return PATH for base programs. -AC_PATH_TOOL([AR], [ar]) -AC_PATH_TOOL([GCOV], [gcov]) -AC_PATH_TOOL([LLVM_COV], [llvm-cov]) -AC_PATH_PROG([LCOV], [lcov]) -dnl The minimum supported version is specified in .python-version and should be used if available, see doc/dependencies.md -AC_PATH_PROGS([PYTHON], [python3.9 python3.10 python3.11 python3.12 python3 python]) -AC_PATH_PROG([GENHTML], [genhtml]) -AC_PATH_PROG([GIT], [git]) -AC_PATH_PROG([CCACHE], [ccache]) -AC_PATH_PROG([XGETTEXT], [xgettext]) -AC_PATH_PROG([HEXDUMP], [hexdump]) -AC_PATH_TOOL([OBJDUMP], [objdump]) -AC_PATH_TOOL([OBJCOPY], [objcopy]) -AC_PATH_PROG([DOXYGEN], [doxygen]) -AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) - -AC_ARG_ENABLE([wallet], - [AS_HELP_STRING([--disable-wallet], - [disable wallet (enabled by default)])], - [enable_wallet=$enableval], - [enable_wallet=auto]) - -AC_ARG_WITH([sqlite], - [AS_HELP_STRING([--with-sqlite=yes|no|auto], - [enable sqlite wallet support (default: auto, i.e., enabled if wallet is enabled and sqlite is found)])], - [use_sqlite=$withval], - [use_sqlite=auto]) - -AC_ARG_WITH([bdb], - [AS_HELP_STRING([--without-bdb], - [disable bdb wallet support (default is enabled if wallet is enabled)])], - [use_bdb=$withval], - [use_bdb=auto]) - -AC_ARG_ENABLE([usdt], - [AS_HELP_STRING([--enable-usdt], - [enable tracepoints for Userspace, Statically Defined Tracing (default is yes if sys/sdt.h is found)])], - [use_usdt=$enableval], - [use_usdt=yes]) - -AC_ARG_WITH([miniupnpc], - [AS_HELP_STRING([--with-miniupnpc], - [enable UPNP (default is yes if libminiupnpc is found)])], - [use_upnp=$withval], - [use_upnp=auto]) - -AC_ARG_WITH([natpmp], - [AS_HELP_STRING([--with-natpmp], - [enable NAT-PMP (default is yes if libnatpmp is found)])], - [use_natpmp=$withval], - [use_natpmp=auto]) - -AC_ARG_ENABLE(tests, - AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]), - [use_tests=$enableval], - [use_tests=yes]) - -AC_ARG_ENABLE(gui-tests, - AS_HELP_STRING([--disable-gui-tests],[do not compile GUI tests (default is to compile if GUI and tests enabled)]), - [use_gui_tests=$enableval], - [use_gui_tests=$use_tests]) - -AC_ARG_ENABLE(bench, - AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]), - [use_bench=$enableval], - [use_bench=yes]) - -AC_ARG_ENABLE([extended-functional-tests], - AS_HELP_STRING([--enable-extended-functional-tests],[enable expensive functional tests when using lcov (default no)]), - [use_extended_functional_tests=$enableval], - [use_extended_functional_tests=no]) - -AC_ARG_ENABLE([fuzz], - AS_HELP_STRING([--enable-fuzz], - [build for fuzzing (default no). enabling this will disable all other targets and override --{enable,disable}-fuzz-binary]), - [enable_fuzz=$enableval], - [enable_fuzz=no]) - -AC_ARG_ENABLE([fuzz-binary], - AS_HELP_STRING([--enable-fuzz-binary], - [enable building of fuzz binary (default yes).]), - [enable_fuzz_binary=$enableval], - [enable_fuzz_binary=yes]) - -AC_ARG_WITH([qrencode], - [AS_HELP_STRING([--with-qrencode], - [enable QR code support (default is yes if qt is enabled and libqrencode is found)])], - [use_qr=$withval], - [use_qr=auto]) - -AC_ARG_ENABLE([hardening], - [AS_HELP_STRING([--disable-hardening], - [do not attempt to harden the resulting executables (default is to harden when possible)])], - [use_hardening=$enableval], - [use_hardening=auto]) - -AC_ARG_ENABLE([reduce-exports], - [AS_HELP_STRING([--enable-reduce-exports], - [attempt to reduce exported symbols in the resulting executables (default is no)])], - [use_reduce_exports=$enableval], - [use_reduce_exports=no]) - -AC_ARG_ENABLE([ccache], - [AS_HELP_STRING([--disable-ccache], - [do not use ccache for building (default is to use if found)])], - [use_ccache=$enableval], - [use_ccache=auto]) - -dnl Suppress warnings from external headers (e.g. Boost, Qt). -dnl May be useful if warnings from external headers clutter the build output -dnl too much, so that it becomes difficult to spot Bitcoin Core warnings -dnl or if they cause a build failure with --enable-werror. -AC_ARG_ENABLE([suppress-external-warnings], - [AS_HELP_STRING([--disable-suppress-external-warnings], - [Do not suppress warnings from external headers (default is to suppress)])], - [suppress_external_warnings=$enableval], - [suppress_external_warnings=yes]) - -AC_ARG_ENABLE([lcov], - [AS_HELP_STRING([--enable-lcov], - [enable lcov testing (default is no)])], - [use_lcov=$enableval], - [use_lcov=no]) - -AC_ARG_ENABLE([zmq], - [AS_HELP_STRING([--disable-zmq], - [disable ZMQ notifications])], - [use_zmq=$enableval], - [use_zmq=yes]) - -AC_ARG_WITH([libmultiprocess], - [AS_HELP_STRING([--with-libmultiprocess=yes|no|auto], - [Build with libmultiprocess library. (default: auto, i.e. detect with pkg-config)])], - [with_libmultiprocess=$withval], - [with_libmultiprocess=auto]) - -AC_ARG_WITH([mpgen], - [AS_HELP_STRING([--with-mpgen=yes|no|auto|PREFIX], - [Build with libmultiprocess codegen tool. Useful to specify different libmultiprocess host system library and build system codegen tool prefixes when cross-compiling (default is host system libmultiprocess prefix)])], - [with_mpgen=$withval], - [with_mpgen=auto]) - -AC_ARG_ENABLE([multiprocess], - [AS_HELP_STRING([--enable-multiprocess], - [build multiprocess bitcoin-node, bitcoin-wallet, and bitcoin-gui executables in addition to monolithic bitcoind and bitcoin-qt executables. Requires libmultiprocess library. Experimental (default is no)])], - [enable_multiprocess=$enableval], - [enable_multiprocess=no]) - -AC_ARG_ENABLE(man, - [AS_HELP_STRING([--disable-man], - [do not install man pages (default is to install)])],, - enable_man=yes) -AM_CONDITIONAL([ENABLE_MAN], [test "$enable_man" != "no"]) - -dnl Enable debug -AC_ARG_ENABLE([debug], - [AS_HELP_STRING([--enable-debug], - [use compiler flags and macros suited for debugging (default is no)])], - [enable_debug=$enableval], - [enable_debug=no]) - -dnl Enable different -fsanitize options -AC_ARG_WITH([sanitizers], - [AS_HELP_STRING([--with-sanitizers], - [comma separated list of extra sanitizers to build with (default is none enabled)])], - [use_sanitizers=$withval]) - -dnl Enable gprof profiling -AC_ARG_ENABLE([gprof], - [AS_HELP_STRING([--enable-gprof], - [use gprof profiling compiler flags (default is no)])], - [enable_gprof=$enableval], - [enable_gprof=no]) - -dnl Turn warnings into errors -AC_ARG_ENABLE([werror], - [AS_HELP_STRING([--enable-werror], - [Treat compiler warnings as errors (default is no)])], - [enable_werror=$enableval], - [enable_werror=no]) - -AC_ARG_ENABLE([external-signer], - [AS_HELP_STRING([--enable-external-signer],[compile external signer support (default is yes)])], - [use_external_signer=$enableval], - [use_external_signer=yes]) - -AC_LANG_PUSH([C++]) - -dnl Always set -g -O2 in our CXXFLAGS. Autoconf will try and set CXXFLAGS to "-g -O2" by default, -dnl so we suppress that (if CXXFLAGS hasn't been overridden by the user), given we are adding it -dnl ourselves. -CORE_CXXFLAGS="$CORE_CXXFLAGS -g -O2" - -if test "$CXXFLAGS_overridden" = "no"; then - CXXFLAGS="" -fi - -dnl Check for a flag to turn compiler warnings into errors. This is helpful for checks which may -dnl appear to succeed because by default they merely emit warnings when they fail. -dnl -dnl Note that this is not necessarily a check to see if -Werror is supported, but rather to see if -dnl a compile with -Werror can succeed. This is important because the compiler may already be -dnl warning about something unrelated, for example about some path issue. If that is the case, -dnl -Werror cannot be used because all of those warnings would be turned into errors. -AX_CHECK_COMPILE_FLAG([-Werror], [CXXFLAG_WERROR="-Werror"], [CXXFLAG_WERROR=""]) - -dnl Check for a flag to turn linker warnings into errors. When flags are passed to linkers via the -dnl compiler driver using a -Wl,-foo flag, linker warnings may be swallowed rather than bubbling up. -dnl See note above, the same applies here as well. -dnl -dnl LDFLAG_WERROR Should only be used when testing -Wl,* -case $host in - *darwin*) - AX_CHECK_LINK_FLAG([-Wl,-fatal_warnings], [LDFLAG_WERROR="-Wl,-fatal_warnings"], [LDFLAG_WERROR=""]) - ;; - *) - AX_CHECK_LINK_FLAG([-Wl,--fatal-warnings], [LDFLAG_WERROR="-Wl,--fatal-warnings"], [LDFLAG_WERROR=""]) - ;; -esac - -if test "$enable_debug" = "yes"; then - - dnl Disable all optimizations - AX_CHECK_COMPILE_FLAG([-O0], [DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -O0"], [], [$CXXFLAG_WERROR]) - - dnl Prefer -g3, fall back to -g if that is unavailable. - AX_CHECK_COMPILE_FLAG( - [-g3], - [DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -g3"], - [AX_CHECK_COMPILE_FLAG([-g], [DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -g"], [], [$CXXFLAG_WERROR])], - [$CXXFLAG_WERROR]) - - AX_CHECK_PREPROC_FLAG([-DDEBUG], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG"], [], [$CXXFLAG_WERROR]) - AX_CHECK_PREPROC_FLAG([-DDEBUG_LOCKORDER], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG_LOCKORDER"], [], [$CXXFLAG_WERROR]) - AX_CHECK_PREPROC_FLAG([-DDEBUG_LOCKCONTENTION], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG_LOCKCONTENTION"], [], [$CXXFLAG_WERROR]) - AX_CHECK_PREPROC_FLAG([-DRPC_DOC_CHECK], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DRPC_DOC_CHECK"], [], [$CXXFLAG_WERROR]) - AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"], [], [$CXXFLAG_WERROR]) - AX_CHECK_COMPILE_FLAG([-ftrapv], [DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -ftrapv"], [], [$CXXFLAG_WERROR]) -fi - -if test "$use_sanitizers" != ""; then - dnl First check if the compiler accepts flags. If an incompatible pair like - dnl -fsanitize=address,thread is used here, this check will fail. This will also - dnl fail if a bad argument is passed, e.g. -fsanitize=undfeined - AX_CHECK_COMPILE_FLAG( - [-fsanitize=$use_sanitizers], - [SANITIZER_CXXFLAGS="-fsanitize=$use_sanitizers" - SANITIZER_CFLAGS="-fsanitize=$use_sanitizers"], - [AC_MSG_ERROR([compiler did not accept requested flags])]) - - dnl Some compilers (e.g. GCC) require additional libraries like libasan, - dnl libtsan, libubsan, etc. Make sure linking still works with the sanitize - dnl flag. This is a separate check so we can give a better error message when - dnl the sanitize flags are supported by the compiler but the actual sanitizer - dnl libs are missing. - AX_CHECK_LINK_FLAG( - [-fsanitize=$use_sanitizers], - [SANITIZER_LDFLAGS="-fsanitize=$use_sanitizers"], - [AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])], - [], - [AC_LANG_PROGRAM([[ - #include <cstdint> - #include <cstddef> - extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { return 0; } - __attribute__((weak)) // allow for libFuzzer linking - ]],[[]])]) -fi - -ERROR_CXXFLAGS= -if test "$enable_werror" = "yes"; then - if test "$CXXFLAG_WERROR" = ""; then - AC_MSG_ERROR([enable-werror set but -Werror is not usable]) - fi - ERROR_CXXFLAGS=$CXXFLAG_WERROR -fi - -AX_CHECK_COMPILE_FLAG([-Wall], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wall"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wextra], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wextra"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wgnu], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wgnu"], [], [$CXXFLAG_WERROR]) -dnl some compilers will ignore -Wformat-security without -Wformat, so just combine the two here. -AX_CHECK_COMPILE_FLAG([-Wformat -Wformat-security], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat -Wformat-security"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wvla], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wvla"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wshadow-field], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wshadow-field"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wthread-safety], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wloop-analysis], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wloop-analysis"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wredundant-decls], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wredundant-decls"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wunused-member-function], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunused-member-function"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wdate-time], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wdate-time"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wconditional-uninitialized], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wconditional-uninitialized"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wduplicated-branches], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wduplicated-branches"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wduplicated-cond], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wduplicated-cond"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wlogical-op], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wlogical-op"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Woverloaded-virtual], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Woverloaded-virtual"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wsuggest-override], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wsuggest-override"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wimplicit-fallthrough"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wunreachable-code], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunreachable-code"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wdocumentation], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wdocumentation"], [], [$CXXFLAG_WERROR]) - -dnl Some compilers (gcc) ignore unknown -Wno-* options, but warn about all -dnl unknown options if any other warning is produced. Test the -Wfoo case, and -dnl set the -Wno-foo case if it works. -AX_CHECK_COMPILE_FLAG([-Wunused-parameter], [NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-parameter"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-Wself-assign], [NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-self-assign"], [], [$CXXFLAG_WERROR]) - -dnl Don't allow extended (non-ASCII) symbols in identifiers. This is easier for code review. -AX_CHECK_COMPILE_FLAG([-fno-extended-identifiers], [CORE_CXXFLAGS="$CORE_CXXFLAGS -fno-extended-identifiers"], [], [$CXXFLAG_WERROR]) - -dnl Currently all versions of gcc are subject to a class of bugs, see the -dnl gccbug_90348 test case (only reproduces on GCC 11 and earlier) and -dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111843. To work around that, set -dnl -fstack-reuse=none for all gcc builds. (Only gcc understands this flag) -AX_CHECK_COMPILE_FLAG([-fstack-reuse=none], [CORE_CXXFLAGS="$CORE_CXXFLAGS -fstack-reuse=none"]) - -enable_arm_crc=no -enable_arm_shani=no -enable_sse42=no -enable_sse41=no -enable_avx2=no -enable_x86_shani=no - -dnl Check for optional instruction set support. Enabling these does _not_ imply that all code will -dnl be compiled with them, rather that specific objects/libs may use them after checking for runtime -dnl compatibility. - -dnl x86 -AX_CHECK_COMPILE_FLAG([-msse4.2], [SSE42_CXXFLAGS="-msse4.2"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-msse4.1], [SSE41_CXXFLAGS="-msse4.1"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-mavx -mavx2], [AVX2_CXXFLAGS="-mavx -mavx2"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-msse4 -msha], [X86_SHANI_CXXFLAGS="-msse4 -msha"], [], [$CXXFLAG_WERROR]) - -enable_clmul= -AX_CHECK_COMPILE_FLAG([-mpclmul], [enable_clmul=yes], [], [$CXXFLAG_WERROR], [AC_LANG_PROGRAM([ - #include <stdint.h> - #include <x86intrin.h> -], [ - __m128i a = _mm_cvtsi64_si128((uint64_t)7); - __m128i b = _mm_clmulepi64_si128(a, a, 37); - __m128i c = _mm_srli_epi64(b, 41); - __m128i d = _mm_xor_si128(b, c); - uint64_t e = _mm_cvtsi128_si64(d); - return e == 0; -])]) - -if test "$enable_clmul" = "yes"; then - CLMUL_CXXFLAGS="-mpclmul" - AC_DEFINE([HAVE_CLMUL], [1], [Define this symbol if clmul instructions can be used]) -fi - -TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$SSE42_CXXFLAGS $CXXFLAGS" -AC_MSG_CHECKING([for SSE4.2 intrinsics]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <stdint.h> - #if defined(_MSC_VER) - #include <intrin.h> - #elif defined(__GNUC__) && defined(__SSE4_2__) - #include <nmmintrin.h> - #endif - ]],[[ - uint64_t l = 0; - l = _mm_crc32_u8(l, 0); - l = _mm_crc32_u32(l, 0); - l = _mm_crc32_u64(l, 0); - return l; - ]])], - [ AC_MSG_RESULT([yes]); enable_sse42=yes], - [ AC_MSG_RESULT([no])] -) -CXXFLAGS="$TEMP_CXXFLAGS" - -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); - ]])], - [ 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])] -) -CXXFLAGS="$TEMP_CXXFLAGS" - -TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$AVX2_CXXFLAGS $CXXFLAGS" -AC_MSG_CHECKING([for AVX2 intrinsics]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <stdint.h> - #include <immintrin.h> - ]],[[ - __m256i l = _mm256_set1_epi32(0); - return _mm256_extract_epi32(l, 7); - ]])], - [ AC_MSG_RESULT([yes]); enable_avx2=yes; AC_DEFINE([ENABLE_AVX2], [1], [Define this symbol to build code that uses AVX2 intrinsics]) ], - [ AC_MSG_RESULT([no])] -) -CXXFLAGS="$TEMP_CXXFLAGS" - -TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$X86_SHANI_CXXFLAGS $CXXFLAGS" -AC_MSG_CHECKING([for x86 SHA-NI intrinsics]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <stdint.h> - #include <immintrin.h> - ]],[[ - __m128i i = _mm_set1_epi32(0); - __m128i j = _mm_set1_epi32(1); - __m128i k = _mm_set1_epi32(2); - return _mm_extract_epi32(_mm_sha256rnds2_epu32(i, i, k), 0); - ]])], - [ AC_MSG_RESULT([yes]); enable_x86_shani=yes; AC_DEFINE([ENABLE_X86_SHANI], [1], [Define this symbol to build code that uses x86 SHA-NI intrinsics]) ], - [ AC_MSG_RESULT([no])] -) -CXXFLAGS="$TEMP_CXXFLAGS" - -# ARM -AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-march=armv8-a+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crypto"], [], [$CXXFLAG_WERROR]) - -TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$ARM_CRC_CXXFLAGS $CXXFLAGS" -AC_MSG_CHECKING([for ARMv8 CRC32 intrinsics]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <arm_acle.h> - #include <arm_neon.h> - ]],[[ -#ifdef __aarch64__ - __crc32cb(0, 0); __crc32ch(0, 0); __crc32cw(0, 0); __crc32cd(0, 0); - vmull_p64(0, 0); -#else -#error "crc32c library does not support hardware acceleration on 32-bit ARM" -#endif - ]])], - [ AC_MSG_RESULT([yes]); enable_arm_crc=yes; ], - [ AC_MSG_RESULT([no])] -) -CXXFLAGS="$TEMP_CXXFLAGS" - -TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$ARM_SHANI_CXXFLAGS $CXXFLAGS" -AC_MSG_CHECKING([for ARMv8 SHA-NI intrinsics]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <arm_acle.h> - #include <arm_neon.h> - ]],[[ - uint32x4_t a, b, c; - vsha256h2q_u32(a, b, c); - vsha256hq_u32(a, b, c); - vsha256su0q_u32(a, b); - vsha256su1q_u32(a, b, c); - ]])], - [ AC_MSG_RESULT([yes]); enable_arm_shani=yes; AC_DEFINE([ENABLE_ARM_SHANI], [1], [Define this symbol to build code that uses ARMv8 SHA-NI intrinsics]) ], - [ AC_MSG_RESULT([no])] -) -CXXFLAGS="$TEMP_CXXFLAGS" - -CORE_CPPFLAGS="$CORE_CPPFLAGS -DHAVE_BUILD_INFO" - -AC_ARG_WITH([utils], - [AS_HELP_STRING([--with-utils], - [build bitcoin-cli bitcoin-tx bitcoin-util bitcoin-wallet (default=yes)])], - [build_bitcoin_utils=$withval], - [build_bitcoin_utils=yes]) - -AC_ARG_ENABLE([util-cli], - [AS_HELP_STRING([--enable-util-cli], - [build bitcoin-cli])], - [build_bitcoin_cli=$enableval], - [build_bitcoin_cli=$build_bitcoin_utils]) - -AC_ARG_ENABLE([util-tx], - [AS_HELP_STRING([--enable-util-tx], - [build bitcoin-tx])], - [build_bitcoin_tx=$enableval], - [build_bitcoin_tx=$build_bitcoin_utils]) - -AC_ARG_ENABLE([util-wallet], - [AS_HELP_STRING([--enable-util-wallet], - [build bitcoin-wallet])], - [build_bitcoin_wallet=$enableval], - [build_bitcoin_wallet=$build_bitcoin_utils]) - -AC_ARG_ENABLE([util-util], - [AS_HELP_STRING([--enable-util-util], - [build bitcoin-util])], - [build_bitcoin_util=$enableval], - [build_bitcoin_util=$build_bitcoin_utils]) - -AC_ARG_ENABLE([experimental-util-chainstate], - [AS_HELP_STRING([--enable-experimental-util-chainstate], - [build experimental bitcoin-chainstate executable (default=no)])], - [build_bitcoin_chainstate=$enableval], - [build_bitcoin_chainstate=no]) - -AC_ARG_WITH([experimental-kernel-lib], - [AS_HELP_STRING([--with-experimental-kernel-lib], - [build experimental bitcoinkernel library (default is to build if we're building the experimental build-chainstate executable)])], - [build_experimental_kernel_lib=$withval], - [build_experimental_kernel_lib=auto]) - -AC_ARG_WITH([daemon], - [AS_HELP_STRING([--with-daemon], - [build bitcoind daemon (default=yes)])], - [build_bitcoind=$withval], - [build_bitcoind=yes]) - -case $host in - *mingw*) - TARGET_OS=windows - AC_CHECK_LIB([kernel32], [GetModuleFileNameA], [], [AC_MSG_ERROR([libkernel32 missing])]) - AC_CHECK_LIB([user32], [main], [], [AC_MSG_ERROR([libuser32 missing])]) - AC_CHECK_LIB([gdi32], [main], [], [AC_MSG_ERROR([libgdi32 missing])]) - AC_CHECK_LIB([comdlg32], [main], [], [AC_MSG_ERROR([libcomdlg32 missing])]) - AC_CHECK_LIB([winmm], [main], [], [AC_MSG_ERROR([libwinmm missing])]) - AC_CHECK_LIB([shell32], [SHGetSpecialFolderPathW], [], [AC_MSG_ERROR([libshell32 missing])]) - AC_CHECK_LIB([comctl32], [main], [], [AC_MSG_ERROR([libcomctl32 missing])]) - AC_CHECK_LIB([ole32], [CoCreateInstance], [], [AC_MSG_ERROR([libole32 missing])]) - AC_CHECK_LIB([oleaut32], [main], [], [AC_MSG_ERROR([liboleaut32 missing])]) - AC_CHECK_LIB([uuid], [main], [], [AC_MSG_ERROR([libuuid missing])]) - AC_CHECK_LIB([advapi32], [CryptAcquireContextW], [], [AC_MSG_ERROR([libadvapi32 missing])]) - AC_CHECK_LIB([ws2_32], [WSAStartup], [], [AC_MSG_ERROR([libws2_32 missing])]) - AC_CHECK_LIB([shlwapi], [PathRemoveFileSpecW], [], [AC_MSG_ERROR([libshlwapi missing])]) - AC_CHECK_LIB([iphlpapi], [GetAdaptersAddresses], [], [AC_MSG_ERROR([libiphlpapi missing])]) - - dnl -static is interpreted by libtool, where it has a different meaning. - dnl In libtool-speak, it's -all-static. - AX_CHECK_LINK_FLAG([-static], [LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"]) - - AC_PATH_PROG([MAKENSIS], [makensis], [none]) - if test "$MAKENSIS" = "none"; then - AC_MSG_WARN([makensis not found. Cannot create installer.]) - fi - - AC_PATH_TOOL([WINDRES], [windres], [none]) - if test "$WINDRES" = "none"; then - AC_MSG_ERROR([windres not found]) - fi - - CORE_CPPFLAGS="$CORE_CPPFLAGS -DSECP256K1_STATIC" - - CORE_CPPFLAGS="$CORE_CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -D_WIN32_WINNT=0x0601 -D_WIN32_IE=0x0501 -DWIN32_LEAN_AND_MEAN" - dnl Prevent the definition of min/max macros. - dnl We always want to use the standard library. - CORE_CPPFLAGS="$CORE_CPPFLAGS -DNOMINMAX" - - dnl libtool insists upon adding -nostdlib and a list of objects/libs to link against. - dnl That breaks our ability to build dll's with static libgcc/libstdc++/libssp. Override - dnl its command here, with the predeps/postdeps removed, and -static inserted. Postdeps are - dnl also overridden to prevent their insertion later. - dnl This should only affect dll's. - archive_cmds_CXX="\$CC -shared \$libobjs \$deplibs \$compiler_flags -static -o \$output_objdir/\$soname \${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker \$lib" - postdeps_CXX= - - dnl We require Windows 7 (NT 6.1) or later - AX_CHECK_LINK_FLAG([-Wl,--major-subsystem-version -Wl,6 -Wl,--minor-subsystem-version -Wl,1], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,--major-subsystem-version -Wl,6 -Wl,--minor-subsystem-version -Wl,1"], [], [$LDFLAG_WERROR]) - - dnl Avoid the use of aligned vector instructions when building for Windows. - dnl See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412. - AX_CHECK_COMPILE_FLAG([-Wa,-muse-unaligned-vector-move], [CORE_CXXFLAGS="$CORE_CXXFLAGS -Wa,-muse-unaligned-vector-move"], [], [$CXXFLAG_WERROR]) - ;; - *darwin*) - TARGET_OS=darwin - if test $cross_compiling != "yes"; then - BUILD_OS=darwin - - AX_CHECK_LINK_FLAG([-Wl,-headerpad_max_install_names], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,-headerpad_max_install_names"], [], [$LDFLAG_WERROR]) - - AC_CHECK_PROG([BREW], [brew], [brew]) - if test "$BREW" = "brew"; then - dnl These Homebrew packages may be keg-only, meaning that they won't be found - dnl in expected paths because they may conflict with system files. Ask - dnl Homebrew where each one is located, then adjust paths accordingly. - dnl It's safe to add these paths even if the functionality is disabled by - dnl the user (--without-wallet or --without-gui for example). - - dnl Homebrew may create symlinks in /usr/local/include for some packages. - dnl Because MacOS's clang internally adds "-I /usr/local/include" to its search - dnl paths, this will negate efforts to use -isystem for those packages, as they - dnl will be found first in /usr/local. Use the internal "-internal-isystem" - dnl option to system-ify all /usr/local/include paths without adding it to the list - dnl of search paths in case it's not already there. - if test "$suppress_external_warnings" != "no"; then - AX_CHECK_PREPROC_FLAG([-Xclang -internal-isystem -Xclang /usr/local/include/], [CORE_CPPFLAGS="$CORE_CPPFLAGS -Xclang -internal-isystem -Xclang /usr/local/include/"], [], [$CXXFLAG_WERROR]) - fi - - if test "$use_bdb" != "no" && $BREW list --versions berkeley-db@4 >/dev/null && test "$BDB_CFLAGS" = "" && test "$BDB_LIBS" = ""; then - bdb_prefix=$($BREW --prefix berkeley-db@4 2>/dev/null) - dnl This must precede the call to BITCOIN_FIND_BDB48 below. - BDB_CFLAGS="-I$bdb_prefix/include" - BDB_LIBS="-L$bdb_prefix/lib -ldb_cxx-4.8" - fi - - if $BREW list --versions qt@5 >/dev/null; then - export PKG_CONFIG_PATH="$($BREW --prefix qt@5 2>/dev/null)/lib/pkgconfig:$PKG_CONFIG_PATH" - fi - - case $host in - *aarch64*) - dnl The preferred Homebrew prefix for Apple Silicon is /opt/homebrew. - dnl Therefore, as we do not use pkg-config to detect miniupnpc and libnatpmp - dnl packages, we should set the CPPFLAGS and LDFLAGS variables for them - dnl explicitly. - if test "$use_upnp" != "no" && $BREW list --versions miniupnpc >/dev/null; then - miniupnpc_prefix=$($BREW --prefix miniupnpc 2>/dev/null) - if test "$suppress_external_warnings" != "no"; then - MINIUPNPC_CPPFLAGS="-isystem $miniupnpc_prefix/include" - else - MINIUPNPC_CPPFLAGS="-I$miniupnpc_prefix/include" - fi - MINIUPNPC_LIBS="-L$miniupnpc_prefix/lib" - fi - if test "$use_natpmp" != "no" && $BREW list --versions libnatpmp >/dev/null; then - libnatpmp_prefix=$($BREW --prefix libnatpmp 2>/dev/null) - if test "$suppress_external_warnings" != "no"; then - NATPMP_CPPFLAGS="-isystem $libnatpmp_prefix/include" - else - NATPMP_CPPFLAGS="-I$libnatpmp_prefix/include" - fi - NATPMP_LIBS="-L$libnatpmp_prefix/lib" - fi - ;; - esac - fi - else - case $build_os in - *darwin*) - BUILD_OS=darwin - ;; - *) - AC_PATH_TOOL([DSYMUTIL], [dsymutil], [dsymutil]) - AC_PATH_PROG([ZIP], [zip], [zip]) - - dnl libtool will try to strip the static lib, which is a problem for - dnl cross-builds because strip attempts to call a hard-coded ld, - dnl which may not exist in the path. Stripping the .a is not - dnl necessary, so just disable it. - old_striplib= - ;; - esac - fi - - CORE_CPPFLAGS="$CORE_CPPFLAGS -DMAC_OSX -DOBJC_OLD_DISPATCH_PROTOTYPES=0" - - dnl ignore deprecated-declarations warnings coming from objcxx code - dnl "'NSUserNotificationCenter' is deprecated: first deprecated in macOS 11.0". - OBJCXXFLAGS="$CXXFLAGS -Wno-deprecated-declarations" - ;; - *linux*) - TARGET_OS=linux - ;; -esac - -if test "$use_extended_functional_tests" != "no"; then - AC_SUBST(EXTENDED_FUNCTIONAL_TESTS, --extended) -fi - -if test "$use_lcov" = "yes"; then - if test "$LCOV" = ""; then - AC_MSG_ERROR([lcov testing requested but lcov not found]) - fi - if test "$PYTHON" = ""; then - AC_MSG_ERROR([lcov testing requested but python not found]) - fi - if test "$GENHTML" = ""; then - AC_MSG_ERROR([lcov testing requested but genhtml not found]) - fi - - AC_MSG_CHECKING([whether compiler is Clang]) - AC_PREPROC_IFELSE([AC_LANG_SOURCE([[ - #if defined(__clang__) && defined(__llvm__) - // Compiler is Clang - #else - # error Compiler is not Clang - #endif - ]])],[ - AC_MSG_RESULT([yes]) - if test "$LLVM_COV" = ""; then - AC_MSG_ERROR([lcov testing requested but llvm-cov not found]) - fi - COV_TOOL="$LLVM_COV gcov" - ],[ - AC_MSG_RESULT([no]) - if test "$GCOV" = "x"; then - AC_MSG_ERROR([lcov testing requested but gcov not found]) - fi - COV_TOOL="$GCOV" - ]) - AC_SUBST(COV_TOOL) - AC_SUBST(COV_TOOL_WRAPPER, "cov_tool_wrapper.sh") - LCOV="$LCOV --gcov-tool $(pwd)/$COV_TOOL_WRAPPER" - - AX_CHECK_LINK_FLAG([--coverage], [CORE_LDFLAGS="$CORE_LDFLAGS --coverage"], - [AC_MSG_ERROR([lcov testing requested but --coverage linker flag does not work])]) - AX_CHECK_COMPILE_FLAG([--coverage],[CORE_CXXFLAGS="$CORE_CXXFLAGS --coverage"], - [AC_MSG_ERROR([lcov testing requested but --coverage flag does not work])]) - CORE_CXXFLAGS="$CORE_CXXFLAGS -Og" - - AC_SUBST(LCOV_OPTS) -fi - -dnl Check for endianness -AC_C_BIGENDIAN - -dnl Check for pthread compile/link requirements -AX_PTHREAD - -dnl Check if -latomic is required for <std::atomic> -CHECK_ATOMIC - -dnl The following macro will add the necessary defines to bitcoin-config.h, but -dnl they also need to be passed down to any subprojects. Pull the results out of -dnl the cache and add them to CPPFLAGS. -AC_SYS_LARGEFILE -dnl detect POSIX or GNU variant of strerror_r -AC_FUNC_STRERROR_R - -if test "$ac_cv_sys_file_offset_bits" != "" && - test "$ac_cv_sys_file_offset_bits" != "no" && - test "$ac_cv_sys_file_offset_bits" != "unknown"; then - CORE_CPPFLAGS="$CORE_CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" -fi - -if test "$ac_cv_sys_large_files" != "" && - test "$ac_cv_sys_large_files" != "no" && - test "$ac_cv_sys_large_files" != "unknown"; then - CORE_CPPFLAGS="$CORE_CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files" -fi - -if test "$enable_gprof" = "yes"; then - dnl -pg is incompatible with -pie. Since hardening and profiling together doesn't make sense, - dnl we simply make them mutually exclusive here. Additionally, hardened toolchains may force - dnl -pie by default, in which case it needs to be turned off with -no-pie. - - if test "$use_hardening" = "yes"; then - AC_MSG_ERROR([gprof profiling is not compatible with hardening. Reconfigure with --disable-hardening or --disable-gprof]) - fi - use_hardening=no - AX_CHECK_COMPILE_FLAG([-pg],[GPROF_CXXFLAGS="-pg"], - [AC_MSG_ERROR([gprof profiling requested but not available])], [$CXXFLAG_WERROR]) - - AX_CHECK_LINK_FLAG([-no-pie], [GPROF_LDFLAGS="-no-pie"]) - AX_CHECK_LINK_FLAG([-pg], [GPROF_LDFLAGS="$GPROF_LDFLAGS -pg"], - [AC_MSG_ERROR([gprof profiling requested but not available])], [$GPROF_LDFLAGS]) -fi - -if test "$TARGET_OS" != "windows"; then - dnl All windows code is PIC, forcing it on just adds useless compile warnings - AX_CHECK_COMPILE_FLAG([-fPIC], [PIC_FLAGS="-fPIC"]) -fi - -if test "$use_hardening" != "no"; then - use_hardening=yes - AX_CHECK_COMPILE_FLAG([-Wstack-protector], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"]) - AX_CHECK_COMPILE_FLAG([-fstack-protector-all], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"]) - - AX_CHECK_COMPILE_FLAG([-fcf-protection=full], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fcf-protection=full"]) - - case $host in - *mingw*) - dnl stack-clash-protection doesn't compile with GCC 10 and earlier. - dnl In any case, it is a no-op for Windows. - dnl See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90458 for more details. - ;; - *) - AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-clash-protection"], [], [$CXXFLAG_WERROR]) - ;; - esac - - case $host in - *aarch64*) - AX_CHECK_COMPILE_FLAG([-mbranch-protection=bti], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -mbranch-protection=bti"]) - ;; - esac - - dnl When enable_debug is yes, all optimizations are disabled. - dnl However, FORTIFY_SOURCE requires that there is some level of optimization, otherwise it does nothing and just creates a compiler warning. - dnl Since FORTIFY_SOURCE is a no-op without optimizations, do not enable it when enable_debug is yes. - if test "$enable_debug" != "yes"; then - AX_CHECK_PREPROC_FLAG([-D_FORTIFY_SOURCE=3],[ - AX_CHECK_PREPROC_FLAG([-U_FORTIFY_SOURCE],[ - HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -U_FORTIFY_SOURCE" - ]) - HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -D_FORTIFY_SOURCE=3" - ]) - fi - - AX_CHECK_LINK_FLAG([-Wl,--enable-reloc-section], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--enable-reloc-section"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,--dynamicbase], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--dynamicbase"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,--nxcompat], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--nxcompat"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,--high-entropy-va], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--high-entropy-va"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,-z,relro], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,-z,now], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,-z,separate-code], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,separate-code"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-fPIE -pie], [PIE_FLAGS="-fPIE"; HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"], [], [$CXXFLAG_WERROR]) -fi - -dnl These flags are specific to ld64, and may cause issues with other linkers. -dnl For example: GNU ld will interpret -dead_strip as -de and then try and use -dnl "ad_strip" as the symbol for the entry point. -if test "$TARGET_OS" = "darwin"; then - AX_CHECK_LINK_FLAG([-Wl,-dead_strip], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,-dead_strip"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,-dead_strip_dylibs], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,-dead_strip_dylibs"], [], [$LDFLAG_WERROR]) - AX_CHECK_LINK_FLAG([-Wl,-fixup_chains], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-fixup_chains"], [], [$LDFLAG_WERROR]) -fi - -AC_CHECK_HEADERS([sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h]) - -AC_CHECK_DECLS([getifaddrs, freeifaddrs],[CHECK_SOCKET],, - [#include <sys/types.h> - #include <ifaddrs.h>] -) - -dnl These are used for daemonization in bitcoind -AC_CHECK_DECLS([fork]) -AC_CHECK_DECLS([setsid]) - -AC_CHECK_DECLS([pipe2]) - -dnl Check for malloc_info (for memory statistics information in getmemoryinfo) -AC_MSG_CHECKING([for getmemoryinfo]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]], - [[ int f = malloc_info(0, NULL); ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_MALLOC_INFO], [1], [Define this symbol if you have malloc_info]) ], - [ AC_MSG_RESULT([no])] -) - -dnl Check for mallopt(M_ARENA_MAX) (to set glibc arenas) -AC_MSG_CHECKING([for mallopt M_ARENA_MAX]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]], - [[ mallopt(M_ARENA_MAX, 1); ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_MALLOPT_ARENA_MAX], [1], [Define this symbol if you have mallopt with M_ARENA_MAX]) ], - [ AC_MSG_RESULT([no])] -) - -dnl Check for posix_fallocate -AC_MSG_CHECKING([for posix_fallocate]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - // same as in src/util/fs_helpers.cpp - #ifdef __linux__ - #ifdef _POSIX_C_SOURCE - #undef _POSIX_C_SOURCE - #endif - #define _POSIX_C_SOURCE 200112L - #endif // __linux__ - #include <fcntl.h>]], - [[ int f = posix_fallocate(0, 0, 0); ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_POSIX_FALLOCATE], [1], [Define this symbol if you have posix_fallocate]) ], - [ 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([[ - #include <sys/random.h>]], - [[ getrandom(nullptr, 32, 0); ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GETRANDOM], [1], [Define this symbol if the Linux getrandom function call is available]) ], - [ AC_MSG_RESULT([no])] -) - -AC_MSG_CHECKING([for getentropy via sys/random.h]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <sys/random.h>]], - [[ getentropy(nullptr, 32) ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GETENTROPY_RAND], [1], [Define this symbol if the BSD getentropy system call is available with sys/random.h]) ], - [ AC_MSG_RESULT([no])] -) - -AC_MSG_CHECKING([for sysctl]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h> - #include <sys/sysctl.h>]], - [[ #ifdef __linux__ - #error "Don't use sysctl on Linux, it's deprecated even when it works" - #endif - sysctl(nullptr, 2, nullptr, nullptr, nullptr, 0); ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_SYSCTL], [1], [Define this symbol if the BSD sysctl() is available]) ], - [ AC_MSG_RESULT([no])] -) - -AC_MSG_CHECKING([for sysctl KERN_ARND]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h> - #include <sys/sysctl.h>]], - [[ #ifdef __linux__ - #error "Don't use sysctl on Linux, it's deprecated even when it works" - #endif - static int name[2] = {CTL_KERN, KERN_ARND}; - sysctl(name, 2, nullptr, nullptr, nullptr, 0); ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_SYSCTL_ARND], [1], [Define this symbol if the BSD sysctl(KERN_ARND) is available]) ], - [ AC_MSG_RESULT([no])] -) - -AC_MSG_CHECKING([for fdatasync]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]], - [[ fdatasync(0); ]])], - [ AC_MSG_RESULT([yes]); HAVE_FDATASYNC=1 ], - [ AC_MSG_RESULT([no]); HAVE_FDATASYNC=0 ] -) -AC_DEFINE_UNQUOTED([HAVE_FDATASYNC], [$HAVE_FDATASYNC], [Define to 1 if fdatasync is available.]) - -AC_MSG_CHECKING([for F_FULLFSYNC]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <fcntl.h>]], - [[ fcntl(0, F_FULLFSYNC, 0); ]])], - [ AC_MSG_RESULT([yes]); HAVE_FULLFSYNC=1 ], - [ AC_MSG_RESULT([no]); HAVE_FULLFSYNC=0 ] -) - -AC_MSG_CHECKING([for O_CLOEXEC]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <fcntl.h>]], - [[ open("", O_CLOEXEC); ]])], - [ AC_MSG_RESULT([yes]); HAVE_O_CLOEXEC=1 ], - [ AC_MSG_RESULT([no]); HAVE_O_CLOEXEC=0 ] -) -AC_DEFINE_UNQUOTED([HAVE_O_CLOEXEC], [$HAVE_O_CLOEXEC], [Define to 1 if O_CLOEXEC flag is available.]) - -dnl crc32c platform checks -AC_MSG_CHECKING([for __builtin_prefetch]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ - char data = 0; - const char* address = &data; - __builtin_prefetch(address, 0, 0); - ]])], - [ AC_MSG_RESULT([yes]); HAVE_BUILTIN_PREFETCH=1 ], - [ AC_MSG_RESULT([no]); HAVE_BUILTIN_PREFETCH=0 ] -) - -AC_MSG_CHECKING([for _mm_prefetch]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <xmmintrin.h>]], [[ - char data = 0; - const char* address = &data; - _mm_prefetch(address, _MM_HINT_NTA); - ]])], - [ AC_MSG_RESULT([yes]); HAVE_MM_PREFETCH=1 ], - [ AC_MSG_RESULT([no]); HAVE_MM_PREFETCH=0 ] -) - -AC_MSG_CHECKING([for strong getauxval support in the system headers]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <sys/auxv.h> - ]], [[ - getauxval(AT_HWCAP); - ]])], - [ AC_MSG_RESULT([yes]); HAVE_STRONG_GETAUXVAL=1; AC_DEFINE([HAVE_STRONG_GETAUXVAL], [1], [Define this symbol to build code that uses getauxval]) ], - [ AC_MSG_RESULT([no]); HAVE_STRONG_GETAUXVAL=0 ] -) - -# Check for UNIX sockets -AC_MSG_CHECKING(for sockaddr_un) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <sys/socket.h> - #include <sys/un.h> - ]], [[ - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_SOCKADDR_UN], [1], [Define this symbol if platform supports unix domain sockets]) ], - [ AC_MSG_RESULT([no]); ] -) - -have_any_system=no -AC_MSG_CHECKING([for std::system]) -AC_LINK_IFELSE( - [ AC_LANG_PROGRAM( - [[ #include <cstdlib> ]], - [[ int nErr = std::system(""); ]] - )], - [ AC_MSG_RESULT([yes]); have_any_system=yes], - [ AC_MSG_RESULT([no]) ] -) - -AC_MSG_CHECKING([for ::_wsystem]) -AC_LINK_IFELSE( - [ AC_LANG_PROGRAM( - [[ #include <stdlib.h> ]], - [[ int nErr = ::_wsystem(NULL); ]] - )], - [ AC_MSG_RESULT([yes]); have_any_system=yes], - [ AC_MSG_RESULT([no]) ] -) - -if test "$have_any_system" != "no"; then - AC_DEFINE([HAVE_SYSTEM], [1], [Define to 1 if std::system or ::wsystem is available.]) -fi - -dnl SUPPRESSED_CPPFLAGS=SUPPRESS_WARNINGS([$SOME_CPPFLAGS]) -dnl Replace -I with -isystem in $SOME_CPPFLAGS to suppress warnings from -dnl headers from its include directories and return the result. -dnl See -isystem documentation: -dnl https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html -dnl https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-isystem-directory -dnl Do not change "-I/usr/include" to "-isystem /usr/include" because that -dnl is not necessary (/usr/include is already a system directory) and because -dnl it would break GCC's #include_next. -AC_DEFUN([SUPPRESS_WARNINGS], - [[$(echo $1 |${SED} -E -e 's/(^| )-I/\1-isystem /g' -e 's;-isystem /usr/include/*( |$);-I/usr/include\1;g')]]) - -dnl enable-fuzz should disable all other targets -if test "$enable_fuzz" = "yes"; then - AC_MSG_WARN([enable-fuzz will disable all other targets and force --enable-fuzz-binary=yes]) - build_bitcoin_utils=no - build_bitcoin_cli=no - build_bitcoin_tx=no - build_bitcoin_util=no - build_bitcoin_chainstate=no - build_bitcoin_wallet=no - build_bitcoind=no - bitcoin_enable_qt=no - bitcoin_enable_qt_test=no - bitcoin_enable_qt_dbus=no - use_bench=no - use_tests=no - use_external_signer=no - use_upnp=no - use_natpmp=no - use_zmq=no - enable_fuzz_binary=yes - - AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"], [], [$CXXFLAG_WERROR]) -else - BITCOIN_QT_INIT - - dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus - BITCOIN_QT_CONFIGURE([5.11.3]) - - dnl Keep a copy of the original $QT_INCLUDES and use it when invoking qt's moc - QT_INCLUDES_UNSUPPRESSED=$QT_INCLUDES - if test "$suppress_external_warnings" != "no" ; then - QT_INCLUDES=SUPPRESS_WARNINGS($QT_INCLUDES) - QT_DBUS_INCLUDES=SUPPRESS_WARNINGS($QT_DBUS_INCLUDES) - QT_TEST_INCLUDES=SUPPRESS_WARNINGS($QT_TEST_INCLUDES) - fi -fi - -if test "$enable_fuzz_binary" = "yes"; then - AC_MSG_CHECKING([whether main function is needed for fuzz binary]) - AX_CHECK_LINK_FLAG( - [], - [AC_MSG_RESULT([no])], - [AC_MSG_RESULT([yes]); CORE_CPPFLAGS="$CORE_CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"], - [$SANITIZER_LDFLAGS], - [AC_LANG_PROGRAM([[ - #include <cstdint> - #include <cstddef> - extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } - /* comment to remove the main function ... - ]],[[ - */ int not_main() { - ]])]) -fi - -if test "$enable_wallet" != "no"; then - dnl Check for libdb_cxx only if wallet enabled - if test "$use_bdb" != "no"; then - BITCOIN_FIND_BDB48 - if test "$suppress_external_warnings" != "no" ; then - BDB_CPPFLAGS=SUPPRESS_WARNINGS($BDB_CPPFLAGS) - fi - fi - - dnl Check for sqlite3 - if test "$use_sqlite" != "no"; then - PKG_CHECK_MODULES([SQLITE], [sqlite3 >= 3.7.17], [have_sqlite=yes], [have_sqlite=no]) - fi - AC_MSG_CHECKING([whether to build wallet with support for sqlite]) - if test "$use_sqlite" = "no"; then - use_sqlite=no - elif test "$have_sqlite" = "no"; then - if test "$use_sqlite" = "yes"; then - AC_MSG_ERROR([sqlite support requested but cannot be built. Use --without-sqlite]) - fi - use_sqlite=no - else - if test "$use_sqlite" != "no"; then - AC_DEFINE([USE_SQLITE],[1],[Define if sqlite support should be compiled in]) - use_sqlite=yes - fi - fi - AC_MSG_RESULT([$use_sqlite]) - - dnl Disable wallet if both --without-bdb and --without-sqlite - if test "$use_bdb$use_sqlite" = "nono"; then - if test "$enable_wallet" = "yes"; then - AC_MSG_ERROR([wallet functionality requested but no BDB or SQLite support available.]) - fi - enable_wallet=no - fi -fi - -if test "$use_usdt" != "no"; then - AC_MSG_CHECKING([whether Userspace, Statically Defined Tracing tracepoints are supported]) - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM( - [#include <sys/sdt.h>], - [DTRACE_PROBE(context, event); - int a, b, c, d, e, f, g; - DTRACE_PROBE7(context, event, a, b, c, d, e, f, g);] - )], - [AC_MSG_RESULT([yes]); AC_DEFINE([ENABLE_TRACING], [1], [Define to 1 to enable tracepoints for Userspace, Statically Defined Tracing])], - [AC_MSG_RESULT([no]); use_usdt=no;] - ) -fi -AM_CONDITIONAL([ENABLE_USDT_TRACEPOINTS], [test "$use_usdt" = "yes"]) - -if test "$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests" = "nononono"; then - use_upnp=no - use_natpmp=no - use_zmq=no -fi - -dnl Check for libminiupnpc (optional) -if test "$use_upnp" != "no"; then - TEMP_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $MINIUPNPC_CPPFLAGS" - AC_CHECK_HEADERS([miniupnpc/miniupnpc.h miniupnpc/upnpcommands.h miniupnpc/upnperrors.h], [], [have_miniupnpc=no]) - - if test "$have_miniupnpc" != "no"; then - AC_CHECK_LIB([miniupnpc], [upnpDiscover], [MINIUPNPC_LIBS="$MINIUPNPC_LIBS -lminiupnpc"], [have_miniupnpc=no], [$MINIUPNPC_LIBS]) - - dnl The minimum supported miniUPnPc API version is set to 17. This excludes - dnl versions with known vulnerabilities. - AC_MSG_CHECKING([whether miniUPnPc API version is supported]) - AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[ - @%:@include <miniupnpc/miniupnpc.h> - ]], [[ - #if MINIUPNPC_API_VERSION >= 17 - // Everything is okay - #else - # error miniUPnPc API version is too old - #endif - ]])],[ - AC_MSG_RESULT([yes]) - ],[ - AC_MSG_RESULT([no]) - AC_MSG_WARN([miniUPnPc API version < 17 is unsupported, disabling UPnP support.]) - have_miniupnpc=no - ]) - fi - CPPFLAGS="$TEMP_CPPFLAGS" -fi - -dnl Check for libnatpmp (optional). -if test "$use_natpmp" != "no"; then - TEMP_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $NATPMP_CPPFLAGS" - AC_CHECK_HEADERS([natpmp.h], [], [have_natpmp=no]) - - if test "$have_natpmp" != "no"; then - AC_CHECK_LIB([natpmp], [initnatpmp], [NATPMP_LIBS="$NATPMP_LIBS -lnatpmp"], [have_natpmp=no], [$NATPMP_LIBS]) - fi - - CPPFLAGS="$TEMP_CPPFLAGS" -fi - -if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench$enable_fuzz_binary" = "nonononononononono"; then - use_boost=no -else - use_boost=yes -fi - -if test "$use_boost" = "yes"; then - - dnl Check for Boost headers - AX_BOOST_BASE([1.73.0],[],[AC_MSG_ERROR([Boost is not available!])]) - if test "$want_boost" = "no"; then - AC_MSG_ERROR([Boost is required]) - fi - - dnl we don't use multi_index serialization - BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION" - - dnl Prevent use of std::unary_function, which was removed in C++17, - dnl and will generate warnings with newer compilers for Boost - dnl older than 1.80. - dnl See: https://github.com/boostorg/config/pull/430. - AX_CHECK_PREPROC_FLAG([-DBOOST_NO_CXX98_FUNCTION_BASE], [BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_CXX98_FUNCTION_BASE"], [], [$CXXFLAG_WERROR], - [AC_LANG_PROGRAM([[#include <boost/config.hpp>]])]) - - if test "$suppress_external_warnings" != "no"; then - BOOST_CPPFLAGS=SUPPRESS_WARNINGS($BOOST_CPPFLAGS) - fi -fi - -case $host in - dnl Re-enable it after enabling Windows support in cpp-subprocess. - *mingw*) - use_external_signer="no" - ;; -esac -if test "$use_external_signer" = "yes"; then - AC_DEFINE([ENABLE_EXTERNAL_SIGNER], [1], [Define if external signer support is enabled]) -fi -AM_CONDITIONAL([ENABLE_EXTERNAL_SIGNER], [test "$use_external_signer" = "yes"]) - -dnl Check for reduced exports -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]) -fi - -if test "$use_tests" = "yes"; then - - if test "$HEXDUMP" = ""; then - AC_MSG_ERROR([hexdump is required for tests]) - fi -fi - -dnl libevent check - -use_libevent=no -if test "$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_tests$use_bench" != "nononononono"; then - PKG_CHECK_MODULES([EVENT], [libevent >= 2.1.8], [use_libevent=yes], [AC_MSG_ERROR([libevent version 2.1.8 or greater not found.])]) - if test "$TARGET_OS" != "windows"; then - PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads >= 2.1.8], [], [AC_MSG_ERROR([libevent_pthreads version 2.1.8 or greater not found.])]) - fi - - if test "$suppress_external_warnings" != "no"; then - EVENT_CFLAGS=SUPPRESS_WARNINGS($EVENT_CFLAGS) - fi -fi - -if test x$use_libevent = xyes; then - TEMP_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $EVENT_CFLAGS" - AC_MSG_CHECKING([if evhttp_connection_get_peer expects const char**]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <cstdint> - #include <event2/http.h> - ]], [[ - evhttp_connection *conn = (evhttp_connection *)1; - const char *host; - uint16_t port; - - evhttp_connection_get_peer(conn, &host, &port); - ]])], - [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR], [1], [Define this symbol if evhttp_connection_get_peer expects const char**]) ], - [ AC_MSG_RESULT([no]) ] - ) - CXXFLAGS="$TEMP_CXXFLAGS" -fi - -dnl QR Code encoding library check - -if test "$use_qr" != "no"; then - BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) -fi - -dnl ZMQ check - -if test "$use_zmq" = "yes"; then - PKG_CHECK_MODULES([ZMQ], [libzmq >= 4], - AC_DEFINE([ENABLE_ZMQ], [1], [Define this symbol to enable ZMQ functions]), - [AC_MSG_WARN([libzmq version 4.x or greater not found, disabling]) - use_zmq=no]) -fi - -if test "$use_zmq" = "yes"; then - dnl Assume libzmq was built for static linking - case $host in - *mingw*) - ZMQ_CFLAGS="$ZMQ_CFLAGS -DZMQ_STATIC" - ;; - esac -fi - -AM_CONDITIONAL([ENABLE_ZMQ], [test "$use_zmq" = "yes"]) - -dnl libmultiprocess library check - -libmultiprocess_found=no -if test "$with_libmultiprocess" = "yes" || test "$with_libmultiprocess" = "auto"; then - PKG_CHECK_MODULES([LIBMULTIPROCESS], [libmultiprocess], [ - libmultiprocess_found=yes; - libmultiprocess_prefix=`$PKG_CONFIG --variable=prefix libmultiprocess`; - ], [true]) -elif test "$with_libmultiprocess" != "no"; then - AC_MSG_ERROR([--with-libmultiprocess=$with_libmultiprocess value is not yes, auto, or no]) -fi - -dnl Enable multiprocess check - -if test "$enable_multiprocess" = "yes"; then - if test "$libmultiprocess_found" != "yes"; then - AC_MSG_ERROR([--enable-multiprocess=yes option specified but libmultiprocess library was not found. May need to install libmultiprocess library, or specify install path with PKG_CONFIG_PATH environment variable. Running 'pkg-config --debug libmultiprocess' may be helpful for debugging.]) - fi - build_multiprocess=yes -elif test "$enable_multiprocess" = "auto"; then - build_multiprocess=$libmultiprocess_found -else - build_multiprocess=no -fi - -AM_CONDITIONAL([BUILD_MULTIPROCESS], [test "$build_multiprocess" = "yes"]) -AM_CONDITIONAL([BUILD_BITCOIN_NODE], [test "$build_multiprocess" = "yes"]) -AM_CONDITIONAL([BUILD_BITCOIN_GUI], [test "$build_multiprocess" = "yes"]) - -dnl codegen tools check - -if test "$build_multiprocess" != "no"; then - if test "$with_mpgen" = "yes" || test "$with_mpgen" = "auto"; then - MPGEN_PREFIX="$libmultiprocess_prefix" - elif test "$with_mpgen" != "no"; then - MPGEN_PREFIX="$with_mpgen"; - fi - AC_SUBST(MPGEN_PREFIX) -fi - -AC_MSG_CHECKING([whether to build bitcoind]) -AM_CONDITIONAL([BUILD_BITCOIND], [test $build_bitcoind = "yes"]) -AC_MSG_RESULT($build_bitcoind) - -AC_MSG_CHECKING([whether to build bitcoin-cli]) -AM_CONDITIONAL([BUILD_BITCOIN_CLI], [test $build_bitcoin_cli = "yes"]) -AC_MSG_RESULT($build_bitcoin_cli) - -AC_MSG_CHECKING([whether to build bitcoin-tx]) -AM_CONDITIONAL([BUILD_BITCOIN_TX], [test $build_bitcoin_tx = "yes"]) -AC_MSG_RESULT($build_bitcoin_tx) - -AC_MSG_CHECKING([whether to build bitcoin-wallet]) -AM_CONDITIONAL([BUILD_BITCOIN_WALLET], [test $build_bitcoin_wallet = "yes"]) -AC_MSG_RESULT($build_bitcoin_wallet) - -AC_MSG_CHECKING([whether to build bitcoin-util]) -AM_CONDITIONAL([BUILD_BITCOIN_UTIL], [test $build_bitcoin_util = "yes"]) -AC_MSG_RESULT($build_bitcoin_util) - -AC_MSG_CHECKING([whether to build experimental bitcoin-chainstate]) -if test "$build_bitcoin_chainstate" = "yes"; then - if test "$build_experimental_kernel_lib" = "no"; then - AC_MSG_ERROR([experimental bitcoin-chainstate cannot be built without the experimental bitcoinkernel library. Use --with-experimental-kernel-lib]); - fi -fi -AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"]) -AC_MSG_RESULT($build_bitcoin_chainstate) - -AM_CONDITIONAL([BUILD_BITCOIN_KERNEL_LIB], [test "$build_experimental_kernel_lib" != "no" && ( test "$build_experimental_kernel_lib" = "yes" || test "$build_bitcoin_chainstate" = "yes" )]) - -AC_LANG_POP - -if test "$use_ccache" != "no"; then - AC_MSG_CHECKING([if ccache should be used]) - if test "$CCACHE" = ""; then - if test "$use_ccache" = "yes"; then - AC_MSG_ERROR([ccache not found.]); - else - use_ccache=no - fi - else - use_ccache=yes - CC="$ac_cv_path_CCACHE $CC" - CXX="$ac_cv_path_CCACHE $CXX" - fi - AC_MSG_RESULT($use_ccache) - if test "$use_ccache" = "yes"; then - AX_CHECK_COMPILE_FLAG([-fdebug-prefix-map=A=B], [DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -fdebug-prefix-map=\$(abs_top_srcdir)=."], [], [$CXXFLAG_WERROR]) - AX_CHECK_PREPROC_FLAG([-fmacro-prefix-map=A=B], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -fmacro-prefix-map=\$(abs_top_srcdir)=."], [], [$CXXFLAG_WERROR]) - fi -fi - -dnl enable wallet -AC_MSG_CHECKING([if wallet should be enabled]) -if test "$enable_wallet" != "no"; then - AC_MSG_RESULT([yes]) - AC_DEFINE_UNQUOTED([ENABLE_WALLET],[1],[Define to 1 to enable wallet functions]) - enable_wallet=yes - -else - AC_MSG_RESULT([no]) -fi - -dnl enable upnp support -AC_MSG_CHECKING([whether to build with support for UPnP]) -if test "$have_miniupnpc" = "no"; then - if test "$use_upnp" = "yes"; then - AC_MSG_ERROR([UPnP requested but cannot be built. Use --without-miniupnpc]) - fi - AC_MSG_RESULT([no]) - use_upnp=no -else - if test "$use_upnp" != "no"; then - AC_MSG_RESULT([yes]) - use_upnp=yes - AC_DEFINE([USE_UPNP], [1], [Define to 1 if UPnP support should be compiled in.]) - if test "$TARGET_OS" = "windows"; then - MINIUPNPC_CPPFLAGS="$MINIUPNPC_CPPFLAGS -DMINIUPNP_STATICLIB" - fi - else - AC_MSG_RESULT([no]) - fi -fi - -dnl Enable NAT-PMP support. -AC_MSG_CHECKING([whether to build with support for NAT-PMP]) -if test "$have_natpmp" = "no"; then - if test "$use_natpmp" = "yes"; then - AC_MSG_ERROR([NAT-PMP requested but cannot be built. Use --without-natpmp]) - fi - AC_MSG_RESULT([no]) - use_natpmp=no -else - if test "$use_natpmp" != "no"; then - AC_MSG_RESULT([yes]) - use_natpmp=yes - AC_DEFINE([USE_NATPMP], [1], [Define to 1 if UPnP support should be compiled in.]) - if test "$TARGET_OS" = "windows"; then - NATPMP_CPPFLAGS="$NATPMP_CPPFLAGS -DSTATICLIB -DNATPMP_STATICLIB" - fi - else - AC_MSG_RESULT([no]) - fi -fi - -dnl these are only used when qt is enabled -BUILD_TEST_QT="" -if test "$bitcoin_enable_qt" != "no"; then - dnl enable dbus support - AC_MSG_CHECKING([whether to build GUI with support for D-Bus]) - if test "$bitcoin_enable_qt_dbus" != "no"; then - AC_DEFINE([USE_DBUS], [1], [Define if dbus support should be compiled in]) - fi - AC_MSG_RESULT([$bitcoin_enable_qt_dbus]) - - dnl enable qr support - AC_MSG_CHECKING([whether to build GUI with support for QR codes]) - if test "$have_qrencode" = "no"; then - if test "$use_qr" = "yes"; then - AC_MSG_ERROR([QR support requested but cannot be built. Use --without-qrencode]) - fi - use_qr=no - else - if test "$use_qr" != "no"; then - AC_DEFINE([USE_QRCODE], [1], [Define if QR support should be compiled in]) - use_qr=yes - fi - fi - AC_MSG_RESULT([$use_qr]) - - if test "$XGETTEXT" = ""; then - AC_MSG_WARN([xgettext is required to update qt translations]) - fi - - AC_MSG_CHECKING([whether to build test_bitcoin-qt]) - if test "$use_gui_tests$bitcoin_enable_qt_test" = "yesyes"; then - AC_MSG_RESULT([yes]) - BUILD_TEST_QT="yes" - else - AC_MSG_RESULT([no]) - fi -fi - -AC_MSG_CHECKING([whether to build test_bitcoin]) -if test "$use_tests" = "yes"; then - if test "$enable_fuzz" = "yes"; then - AC_MSG_RESULT([no, because fuzzing is enabled]) - else - AC_MSG_RESULT([yes]) - fi - BUILD_TEST="yes" -else - AC_MSG_RESULT([no]) - BUILD_TEST="" -fi - -AC_MSG_CHECKING([whether to reduce exports]) -if test "$use_reduce_exports" = "yes"; then - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - -if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nonononononononono"; then - AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests]) -fi - -AM_CONDITIONAL([TARGET_DARWIN], [test "$TARGET_OS" = "darwin"]) -AM_CONDITIONAL([BUILD_DARWIN], [test "$BUILD_OS" = "darwin"]) -AM_CONDITIONAL([TARGET_LINUX], [test "$TARGET_OS" = "linux"]) -AM_CONDITIONAL([TARGET_WINDOWS], [test "$TARGET_OS" = "windows"]) -AM_CONDITIONAL([ENABLE_WALLET], [test "$enable_wallet" = "yes"]) -AM_CONDITIONAL([USE_SQLITE], [test "$use_sqlite" = "yes"]) -AM_CONDITIONAL([USE_BDB], [test "$use_bdb" = "yes"]) -AM_CONDITIONAL([ENABLE_TESTS], [test "$BUILD_TEST" = "yes"]) -AM_CONDITIONAL([ENABLE_FUZZ], [test "$enable_fuzz" = "yes"]) -AM_CONDITIONAL([ENABLE_FUZZ_BINARY], [test "$enable_fuzz_binary" = "yes"]) -AM_CONDITIONAL([ENABLE_QT], [test "$bitcoin_enable_qt" = "yes"]) -AM_CONDITIONAL([ENABLE_QT_TESTS], [test "$BUILD_TEST_QT" = "yes"]) -AM_CONDITIONAL([ENABLE_BENCH], [test "$use_bench" = "yes"]) -AM_CONDITIONAL([USE_QRCODE], [test "$use_qr" = "yes"]) -AM_CONDITIONAL([USE_LCOV], [test "$use_lcov" = "yes"]) -AM_CONDITIONAL([HARDEN], [test "$use_hardening" = "yes"]) -AM_CONDITIONAL([ENABLE_SSE42], [test "$enable_sse42" = "yes"]) -AM_CONDITIONAL([ENABLE_SSE41], [test "$enable_sse41" = "yes"]) -AM_CONDITIONAL([ENABLE_AVX2], [test "$enable_avx2" = "yes"]) -AM_CONDITIONAL([ENABLE_X86_SHANI], [test "$enable_x86_shani" = "yes"]) -AM_CONDITIONAL([ENABLE_ARM_CRC], [test "$enable_arm_crc" = "yes"]) -AM_CONDITIONAL([ENABLE_ARM_SHANI], [test "$enable_arm_shani" = "yes"]) -AM_CONDITIONAL([WORDS_BIGENDIAN], [test "$ac_cv_c_bigendian" = "yes"]) -AM_CONDITIONAL([USE_NATPMP], [test "$use_natpmp" = "yes"]) -AM_CONDITIONAL([USE_UPNP], [test "$use_upnp" = "yes"]) - -dnl for minisketch -AM_CONDITIONAL([ENABLE_CLMUL], [test "$enable_clmul" = "yes"]) - -AC_DEFINE([CLIENT_VERSION_MAJOR], [_CLIENT_VERSION_MAJOR], [Major version]) -AC_DEFINE([CLIENT_VERSION_MINOR], [_CLIENT_VERSION_MINOR], [Minor version]) -AC_DEFINE([CLIENT_VERSION_BUILD], [_CLIENT_VERSION_BUILD], [Version Build]) -AC_DEFINE([CLIENT_VERSION_IS_RELEASE], [_CLIENT_VERSION_IS_RELEASE], [Version is release]) -AC_DEFINE([COPYRIGHT_YEAR], [_COPYRIGHT_YEAR], [Copyright year]) -AC_DEFINE([COPYRIGHT_HOLDERS], ["_COPYRIGHT_HOLDERS"], [Copyright holder(s) before %s replacement]) -AC_DEFINE([COPYRIGHT_HOLDERS_SUBSTITUTION], ["_COPYRIGHT_HOLDERS_SUBSTITUTION"], [Replacement for %s in copyright holders string]) -define(_COPYRIGHT_HOLDERS_FINAL, [patsubst(_COPYRIGHT_HOLDERS, [%s], [_COPYRIGHT_HOLDERS_SUBSTITUTION])]) -AC_DEFINE([COPYRIGHT_HOLDERS_FINAL], ["_COPYRIGHT_HOLDERS_FINAL"], [Copyright holder(s)]) -AC_SUBST(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR) -AC_SUBST(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR) -AC_SUBST(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD) -AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) -AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) -AC_SUBST(COPYRIGHT_HOLDERS, "_COPYRIGHT_HOLDERS") -AC_SUBST(COPYRIGHT_HOLDERS_SUBSTITUTION, "_COPYRIGHT_HOLDERS_SUBSTITUTION") -AC_SUBST(COPYRIGHT_HOLDERS_FINAL, "_COPYRIGHT_HOLDERS_FINAL") -AC_SUBST(BITCOIN_DAEMON_NAME) -AC_SUBST(BITCOIN_GUI_NAME) -AC_SUBST(BITCOIN_TEST_NAME) -AC_SUBST(BITCOIN_CLI_NAME) -AC_SUBST(BITCOIN_TX_NAME) -AC_SUBST(BITCOIN_UTIL_NAME) -AC_SUBST(BITCOIN_CHAINSTATE_NAME) -AC_SUBST(BITCOIN_WALLET_TOOL_NAME) -AC_SUBST(BITCOIN_MP_NODE_NAME) -AC_SUBST(BITCOIN_MP_GUI_NAME) - -AC_SUBST(RELDFLAGS) -AC_SUBST(CORE_LDFLAGS) -AC_SUBST(CORE_CPPFLAGS) -AC_SUBST(CORE_CXXFLAGS) -AC_SUBST(DEBUG_CPPFLAGS) -AC_SUBST(WARN_CXXFLAGS) -AC_SUBST(NOWARN_CXXFLAGS) -AC_SUBST(DEBUG_CXXFLAGS) -AC_SUBST(ERROR_CXXFLAGS) -AC_SUBST(GPROF_CXXFLAGS) -AC_SUBST(GPROF_LDFLAGS) -AC_SUBST(HARDENED_CXXFLAGS) -AC_SUBST(HARDENED_CPPFLAGS) -AC_SUBST(HARDENED_LDFLAGS) -AC_SUBST(PIC_FLAGS) -AC_SUBST(PIE_FLAGS) -AC_SUBST(SANITIZER_CXXFLAGS) -AC_SUBST(SANITIZER_LDFLAGS) -AC_SUBST(SSE42_CXXFLAGS) -AC_SUBST(SSE41_CXXFLAGS) -AC_SUBST(CLMUL_CXXFLAGS) -AC_SUBST(AVX2_CXXFLAGS) -AC_SUBST(X86_SHANI_CXXFLAGS) -AC_SUBST(ARM_CRC_CXXFLAGS) -AC_SUBST(ARM_SHANI_CXXFLAGS) -AC_SUBST(LIBTOOL_APP_LDFLAGS) -AC_SUBST(USE_SQLITE) -AC_SUBST(USE_BDB) -AC_SUBST(ENABLE_EXTERNAL_SIGNER) -AC_SUBST(USE_UPNP) -AC_SUBST(USE_QRCODE) -AC_SUBST(TESTDEFS) -AC_SUBST(MINIUPNPC_CPPFLAGS) -AC_SUBST(MINIUPNPC_LIBS) -AC_SUBST(NATPMP_CPPFLAGS) -AC_SUBST(NATPMP_LIBS) -AC_SUBST(HAVE_FDATASYNC) -AC_SUBST(HAVE_FULLFSYNC) -AC_SUBST(HAVE_O_CLOEXEC) -AC_SUBST(HAVE_BUILTIN_PREFETCH) -AC_SUBST(HAVE_MM_PREFETCH) -AC_SUBST(HAVE_STRONG_GETAUXVAL) -AC_SUBST(HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR) -AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini]) -AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) -AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])]) -AC_CONFIG_LINKS([contrib/devtools/iwyu/bitcoin.core.imp:contrib/devtools/iwyu/bitcoin.core.imp]) -AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py]) -AC_CONFIG_LINKS([src/.bear-tidy-config:src/.bear-tidy-config]) -AC_CONFIG_LINKS([src/.clang-tidy:src/.clang-tidy]) -AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py]) -AC_CONFIG_LINKS([test/fuzz/test_runner.py:test/fuzz/test_runner.py]) -AC_CONFIG_LINKS([test/util/test_runner.py:test/util/test_runner.py]) -AC_CONFIG_LINKS([test/util/rpcauth-test.py:test/util/rpcauth-test.py]) -AC_CONFIG_LINKS([src/qt/Makefile:src/qt/Makefile]) -AC_CONFIG_LINKS([src/qt/test/Makefile:src/qt/test/Makefile]) -AC_CONFIG_LINKS([src/test/Makefile:src/test/Makefile]) - -dnl boost's m4 checks do something really nasty: they export these vars. As a -dnl result, they leak into secp256k1's configure and crazy things happen. -dnl Until this is fixed upstream and we've synced, we'll just un-export them. -CPPFLAGS_TEMP="$CPPFLAGS" -unset CPPFLAGS -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_CONFIG_SUBDIRS([src/secp256k1]) - -AC_OUTPUT - -dnl Replace the BUILDDIR path with the correct Windows path if compiling on Native Windows -case ${OS} in - *Windows*) - sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' test/config.ini > test/config-2.ini - mv test/config-2.ini test/config.ini - ;; -esac - -dnl An old hack similar to a98356fee to remove hard-coded -dnl bind_at_load flag from libtool -case $host in - *darwin*) - AC_MSG_RESULT([Removing -Wl,bind_at_load from libtool.]) - sed < libtool > libtool-2 '/bind_at_load/d' - mv libtool-2 libtool - chmod 755 libtool - ;; -esac - -echo -echo "Options used to compile and link:" -echo " external signer = $use_external_signer" -echo " multiprocess = $build_multiprocess" -echo " with wallet = $enable_wallet" -if test "$enable_wallet" != "no"; then - echo " with sqlite = $use_sqlite" - echo " with bdb = $use_bdb" -fi -echo " with gui / qt = $bitcoin_enable_qt" -if test $bitcoin_enable_qt != "no"; then - echo " with qr = $use_qr" -fi -echo " with zmq = $use_zmq" -if test $enable_fuzz = "no"; then - echo " with test = $use_tests" -else - echo " with test = not building test_bitcoin because fuzzing is enabled" -fi -echo " with fuzz binary = $enable_fuzz_binary" -echo " with bench = $use_bench" -echo " with upnp = $use_upnp" -echo " with natpmp = $use_natpmp" -echo " USDT tracing = $use_usdt" -echo " sanitizers = $use_sanitizers" -echo " debug enabled = $enable_debug" -echo " gprof enabled = $enable_gprof" -echo " werror = $enable_werror" -echo -echo " target os = $host_os" -echo " build os = $build_os" -echo -echo " CC = $CC" -echo " CFLAGS = $PTHREAD_CFLAGS $SANITIZER_CFLAGS $CFLAGS" -echo " CPPFLAGS = $DEBUG_CPPFLAGS $HARDENED_CPPFLAGS $CORE_CPPFLAGS $CPPFLAGS" -echo " CXX = $CXX" -echo " CXXFLAGS = $CORE_CXXFLAGS $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $SANITIZER_CXXFLAGS $CXXFLAGS" -echo " LDFLAGS = $PTHREAD_LIBS $HARDENED_LDFLAGS $GPROF_LDFLAGS $SANITIZER_LDFLAGS $CORE_LDFLAGS $LDFLAGS" -echo " AR = $AR" -echo " ARFLAGS = $ARFLAGS" -echo 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..c6f683f7ab 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 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_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..f2658b5a58 100644 --- a/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp +++ b/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // 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> @@ -12,7 +12,7 @@ class BitcoinModule final : public clang::tidy::ClangTidyModule 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_logprintf.cpp b/contrib/devtools/bitcoin-tidy/example_logprintf.cpp deleted file mode 100644 index a12a666c08..0000000000 --- a/contrib/devtools/bitcoin-tidy/example_logprintf.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// 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 <string> - -// Test for bitcoin-unterminated-logprintf - -enum LogFlags { - NONE -}; - -enum Level { - None -}; - -template <typename... Args> -static inline void LogPrintf_(const std::string& logging_function, const std::string& source_file, const int source_line, const LogFlags flag, const Level level, const char* fmt, const Args&... args) -{ -} - -#define LogPrintLevel_(category, level, ...) LogPrintf_(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__) -#define LogPrintf(...) LogPrintLevel_(LogFlags::NONE, Level::None, __VA_ARGS__) - -#define LogPrint(category, ...) \ - do { \ - LogPrintf(__VA_ARGS__); \ - } while (0) - - -class CWallet -{ - std::string GetDisplayName() const - { - return "default wallet"; - } - -public: - template <typename... Params> - void WalletLogPrintf(const char* fmt, Params... parameters) const - { - LogPrintf(("%s " + std::string{fmt}).c_str(), GetDisplayName(), parameters...); - }; -}; - -struct ScriptPubKeyMan -{ - std::string GetDisplayName() const - { - return "default wallet"; - } - - template <typename... Params> - void WalletLogPrintf(const char* fmt, Params... parameters) const - { - LogPrintf(("%s " + std::string{fmt}).c_str(), GetDisplayName(), parameters...); - }; -}; - -void good_func() -{ - LogPrintf("hello world!\n"); -} -void good_func2() -{ - CWallet wallet; - wallet.WalletLogPrintf("hi\n"); - ScriptPubKeyMan spkm; - spkm.WalletLogPrintf("hi\n"); - - const CWallet& walletref = wallet; - walletref.WalletLogPrintf("hi\n"); - - auto* walletptr = new CWallet(); - walletptr->WalletLogPrintf("hi\n"); - delete walletptr; -} -void bad_func() -{ - LogPrintf("hello world!"); -} -void bad_func2() -{ - LogPrintf(""); -} -void bad_func3() -{ - // Ending in "..." has no special meaning. - LogPrintf("hello world!..."); -} -void bad_func4_ignored() -{ - LogPrintf("hello world!"); // NOLINT(bitcoin-unterminated-logprintf) -} -void bad_func5() -{ - CWallet wallet; - wallet.WalletLogPrintf("hi"); - ScriptPubKeyMan spkm; - spkm.WalletLogPrintf("hi"); - - const CWallet& walletref = wallet; - walletref.WalletLogPrintf("hi"); - - auto* walletptr = new CWallet(); - walletptr->WalletLogPrintf("hi"); - delete walletptr; -} 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/logprintf.cpp b/contrib/devtools/bitcoin-tidy/logprintf.cpp deleted file mode 100644 index 36beac28c8..0000000000 --- a/contrib/devtools/bitcoin-tidy/logprintf.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// 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 "logprintf.h" - -#include <clang/AST/ASTContext.h> -#include <clang/ASTMatchers/ASTMatchFinder.h> - - -namespace { -AST_MATCHER(clang::StringLiteral, unterminated) -{ - size_t len = Node.getLength(); - if (len > 0 && Node.getCodeUnit(len - 1) == '\n') { - return false; - } - return true; -} -} // namespace - -namespace bitcoin { - -void LogPrintfCheck::registerMatchers(clang::ast_matchers::MatchFinder* finder) -{ - using namespace clang::ast_matchers; - - /* - Logprintf(..., ..., ..., ..., ..., "foo", ...) - */ - - finder->addMatcher( - callExpr( - callee(functionDecl(hasName("LogPrintf_"))), - hasArgument(5, stringLiteral(unterminated()).bind("logstring"))), - this); - - /* - auto walletptr = &wallet; - wallet.WalletLogPrintf("foo"); - wallet->WalletLogPrintf("foo"); - */ - finder->addMatcher( - cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("WalletLogPrintf"))), - hasArgument(0, stringLiteral(unterminated()).bind("logstring"))), - this); -} - -void LogPrintfCheck::check(const clang::ast_matchers::MatchFinder::MatchResult& Result) -{ - if (const clang::StringLiteral* lit = Result.Nodes.getNodeAs<clang::StringLiteral>("logstring")) { - const clang::ASTContext& ctx = *Result.Context; - const auto user_diag = diag(lit->getEndLoc(), "Unterminated format string used with LogPrintf"); - const auto& loc = lit->getLocationOfByte(lit->getByteLength(), *Result.SourceManager, ctx.getLangOpts(), ctx.getTargetInfo()); - user_diag << clang::FixItHint::CreateInsertion(loc, "\\n"); - } -} - -} // namespace bitcoin 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/logprintf.h b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h index db95dfe143..c853073467 100644 --- a/contrib/devtools/bitcoin-tidy/logprintf.h +++ b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h @@ -2,18 +2,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef LOGPRINTF_CHECK_H -#define LOGPRINTF_CHECK_H +#ifndef NONTRIVIAL_THREADLOCAL_CHECK_H +#define NONTRIVIAL_THREADLOCAL_CHECK_H #include <clang-tidy/ClangTidyCheck.h> namespace bitcoin { -// Warn about any use of LogPrintf that does not end with a newline. -class LogPrintfCheck final : public clang::tidy::ClangTidyCheck +// Warn about any thread_local variable with a non-trivial destructor. +class NonTrivialThreadLocal final : public clang::tidy::ClangTidyCheck { public: - LogPrintfCheck(clang::StringRef Name, clang::tidy::ClangTidyContext* Context) + NonTrivialThreadLocal(clang::StringRef Name, clang::tidy::ClangTidyContext* Context) : clang::tidy::ClangTidyCheck(Name, Context) {} bool isLanguageVersionSupported(const clang::LangOptions& LangOpts) const override @@ -26,4 +26,4 @@ public: } // namespace bitcoin -#endif // LOGPRINTF_CHECK_H +#endif // NONTRIVIAL_THREADLOCAL_CHECK_H diff --git a/contrib/devtools/check-deps.sh b/contrib/devtools/check-deps.sh new file mode 100755 index 0000000000..cdfc4e7533 --- /dev/null +++ b/contrib/devtools/check-deps.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash + +export LC_ALL=C +set -Eeuo pipefail + +# Declare paths to libraries +declare -A LIBS +LIBS[cli]="libbitcoin_cli.a" +LIBS[common]="libbitcoin_common.a" +LIBS[consensus]="libbitcoin_consensus.a" +LIBS[crypto]="crypto/libbitcoin_crypto.a crypto/libbitcoin_crypto_x86_shani.a crypto/libbitcoin_crypto_sse41.a crypto/libbitcoin_crypto_avx2.a" +LIBS[node]="libbitcoin_node.a" +LIBS[util]="util/libbitcoin_util.a" +LIBS[wallet]="wallet/libbitcoin_wallet.a" + +# Declare allowed dependencies "X Y" where X is allowed to depend on Y. This +# list is taken from doc/design/libraries.md. +ALLOWED_DEPENDENCIES=( + "cli common" + "cli util" + "common consensus" + "common crypto" + "common util" + "consensus crypto" + "node common" + "node consensus" + "node crypto" + "node kernel" + "node util" + "util crypto" + "wallet common" + "wallet crypto" + "wallet util" +) + +# Add minor dependencies omitted from doc/design/libraries.md to keep the +# dependency diagram simple. +ALLOWED_DEPENDENCIES+=( + "wallet consensus" +) + +# Declare list of known errors that should be suppressed. +declare -A SUPPRESS +# init.cpp file currently calls Berkeley DB sanity check function on startup, so +# there is an undocumented dependency of the node library on the wallet library. +SUPPRESS["init.cpp.o bdb.cpp.o _ZN6wallet27BerkeleyDatabaseSanityCheckEv"]=1 +# init/common.cpp file calls InitError and InitWarning from interface_ui which +# is currently part of the node library. interface_ui should just be part of the +# common library instead, and is moved in +# https://github.com/bitcoin/bitcoin/issues/10102 +SUPPRESS["common.cpp.o interface_ui.cpp.o _Z11InitWarningRK13bilingual_str"]=1 +SUPPRESS["common.cpp.o interface_ui.cpp.o _Z9InitErrorRK13bilingual_str"]=1 +# rpc/external_signer.cpp adds defines node RPC methods but is built as part of the +# common library. It should be moved to the node library instead. +SUPPRESS["external_signer.cpp.o server.cpp.o _ZN9CRPCTable13appendCommandERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPK11CRPCCommand"]=1 + +usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") [BUILD_DIR]" +} + +# Output makefile targets, converting library .a paths to CMake targets +lib_targets() { + for lib in "${!LIBS[@]}"; do + for lib_path in ${LIBS[$lib]}; do + local name="${lib_path##*/}" + name="${name#lib}" + name="${name%.a}" + echo "$name" + done + done +} + +# Extract symbol names and object names and write to text files +extract_symbols() { + local temp_dir="$1" + for lib in "${!LIBS[@]}"; do + for lib_path in ${LIBS[$lib]}; do + nm -o "$lib_path" | { grep ' T \| W ' || true; } | awk '{print $3, $1}' >> "${temp_dir}/${lib}_exports.txt" + nm -o "$lib_path" | { grep ' U ' || true; } | awk '{print $3, $1}' >> "${temp_dir}/${lib}_imports.txt" + awk '{print $1}' "${temp_dir}/${lib}_exports.txt" | sort -u > "${temp_dir}/${lib}_exported_symbols.txt" + awk '{print $1}' "${temp_dir}/${lib}_imports.txt" | sort -u > "${temp_dir}/${lib}_imported_symbols.txt" + done + done +} + +# Lookup object name(s) corresponding to symbol name in text file +obj_names() { + local symbol="$1" + local txt_file="$2" + sed -n "s/^$symbol [^:]\\+:\\([^:]\\+\\):[^:]*\$/\\1/p" "$txt_file" | sort -u +} + +# Iterate through libraries and find disallowed dependencies +check_libraries() { + local temp_dir="$1" + local result=0 + for src in "${!LIBS[@]}"; do + for dst in "${!LIBS[@]}"; do + if [ "$src" != "$dst" ] && ! is_allowed "$src" "$dst"; then + if ! check_disallowed "$src" "$dst" "$temp_dir"; then + result=1 + fi + fi + done + done + check_not_suppressed + return $result +} + +# Return whether src library is allowed to depend on dst. +is_allowed() { + local src="$1" + local dst="$2" + for allowed in "${ALLOWED_DEPENDENCIES[@]}"; do + if [ "$src $dst" = "$allowed" ]; then + return 0 + fi + done + return 1 +} + +# Return whether src library imports any symbols from dst, assuming src is not +# allowed to depend on dst. +check_disallowed() { + local src="$1" + local dst="$2" + local temp_dir="$3" + local result=0 + + # Loop over symbol names exported by dst and imported by src + while read symbol; do + local dst_obj + dst_obj=$(obj_names "$symbol" "${temp_dir}/${dst}_exports.txt") + while read src_obj; do + if ! check_suppress "$src_obj" "$dst_obj" "$symbol"; then + echo "Error: $src_obj depends on $dst_obj symbol '$(c++filt "$symbol")', can suppress with:" + echo " SUPPRESS[\"$src_obj $dst_obj $symbol\"]=1" + result=1 + fi + done < <(obj_names "$symbol" "${temp_dir}/${src}_imports.txt") + done < <(comm -12 "${temp_dir}/${dst}_exported_symbols.txt" "${temp_dir}/${src}_imported_symbols.txt") + return $result +} + +# Declare array to track errors which were suppressed. +declare -A SUPPRESSED + +# Return whether error should be suppressed and record suppression in +# SUPPRESSED array. +check_suppress() { + local src_obj="$1" + local dst_obj="$2" + local symbol="$3" + for suppress in "${!SUPPRESS[@]}"; do + read suppress_src suppress_dst suppress_pattern <<<"$suppress" + if [[ "$src_obj" == "$suppress_src" && "$dst_obj" == "$suppress_dst" && "$symbol" =~ $suppress_pattern ]]; then + SUPPRESSED["$suppress"]=1 + return 0 + fi + done + return 1 +} + +# Warn about error which were supposed to be suppressed, but were not encountered. +check_not_suppressed() { + for suppress in "${!SUPPRESS[@]}"; do + if [[ ! -v SUPPRESSED[$suppress] ]]; then + echo >&2 "Warning: suppression '$suppress' was ignored, consider deleting." + fi + done +} + +# Check arguments. +if [ "$#" = 0 ]; then + BUILD_DIR="$(dirname "${BASH_SOURCE[0]}")/../../build" +elif [ "$#" = 1 ]; then + BUILD_DIR="$1" +else + echo >&2 "Error: wrong number of arguments." + usage >&2 + exit 1 +fi +if [ ! -f "$BUILD_DIR/Makefile" ]; then + echo >&2 "Error: directory '$BUILD_DIR' does not contain a makefile, please specify path to build directory for library targets." + usage >&2 + exit 1 +fi + +# Build libraries and run checks. +# shellcheck disable=SC2046 +cmake --build "$BUILD_DIR" -j"$(nproc)" -t $(lib_targets) +TEMP_DIR="$(mktemp -d)" +cd "$BUILD_DIR/src" +extract_symbols "$TEMP_DIR" +if check_libraries "$TEMP_DIR"; then + echo "Success! No unexpected dependencies were detected." + RET=0 +else + echo >&2 "Error: Unexpected dependencies were detected. Check previous output." + RET=1 +fi +rm -r "$TEMP_DIR" +exit $RET diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py index e2b661d65d..30e804dbe2 100755 --- a/contrib/devtools/clang-format-diff.py +++ b/contrib/devtools/clang-format-diff.py @@ -164,7 +164,7 @@ def main(): 'Failed to run "%s" - %s"' % (" ".join(command), e.strerror) ) - stdout, stderr = p.communicate() + stdout, _stderr = p.communicate() if p.returncode != 0: sys.exit(p.returncode) diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index 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/gen-bitcoin-conf.sh b/contrib/devtools/gen-bitcoin-conf.sh index 2ebbd42022..d830852c9e 100755 --- a/contrib/devtools/gen-bitcoin-conf.sh +++ b/contrib/devtools/gen-bitcoin-conf.sh @@ -72,9 +72,12 @@ cat >> "${EXAMPLE_CONF_FILE}" << 'EOF' # Options for mainnet [main] -# Options for testnet +# Options for testnet3 [test] +# Options for testnet4 +[testnet4] + # Options for signet [signet] diff --git a/contrib/devtools/headerssync-params.py b/contrib/devtools/headerssync-params.py index 0198f5db99..f8e415532a 100644..100755 --- a/contrib/devtools/headerssync-params.py +++ b/contrib/devtools/headerssync-params.py @@ -12,13 +12,13 @@ import random # Parameters: # Aim for still working fine at some point in the future. [datetime] -TIME = datetime(2026, 10, 5) +TIME = datetime(2027, 4, 1) # Expected block interval. [timedelta] BLOCK_INTERVAL = timedelta(seconds=600) # The number of headers corresponding to the minchainwork parameter. [headers] -MINCHAINWORK_HEADERS = 804000 +MINCHAINWORK_HEADERS = 856760 # Combined processing bandwidth from all attackers to one victim. [bit/s] # 6 Gbit/s is approximately the speed at which a single thread of a Ryzen 5950X CPU thread can hash diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index f57e9abfec..4c20685b51 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -7,6 +7,7 @@ Perform basic security checks on a series of executables. Exit status will be 0 if successful, and the program will be silent. Otherwise the exit status will be 1 and it will log which executables failed which checks. ''' +import re import sys import lief @@ -38,13 +39,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 +106,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 ''' @@ -116,6 +117,25 @@ def check_ELF_control_flow(binary) -> bool: return True return False +def check_ELF_FORTIFY(binary) -> bool: + + # bitcoin-util does not currently contain any fortified functions + if 'Bitcoin Core bitcoin-util utility version ' in binary.strings: + return True + + chk_funcs = set() + + for sym in binary.imported_symbols: + match = re.search(r'__[a-z]*_chk', sym.name) + if match: + chk_funcs.add(match.group(0)) + + # ignore stack-protector and bdb + chk_funcs.discard('__stack_chk') + chk_funcs.discard('__db_chk') + + return len(chk_funcs) >= 1 + def check_PE_DYNAMIC_BASE(binary) -> bool: '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)''' return lief.PE.DLL_CHARACTERISTICS.DYNAMIC_BASE in binary.optional_header.dll_characteristics_lists @@ -130,7 +150,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 +165,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 +183,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 +202,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 +212,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 +226,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,23 +236,23 @@ 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.ARM: BASE_ELF, - lief.ARCHITECTURES.ARM64: BASE_ELF, - lief.ARCHITECTURES.PPC: BASE_ELF, - lief.ARCHITECTURES.RISCV: BASE_ELF, + lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_CONTROL_FLOW), ('FORTIFY', check_ELF_FORTIFY)], + lief.ARCHITECTURES.ARM: BASE_ELF + [('FORTIFY', check_ELF_FORTIFY)], + lief.ARCHITECTURES.ARM64: BASE_ELF + [('FORTIFY', check_ELF_FORTIFY)], + lief.ARCHITECTURES.PPC: BASE_ELF + [('FORTIFY', check_ELF_FORTIFY)], + lief.ARCHITECTURES.RISCV: BASE_ELF, # Skip FORTIFY. See https://github.com/lief-project/LIEF/issues/1082. }, lief.EXE_FORMATS.PE: { lief.ARCHITECTURES.X86: BASE_PE, @@ -240,39 +260,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 e4a62c2072..3f6010280a 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -14,31 +14,31 @@ import sys import lief -# Debian 10 (Buster) EOL: 2024. https://wiki.debian.org/LTS +# Debian 11 (Bullseye) EOL: 2026. https://wiki.debian.org/LTS # -# - libgcc version 8.3.0 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libgcc1) -# - libc version 2.28 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libc6) +# - libgcc version 10.2.1 (https://packages.debian.org/bullseye/libgcc-s1) +# - libc version 2.31 (https://packages.debian.org/source/bullseye/glibc) # -# Ubuntu 18.04 (Bionic) EOL: 2028. https://wiki.ubuntu.com/ReleaseTeam +# Ubuntu 20.04 (Focal) EOL: 2030. https://wiki.ubuntu.com/ReleaseTeam # -# - libgcc version 8.4.0 (https://packages.ubuntu.com/bionic/libgcc1) -# - libc version 2.27 (https://packages.ubuntu.com/bionic/libc6) +# - libgcc version 10.5.0 (https://packages.ubuntu.com/focal/libgcc1) +# - libc version 2.31 (https://packages.ubuntu.com/focal/libc6) # -# CentOS Stream 8 EOL: 2024. https://wiki.centos.org/About/Product +# CentOS Stream 9 EOL: 2027. https://www.centos.org/cl-vs-cs/#end-of-life # -# - libgcc version 8.5.0 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/) -# - libc version 2.28 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/) +# - libgcc version 12.2.1 (https://mirror.stream.centos.org/9-stream/AppStream/x86_64/os/Packages/) +# - libc version 2.34 (https://mirror.stream.centos.org/9-stream/AppStream/x86_64/os/Packages/) # # See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html for more info. MAX_VERSIONS = { 'GCC': (4,3,0), 'GLIBC': { - lief.ELF.ARCH.x86_64: (2,27), - lief.ELF.ARCH.ARM: (2,27), - lief.ELF.ARCH.AARCH64:(2,27), - lief.ELF.ARCH.PPC64: (2,27), - lief.ELF.ARCH.RISCV: (2,27), + lief.ELF.ARCH.x86_64: (2,31), + lief.ELF.ARCH.ARM: (2,31), + lief.ELF.ARCH.AARCH64:(2,31), + lief.ELF.ARCH.PPC64: (2,31), + lief.ELF.ARCH.RISCV: (2,31), }, 'LIBATOMIC': (1,0), 'V': (0,5,0), # xkb (bitcoin-qt only) @@ -212,6 +212,11 @@ def check_exported_symbols(binary) -> bool: ok = False return ok +def check_RUNPATH(binary) -> bool: + assert binary.get(lief.ELF.DYNAMIC_TAGS.RUNPATH) is None + assert binary.get(lief.ELF.DYNAMIC_TAGS.RPATH) is None + return True + def check_ELF_libraries(binary) -> bool: ok: bool = True for library in binary.libraries: @@ -230,7 +235,7 @@ def check_MACHO_libraries(binary) -> bool: return ok def check_MACHO_min_os(binary) -> bool: - if binary.build_version.minos == [11,0,0]: + if binary.build_version.minos == [13,0,0]: return True return False @@ -239,8 +244,8 @@ def check_MACHO_sdk(binary) -> bool: return True return False -def check_MACHO_ld64(binary) -> bool: - if binary.build_version.tools[0].version == [17, 0, 6]: +def check_MACHO_lld(binary) -> bool: + if binary.build_version.tools[0].version == [18, 1, 8]: return True return False @@ -277,12 +282,13 @@ lief.EXE_FORMATS.ELF: [ ('LIBRARY_DEPENDENCIES', check_ELF_libraries), ('INTERPRETER_NAME', check_ELF_interpreter), ('ABI', check_ELF_ABI), + ('RUNPATH', check_RUNPATH), ], lief.EXE_FORMATS.MACHO: [ ('DYNAMIC_LIBRARIES', check_MACHO_libraries), ('MIN_OS', check_MACHO_min_os), ('SDK', check_MACHO_sdk), - ('LD64', check_MACHO_ld64), + ('LLD', check_MACHO_lld), ], lief.EXE_FORMATS.PE: [ ('DYNAMIC_LIBRARIES', check_PE_libraries), @@ -293,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 dd0cf7030a..99f171608d 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,77 @@ 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','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE NX RELRO Canary CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO Canary CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']), - (0, '')) + pass_flags = ['-D_FORTIFY_SOURCE=3', '-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 + ['-U_FORTIFY_SOURCE']), (1, executable + ': failed FORTIFY')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) else: - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE NX RELRO Canary')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO Canary')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), - (0, '')) + pass_flags = ['-D_FORTIFY_SOURCE=3', '-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')) + # LIEF fails to parse RISC-V with no PIE correctly, and doesn't detect the fortified function, + # so skip this test for RISC-V (for now). See https://github.com/lief-project/LIEF/issues/1082. + if arch != lief.ARCHITECTURES.RISCV: + 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 + ['-U_FORTIFY_SOURCE']), (1, executable + ': failed FORTIFY')) + 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..c75a5e1546 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,13.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_deterministic_coverage.sh b/contrib/devtools/test_deterministic_coverage.sh index 23c260b529..885396bb25 100755 --- a/contrib/devtools/test_deterministic_coverage.sh +++ b/contrib/devtools/test_deterministic_coverage.sh @@ -81,7 +81,7 @@ if ! command -v gcovr > /dev/null; then fi if [[ ! -e ${TEST_BITCOIN_BINARY} ]]; then - echo "Error: Executable ${TEST_BITCOIN_BINARY} not found. Run \"./configure --enable-lcov\" and compile." + echo "Error: Executable ${TEST_BITCOIN_BINARY} not found. Run \"cmake -B build -DCMAKE_BUILD_TYPE=Coverage\" and compile." exit 1 fi @@ -90,7 +90,7 @@ get_file_suffix_count() { } if [[ $(get_file_suffix_count gcno) == 0 ]]; then - echo "Error: Could not find any *.gcno files. The *.gcno files are generated by the compiler. Run \"./configure --enable-lcov\" and re-compile." + echo "Error: Could not find any *.gcno files. The *.gcno files are generated by the compiler. Run \"cmake -B build -DCMAKE_BUILD_TYPE=Coverage\" and re-compile." exit 1 fi @@ -115,7 +115,7 @@ while [[ ${TEST_RUN_ID} -lt ${N_TEST_RUNS} ]]; do fi rm "${TEST_OUTPUT_TEMPFILE}" if [[ $(get_file_suffix_count gcda) == 0 ]]; then - echo "Error: Running the test suite did not create any *.gcda files. The gcda files are generated when the instrumented test programs are executed. Run \"./configure --enable-lcov\" and re-compile." + echo "Error: Running the test suite did not create any *.gcda files. The gcda files are generated when the instrumented test programs are executed. Run \"cmake -B build -DCMAKE_BUILD_TYPE=Coverage\" and re-compile." exit 1 fi GCOVR_TEMPFILE=$(mktemp) diff --git a/contrib/devtools/test_utxo_snapshots.sh b/contrib/devtools/test_utxo_snapshots.sh deleted file mode 100755 index d7c019f4a6..0000000000 --- a/contrib/devtools/test_utxo_snapshots.sh +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/env bash -# Demonstrate the creation and usage of UTXO snapshots. -# -# A server node starts up, IBDs up to a certain height, then generates a UTXO -# snapshot at that point. -# -# The server then downloads more blocks (to create a diff from the snapshot). -# -# We bring a client up, load the UTXO snapshot, and we show the client sync to -# the "network tip" and then start a background validation of the snapshot it -# loaded. We see the background validation chainstate removed after validation -# completes. -# -# The shellcheck rule SC2086 (quoted variables) disablements are necessary -# since this rule needs to be violated in order to get bitcoind to pick up on -# $EARLY_IBD_FLAGS for the script to work. - -export LC_ALL=C -set -e - -BASE_HEIGHT=${1:-30000} -INCREMENTAL_HEIGHT=20000 -FINAL_HEIGHT=$((BASE_HEIGHT + INCREMENTAL_HEIGHT)) - -SERVER_DATADIR="$(pwd)/utxodemo-data-server-$BASE_HEIGHT" -CLIENT_DATADIR="$(pwd)/utxodemo-data-client-$BASE_HEIGHT" -UTXO_DAT_FILE="$(pwd)/utxo.$BASE_HEIGHT.dat" - -# Chosen to try to not interfere with any running bitcoind processes. -SERVER_PORT=8633 -SERVER_RPC_PORT=8632 - -CLIENT_PORT=8733 -CLIENT_RPC_PORT=8732 - -SERVER_PORTS="-port=${SERVER_PORT} -rpcport=${SERVER_RPC_PORT}" -CLIENT_PORTS="-port=${CLIENT_PORT} -rpcport=${CLIENT_RPC_PORT}" - -# Ensure the client exercises all indexes to test that snapshot use works -# properly with indexes. -ALL_INDEXES="-txindex -coinstatsindex -blockfilterindex=1" - -if ! command -v jq >/dev/null ; then - echo "This script requires jq to parse JSON RPC output. Please install it." - echo "(e.g. sudo apt install jq)" - exit 1 -fi - -DUMP_OUTPUT="dumptxoutset-output-$BASE_HEIGHT.json" - -finish() { - echo - echo "Killing server and client PIDs ($SERVER_PID, $CLIENT_PID) and cleaning up datadirs" - echo - rm -f "$UTXO_DAT_FILE" "$DUMP_OUTPUT" - rm -rf "$SERVER_DATADIR" "$CLIENT_DATADIR" - kill -9 "$SERVER_PID" "$CLIENT_PID" -} - -trap finish EXIT - -# Need to specify these to trick client into accepting server as a peer -# it can IBD from, otherwise the default values prevent IBD from the server node. -EARLY_IBD_FLAGS="-maxtipage=9223372036854775207 -minimumchainwork=0x00" - -server_rpc() { - ./src/bitcoin-cli -rpcport=$SERVER_RPC_PORT -datadir="$SERVER_DATADIR" "$@" -} -client_rpc() { - ./src/bitcoin-cli -rpcport=$CLIENT_RPC_PORT -datadir="$CLIENT_DATADIR" "$@" -} -server_sleep_til_boot() { - while ! server_rpc ping >/dev/null 2>&1; do sleep 0.1; done -} -client_sleep_til_boot() { - while ! client_rpc ping >/dev/null 2>&1; do sleep 0.1; done -} -server_sleep_til_shutdown() { - while server_rpc ping >/dev/null 2>&1; do sleep 0.1; done -} - -mkdir -p "$SERVER_DATADIR" "$CLIENT_DATADIR" - -echo "Hi, welcome to the assumeutxo demo/test" -echo -echo "We're going to" -echo -echo " - start up a 'server' node, sync it via mainnet IBD to height ${BASE_HEIGHT}" -echo " - create a UTXO snapshot at that height" -echo " - IBD ${INCREMENTAL_HEIGHT} more blocks on top of that" -echo -echo "then we'll demonstrate assumeutxo by " -echo -echo " - starting another node (the 'client') and loading the snapshot in" -echo " * first you'll have to modify the code slightly (chainparams) and recompile" -echo " * don't worry, we'll make it easy" -echo " - observing the client sync ${INCREMENTAL_HEIGHT} blocks on top of the snapshot from the server" -echo " - observing the client validate the snapshot chain via background IBD" -echo -read -p "Press [enter] to continue" _ - -echo -echo "-- Starting the demo. You might want to run the two following commands in" -echo " separate terminal windows:" -echo -echo " watch -n0.1 tail -n 30 $SERVER_DATADIR/debug.log" -echo " watch -n0.1 tail -n 30 $CLIENT_DATADIR/debug.log" -echo -read -p "Press [enter] to continue" _ - -echo -echo "-- IBDing the blocks (height=$BASE_HEIGHT) required to the server node..." -# shellcheck disable=SC2086 -./src/bitcoind -logthreadnames=1 $SERVER_PORTS \ - -datadir="$SERVER_DATADIR" $EARLY_IBD_FLAGS -stopatheight="$BASE_HEIGHT" >/dev/null - -echo -echo "-- Creating snapshot at ~ height $BASE_HEIGHT ($UTXO_DAT_FILE)..." -server_sleep_til_shutdown # wait for stopatheight to be hit -# shellcheck disable=SC2086 -./src/bitcoind -logthreadnames=1 $SERVER_PORTS \ - -datadir="$SERVER_DATADIR" $EARLY_IBD_FLAGS -connect=0 -listen=0 >/dev/null & -SERVER_PID="$!" - -server_sleep_til_boot -server_rpc dumptxoutset "$UTXO_DAT_FILE" > "$DUMP_OUTPUT" -cat "$DUMP_OUTPUT" -kill -9 "$SERVER_PID" - -RPC_BASE_HEIGHT=$(jq -r .base_height < "$DUMP_OUTPUT") -RPC_AU=$(jq -r .txoutset_hash < "$DUMP_OUTPUT") -RPC_NCHAINTX=$(jq -r .nchaintx < "$DUMP_OUTPUT") -RPC_BLOCKHASH=$(jq -r .base_hash < "$DUMP_OUTPUT") - -server_sleep_til_shutdown - -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 -echo -echo "-- IBDing more blocks to the server node (height=$FINAL_HEIGHT) so there is a diff between snapshot and tip..." -# shellcheck disable=SC2086 -./src/bitcoind $SERVER_PORTS -logthreadnames=1 -datadir="$SERVER_DATADIR" \ - $EARLY_IBD_FLAGS -stopatheight="$FINAL_HEIGHT" >/dev/null - -echo -echo "-- Starting the server node to provide blocks to the client node..." -# shellcheck disable=SC2086 -./src/bitcoind $SERVER_PORTS -logthreadnames=1 -debug=net -datadir="$SERVER_DATADIR" \ - $EARLY_IBD_FLAGS -connect=0 -listen=1 >/dev/null & -SERVER_PID="$!" -server_sleep_til_boot - -echo -echo "-- Okay, what you're about to see is the client starting up and activating the snapshot." -echo " I'm going to display the top 14 log lines from the client on top of an RPC called" -echo " getchainstates, which is like getblockchaininfo but for both the snapshot and " -echo " background validation chainstates." -echo -echo " You're going to first see the snapshot chainstate sync to the server's tip, then" -echo " the background IBD chain kicks in to validate up to the base of the snapshot." -echo -echo " Once validation of the snapshot is done, you should see log lines indicating" -echo " that we've deleted the background validation chainstate." -echo -echo " Once everything completes, exit the watch command with CTRL+C." -echo -read -p "When you're ready for all this, hit [enter]" _ - -echo -echo "-- Starting the client node to get headers from the server, then load the snapshot..." -# shellcheck disable=SC2086 -./src/bitcoind $CLIENT_PORTS $ALL_INDEXES -logthreadnames=1 -datadir="$CLIENT_DATADIR" \ - -connect=0 -addnode=127.0.0.1:$SERVER_PORT -debug=net $EARLY_IBD_FLAGS >/dev/null & -CLIENT_PID="$!" -client_sleep_til_boot - -echo -echo "-- Initial state of the client:" -client_rpc getchainstates - -echo -echo "-- Loading UTXO snapshot into client. Calling RPC in a loop..." -while ! client_rpc loadtxoutset "$UTXO_DAT_FILE" ; do sleep 10; done - -watch -n 0.3 "( tail -n 14 $CLIENT_DATADIR/debug.log ; echo ; ./src/bitcoin-cli -rpcport=$CLIENT_RPC_PORT -datadir=$CLIENT_DATADIR getchainstates) | cat" - -echo -echo "-- Okay, now I'm going to restart the client to make sure that the snapshot chain reloads " -echo " as the main chain properly..." -echo -echo " Press CTRL+C after you're satisfied to exit the demo" -echo -read -p "Press [enter] to continue" - -client_sleep_til_boot -# shellcheck disable=SC2086 -./src/bitcoind $CLIENT_PORTS $ALL_INDEXES -logthreadnames=1 -datadir="$CLIENT_DATADIR" -connect=0 \ - -addnode=127.0.0.1:$SERVER_PORT "$EARLY_IBD_FLAGS" >/dev/null & -CLIENT_PID="$!" -client_sleep_til_boot - -watch -n 0.3 "( tail -n 14 $CLIENT_DATADIR/debug.log ; echo ; ./src/bitcoin-cli -rpcport=$CLIENT_RPC_PORT -datadir=$CLIENT_DATADIR getchainstates) | cat" - -echo -echo "-- Done!" diff --git a/contrib/devtools/utxo_snapshot.sh b/contrib/devtools/utxo_snapshot.sh deleted file mode 100755 index fbb8591965..0000000000 --- a/contrib/devtools/utxo_snapshot.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2019-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. -# -export LC_ALL=C - -set -ueo pipefail - -NETWORK_DISABLED=false - -if (( $# < 3 )); then - echo 'Usage: utxo_snapshot.sh <generate-at-height> <snapshot-out-path> <bitcoin-cli-call ...>' - echo - echo " if <snapshot-out-path> is '-', don't produce a snapshot file but instead print the " - echo " expected assumeutxo hash" - echo - echo 'Examples:' - echo - echo " ./contrib/devtools/utxo_snapshot.sh 570000 utxo.dat ./src/bitcoin-cli -datadir=\$(pwd)/testdata" - echo ' ./contrib/devtools/utxo_snapshot.sh 570000 - ./src/bitcoin-cli' - exit 1 -fi - -GENERATE_AT_HEIGHT="${1}"; shift; -OUTPUT_PATH="${1}"; shift; -# Most of the calls we make take a while to run, so pad with a lengthy timeout. -BITCOIN_CLI_CALL="${*} -rpcclienttimeout=9999999" - -# Check if the node is pruned and get the pruned block height -PRUNED=$( ${BITCOIN_CLI_CALL} getblockchaininfo | awk '/pruneheight/ {print $2}' | tr -d ',' ) - -if (( GENERATE_AT_HEIGHT < PRUNED )); then - echo "Error: The requested snapshot height (${GENERATE_AT_HEIGHT}) should be greater than the pruned block height (${PRUNED})." - exit 1 -fi - -# Early exit if file at OUTPUT_PATH already exists -if [[ -e "$OUTPUT_PATH" ]]; then - (>&2 echo "Error: $OUTPUT_PATH already exists or is not a valid path.") - exit 1 -fi - -# Validate that the path is correct -if [[ "${OUTPUT_PATH}" != "-" && ! -d "$(dirname "${OUTPUT_PATH}")" ]]; then - (>&2 echo "Error: The directory $(dirname "${OUTPUT_PATH}") does not exist.") - exit 1 -fi - -function cleanup { - (>&2 echo "Restoring chain to original height; this may take a while") - ${BITCOIN_CLI_CALL} reconsiderblock "${PIVOT_BLOCKHASH}" - - if $NETWORK_DISABLED; then - (>&2 echo "Restoring network activity") - ${BITCOIN_CLI_CALL} setnetworkactive true - fi -} - -function early_exit { - (>&2 echo "Exiting due to Ctrl-C") - cleanup - exit 1 -} - -# Prompt the user to disable network activity -read -p "Do you want to disable network activity (setnetworkactive false) before running invalidateblock? (Y/n): " -r -if [[ "$REPLY" =~ ^[Yy]*$ || -z "$REPLY" ]]; then - # User input is "Y", "y", or Enter key, proceed with the action - NETWORK_DISABLED=true - (>&2 echo "Disabling network activity") - ${BITCOIN_CLI_CALL} setnetworkactive false -else - (>&2 echo "Network activity remains enabled") -fi - -# Block we'll invalidate/reconsider to rewind/fast-forward the chain. -PIVOT_BLOCKHASH=$($BITCOIN_CLI_CALL getblockhash $(( GENERATE_AT_HEIGHT + 1 )) ) - -# Trap for normal exit and Ctrl-C -trap cleanup EXIT -trap early_exit INT - -(>&2 echo "Rewinding chain back to height ${GENERATE_AT_HEIGHT} (by invalidating ${PIVOT_BLOCKHASH}); this may take a while") -${BITCOIN_CLI_CALL} invalidateblock "${PIVOT_BLOCKHASH}" - -if [[ "${OUTPUT_PATH}" = "-" ]]; then - (>&2 echo "Generating txoutset info...") - ${BITCOIN_CLI_CALL} gettxoutsetinfo | grep hash_serialized_3 | sed 's/^.*: "\(.\+\)\+",/\1/g' -else - (>&2 echo "Generating UTXO snapshot...") - ${BITCOIN_CLI_CALL} dumptxoutset "${OUTPUT_PATH}" -fi 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/README.md b/contrib/guix/README.md index 6fb647f8a9..5e05e1016e 100644 --- a/contrib/guix/README.md +++ b/contrib/guix/README.md @@ -261,6 +261,7 @@ details. - `guix` build commands as in `guix shell --cores="$JOBS"` - `make` as in `make --jobs="$JOBS"` + - `cmake` as in `cmake --build build -j "$JOBS"` - `xargs` as in `xargs -P"$JOBS"` See [here](#controlling-the-number-of-threads-used-by-guix-build-commands) for diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index f589ac7a55..3184cd4afe 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)" @@ -178,9 +176,16 @@ make -C depends --jobs="$JOBS" HOST="$HOST" \ x86_64_linux_AR=x86_64-linux-gnu-gcc-ar \ x86_64_linux_RANLIB=x86_64-linux-gnu-gcc-ranlib \ x86_64_linux_NM=x86_64-linux-gnu-gcc-nm \ - x86_64_linux_STRIP=x86_64-linux-gnu-strip \ - FORCE_USE_SYSTEM_CLANG=1 + 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 # @@ -201,13 +206,13 @@ mkdir -p "$OUTDIR" ########################### # CONFIGFLAGS -CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests --disable-fuzz-binary" +CONFIGFLAGS="-DREDUCE_EXPORTS=ON -DBUILD_BENCH=OFF -DBUILD_GUI_TESTS=OFF -DBUILD_FUZZ_BINARY=OFF" # CFLAGS HOST_CFLAGS="-O2 -g" HOST_CFLAGS+=$(find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;) case "$HOST" in - *linux*) HOST_CFLAGS+=" -ffile-prefix-map=${PWD}=." ;; + *linux*) HOST_CFLAGS+=" -ffile-prefix-map=${DISTSRC}/src=." ;; *mingw*) HOST_CFLAGS+=" -fno-ident" ;; *darwin*) unset HOST_CFLAGS ;; esac @@ -225,8 +230,6 @@ case "$HOST" in *mingw*) HOST_LDFLAGS="-Wl,--no-insert-timestamp" ;; esac -# Make $HOST-specific native binaries from depends available in $PATH -export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}" mkdir -p "$DISTSRC" ( cd "$DISTSRC" @@ -234,38 +237,31 @@ mkdir -p "$DISTSRC" # Extract the source tarball tar --strip-components=1 -xf "${GIT_ARCHIVE}" - ./autogen.sh - # Configure this DISTSRC for $HOST # shellcheck disable=SC2086 - env CONFIG_SITE="${BASEPREFIX}/${HOST}/share/config.site" \ - ./configure --prefix=/ \ - --disable-ccache \ - --disable-maintainer-mode \ - --disable-dependency-tracking \ - ${CONFIGFLAGS} \ - ${HOST_CFLAGS:+CFLAGS="${HOST_CFLAGS}"} \ - ${HOST_CXXFLAGS:+CXXFLAGS="${HOST_CXXFLAGS}"} \ - ${HOST_LDFLAGS:+LDFLAGS="${HOST_LDFLAGS}"} - - sed -i.old 's/-lstdc++ //g' config.status libtool + env CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}" \ + cmake -S . -B build \ + --toolchain "${BASEPREFIX}/${HOST}/toolchain.cmake" \ + -DWITH_CCACHE=OFF \ + ${CONFIGFLAGS} # Build Bitcoin Core - make --jobs="$JOBS" ${V:+V=1} + cmake --build build -j "$JOBS" ${V:+--verbose} # Check that symbol/security checks tools are sane. - make test-security-check ${V:+V=1} + cmake --build build --target test-security-check ${V:+--verbose} # Perform basic security checks on a series of executables. - make -C src --jobs=1 check-security ${V:+V=1} + cmake --build build -j 1 --target check-security ${V:+--verbose} # Check that executables only contain allowed version symbols. - make -C src --jobs=1 check-symbols ${V:+V=1} + cmake --build build -j 1 --target check-symbols ${V:+--verbose} mkdir -p "$OUTDIR" # Make the os-specific installers case "$HOST" in *mingw*) - make deploy ${V:+V=1} BITCOIN_WIN_INSTALLER="${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe" + cmake --build build -j "$JOBS" -t deploy ${V:+--verbose} + mv build/bitcoin-win64-setup.exe "${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe" ;; esac @@ -277,20 +273,25 @@ mkdir -p "$DISTSRC" # Install built Bitcoin Core to $INSTALLPATH case "$HOST" in *darwin*) - make install-strip DESTDIR="${INSTALLPATH}" ${V:+V=1} + # This workaround can be dropped for CMake >= 3.27. + # See the upstream commit 689616785f76acd844fd448c51c5b2a0711aafa2. + find build -name 'cmake_install.cmake' -exec sed -i 's| -u -r | |g' {} + + + cmake --install build --strip --prefix "${INSTALLPATH}" ${V:+--verbose} ;; *) - make install DESTDIR="${INSTALLPATH}" ${V:+V=1} + cmake --install build --prefix "${INSTALLPATH}" ${V:+--verbose} ;; esac case "$HOST" in *darwin*) - make deploydir ${V:+V=1} + cmake --build build --target deploy ${V:+--verbose} + mv build/dist/Bitcoin-Core.zip "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip" mkdir -p "unsigned-app-${HOST}" cp --target-directory="unsigned-app-${HOST}" \ contrib/macdeploy/detached-sig-create.sh - mv --target-directory="unsigned-app-${HOST}" dist + mv --target-directory="unsigned-app-${HOST}" build/dist ( cd "unsigned-app-${HOST}" find . -print0 \ @@ -299,23 +300,18 @@ mkdir -p "$DISTSRC" | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" \ || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" && exit 1 ) ) - make deploy ${V:+V=1} OSX_ZIP="${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip" ;; esac ( cd installed - # Prune libtool and object archives - find . -name "lib*.la" -delete - find . -name "lib*.a" -delete - case "$HOST" in *darwin*) ;; *) # Split binaries from their debug symbols { find "${DISTNAME}/bin" -type f -executable -print0 - } | xargs -0 -P"$JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg + } | xargs -0 -P"$JOBS" -I{} "${DISTSRC}/build/split-debug.sh" {} {} {}.dbg ;; esac diff --git a/contrib/guix/libexec/prelude.bash b/contrib/guix/libexec/prelude.bash index ce6a9562b4..428fc41e73 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=dc4842797bfdc5f9f3f5f725bf189c2b68bd6b5a \ + --commit=53396a22afc04536ddf75d8f82ad2eafa5082725 \ --cores="$JOBS" \ --keep-failed \ --fallback \ diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 40500ccb88..e5ebecbf93 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -1,5 +1,4 @@ (use-modules (gnu packages) - (gnu packages autotools) ((gnu packages bash) #:select (bash-minimal)) (gnu packages bison) ((gnu packages certs) #:select (nss-certs)) @@ -22,9 +21,9 @@ ((gnu packages tls) #:select (openssl)) ((gnu packages version-control) #:select (git-minimal)) (guix build-system cmake) - (guix build-system gnu) (guix build-system python) (guix build-system trivial) + (guix download) (guix gexp) (guix git-download) ((guix licenses) #:prefix license:) @@ -91,14 +90,15 @@ chain for " target " development.")) (home-page (package-home-page xgcc)) (license (package-license xgcc))))) -(define base-gcc gcc-12) +(define base-gcc gcc-12) ;; 12.4.0 + (define base-linux-kernel-headers linux-libre-headers-6.1) (define* (make-bitcoin-cross-toolchain target #:key (base-gcc-for-libc linux-base-gcc) (base-kernel-headers base-linux-kernel-headers) - (base-libc glibc-2.27) + (base-libc glibc-2.31) (base-gcc linux-base-gcc)) "Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values desirable for building Bitcoin Core release binaries." @@ -116,10 +116,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 @@ -427,6 +434,7 @@ inspecting signatures in Mach-O binaries.") "--enable-default-ssp=yes", "--enable-default-pie=yes", "--enable-standard-branch-protection=yes", + "--enable-cet=yes", building-on))) ((#:phases phases) `(modify-phases ,phases @@ -440,30 +448,28 @@ inspecting signatures in Mach-O binaries.") (("-rpath=") "-rpath-link=")) #t)))))))) -(define-public glibc-2.27 +(define-public glibc-2.31 + (let ((commit "8e30f03744837a85e33d84ccd34ed3abe30d37c3")) (package - (inherit glibc-2.31) - (version "2.27") + (inherit glibc) ;; 2.35 + (version "2.31") (source (origin (method git-fetch) (uri (git-reference (url "https://sourceware.org/git/glibc.git") - (commit "73886db6218e613bd6d4edf529f11e008a6c2fa6"))) - (file-name (git-file-name "glibc" "73886db6218e613bd6d4edf529f11e008a6c2fa6")) + (commit commit))) + (file-name (git-file-name "glibc" commit)) (sha256 (base32 - "0azpb9cvnbv25zg8019rqz48h8i2257ngyjg566dlnp74ivrs9vq")) - (patches (search-our-patches "glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch" - "glibc-2.27-fcommon.patch" - "glibc-2.27-guix-prefix.patch" - "glibc-2.27-no-librt.patch" - "glibc-2.27-powerpc-ldbrx.patch")))) + "1zi0s9yy5zkisw823vivn7zlj8w6g9p3mm7lmlqiixcxdkz4dbn6")) + (patches (search-our-patches "glibc-guix-prefix.patch")))) (arguments (substitute-keyword-arguments (package-arguments glibc) ((#:configure-flags flags) `(append ,flags ;; https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html (list "--enable-stack-protector=all", + "--enable-cet", "--enable-bind-now", "--disable-werror", building-on))) @@ -473,12 +479,13 @@ inspecting signatures in Mach-O binaries.") (lambda* (#:key outputs #:allow-other-keys) ;; Install the rpc data base file under `$out/etc/rpc'. ;; Otherwise build will fail with "Permission denied." + ;; Can be removed when we are building 2.32 or later. (let ((out (assoc-ref outputs "out"))) (substitute* "sunrpc/Makefile" (("^\\$\\(inst_sysconfdir\\)/rpc(.*)$" _ suffix) (string-append out "/etc/rpc" suffix "\n")) (("^install-others =.*$") - (string-append "install-others = " out "/etc/rpc\n")))))))))))) + (string-append "install-others = " out "/etc/rpc\n"))))))))))))) (packages->manifest (append @@ -502,13 +509,10 @@ 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 @@ -517,24 +521,19 @@ 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-17 - lld-17 - (make-lld-wrapper lld-17 #:lld-as-ld? #t) + (list clang-toolchain-18 + lld-18 + (make-lld-wrapper lld-18 #:lld-as-ld? #t) python-signapple zip)) (else '()))))) 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/glibc-2.27-fcommon.patch b/contrib/guix/patches/glibc-2.27-fcommon.patch deleted file mode 100644 index f8d14837fc..0000000000 --- a/contrib/guix/patches/glibc-2.27-fcommon.patch +++ /dev/null @@ -1,34 +0,0 @@ -commit 264a4a0dbe1f4369db315080034b500bed66016c -Author: fanquake <fanquake@gmail.com> -Date: Fri May 6 11:03:04 2022 +0100 - - build: use -fcommon to retain legacy behaviour with GCC 10 - - GCC 10 started using -fno-common by default, which causes issues with - the powerpc builds using gibc 2.27. A patch was committed to glibc to fix - the issue, 18363b4f010da9ba459b13310b113ac0647c2fcc but is non-trvial - to backport, and was broken in at least one way, see the followup in - commit 7650321ce037302bfc2f026aa19e0213b8d02fe6. - - For now, retain the legacy GCC behaviour by passing -fcommon when - building glibc. - - https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html. - https://sourceware.org/git/?p=glibc.git;a=commit;h=18363b4f010da9ba459b13310b113ac0647c2fcc - https://sourceware.org/git/?p=glibc.git;a=commit;h=7650321ce037302bfc2f026aa19e0213b8d02fe6 - - This patch can be dropped when we are building with glibc 2.31+. - -diff --git a/Makeconfig b/Makeconfig -index 86a71e5802..aa2166be60 100644 ---- a/Makeconfig -+++ b/Makeconfig -@@ -896,7 +896,7 @@ ifeq "$(strip $(+cflags))" "" - endif # $(+cflags) == "" - - +cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags) \ -- $(+stack-protector) -+ $(+stack-protector) -fcommon - +gcc-nowarn := -w - - # Don't duplicate options if we inherited variables from the parent. diff --git a/contrib/guix/patches/glibc-2.27-no-librt.patch b/contrib/guix/patches/glibc-2.27-no-librt.patch deleted file mode 100644 index 4f2092ba7e..0000000000 --- a/contrib/guix/patches/glibc-2.27-no-librt.patch +++ /dev/null @@ -1,53 +0,0 @@ -This patch can be dropped when we are building with glibc 2.30+. - -commit 6e41ef56c9baab719a02f1377b1e7ce7bff61e73 -Author: Florian Weimer <fweimer@redhat.com> -Date: Fri Feb 8 10:21:56 2019 +0100 - - rt: Turn forwards from librt to libc into compat symbols [BZ #24194] - - As the result of commit 6e6249d0b461b952d0f544792372663feb6d792a - ("BZ#14743: Move clock_* symbols from librt to libc."), in glibc 2.17, - clock_gettime, clock_getres, clock_settime, clock_getcpuclockid, - clock_nanosleep were added to libc, and the file rt/clock-compat.c - was added with forwarders to the actual implementations in libc. - These forwarders were wrapped in - - #if SHLIB_COMPAT (librt, GLIBC_2_2, GLIBC_2_17) - - so that they are not present for newer architectures (such as - powerpc64le) with a 2.17 or later ABI baseline. But the forwarders - were not marked as compatibility symbols. As a result, on older - architectures, historic configure checks such as - - AC_CHECK_LIB(rt, clock_gettime) - - still cause linking against librt, even though this is completely - unnecessary. It also creates a needless porting hazard because - architectures behave differently when it comes to symbol availability. - - Reviewed-by: Carlos O'Donell <carlos@redhat.com> - -diff --git a/rt/clock-compat.c b/rt/clock-compat.c -index f816973c05..11e71aa890 100644 ---- a/rt/clock-compat.c -+++ b/rt/clock-compat.c -@@ -30,14 +30,16 @@ - #if HAVE_IFUNC - # undef INIT_ARCH - # define INIT_ARCH() --# define COMPAT_REDIRECT(name, proto, arglist) libc_ifunc (name, &__##name) -+# define COMPAT_REDIRECT(name, proto, arglist) libc_ifunc (name, &__##name) \ -+ compat_symbol (librt, name, name, GLIBC_2_2); - #else - # define COMPAT_REDIRECT(name, proto, arglist) \ - int \ - name proto \ - { \ - return __##name arglist; \ -- } -+ } \ -+ compat_symbol (librt, name, name, GLIBC_2_2); - #endif - - COMPAT_REDIRECT (clock_getres, diff --git a/contrib/guix/patches/glibc-2.27-powerpc-ldbrx.patch b/contrib/guix/patches/glibc-2.27-powerpc-ldbrx.patch deleted file mode 100644 index 26716054c8..0000000000 --- a/contrib/guix/patches/glibc-2.27-powerpc-ldbrx.patch +++ /dev/null @@ -1,245 +0,0 @@ -From 50b0b3c9ff71ffd7ebbd74ae46844c3566478123 Mon Sep 17 00:00:00 2001 -From: "Gabriel F. T. Gomes" <gabrielftg@linux.ibm.com> -Date: Mon, 27 May 2019 15:21:22 -0300 -Subject: [PATCH] powerpc: Fix build failures with current GCC - -Since GCC commit 271500 (svn), also known as the following commit on the -git mirror: - -commit e154242724b084380e3221df7c08fcdbd8460674 -Author: amodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4> -Date: Wed May 22 04:34:26 2019 +0000 - - [RS6000] Don't pass -many to the assembler - -glibc builds are failing when an assembly implementation does not -declare the correct '.machine' directive, or when no such directive is -declared at all. For example, when a POWER6 instruction is used, but -'.machine power6' is not declared, the assembler will fail with an error -similar to the following: - - ../sysdeps/powerpc/powerpc64/power8/strcmp.S: Assembler messages: - 24 ../sysdeps/powerpc/powerpc64/power8/strcmp.S:55: Error: unrecognized opcode: `cmpb' - -This patch adds '.machine powerN' directives where none existed, as well -as it updates '.machine power7' directives on POWER8 files, because the -minimum binutils version required to build glibc (binutils 2.25) now -provides this machine version. It also adds '-many' to the assembler -command used to build tst-set_ppr.c. - -Tested for powerpc, powerpc64, and powerpc64le, as well as with -build-many-glibcs.py for powerpc targets. - -Reviewed-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com> ---- - sysdeps/powerpc/Makefile | 5 +++ - sysdeps/powerpc/powerpc64/power4/memcmp.S | 7 ++++ - sysdeps/powerpc/powerpc64/power7/strncmp.S | 1 + - .../powerpc/powerpc64/power8/fpu/s_llround.S | 1 + - sysdeps/powerpc/powerpc64/power8/strcasecmp.S | 36 ++++++------------- - sysdeps/powerpc/powerpc64/power8/strcasestr.S | 14 ++------ - sysdeps/powerpc/powerpc64/power8/strcmp.S | 1 + - 7 files changed, 28 insertions(+), 37 deletions(-) - -diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile -index 6aa683b03f..23126147df 100644 ---- a/sysdeps/powerpc/Makefile -+++ b/sysdeps/powerpc/Makefile -@@ -45,6 +45,11 @@ ifeq ($(subdir),misc) - sysdep_headers += sys/platform/ppc.h - tests += test-gettimebase - tests += tst-set_ppr -+ -+# This test is expected to run and exit with EXIT_UNSUPPORTED on -+# processors that do not implement the Power ISA 2.06 or greater. -+# But the test makes use of instructions from Power ISA 2.06 and 2.07. -+CFLAGS-tst-set_ppr.c += -Wa,-many - endif - - ifneq (,$(filter %le,$(config-machine))) -diff --git a/sysdeps/powerpc/powerpc64/power4/memcmp.S b/sysdeps/powerpc/powerpc64/power4/memcmp.S -index e5319f101f..38dcf4c9a1 100644 ---- a/sysdeps/powerpc/powerpc64/power4/memcmp.S -+++ b/sysdeps/powerpc/powerpc64/power4/memcmp.S -@@ -26,7 +26,14 @@ - # define MEMCMP memcmp - #endif - -+#ifndef __LITTLE_ENDIAN__ - .machine power4 -+#else -+/* Little endian is only available since POWER8, so it's safe to -+ specify .machine as power8 (or older), even though this is a POWER4 -+ file. Since the little-endian code uses 'ldbrx', power7 is enough. */ -+ .machine power7 -+#endif - ENTRY_TOCLESS (MEMCMP, 4) - CALL_MCOUNT 3 - -diff --git a/sysdeps/powerpc/powerpc64/power7/strncmp.S b/sysdeps/powerpc/powerpc64/power7/strncmp.S -index 0c7429d19f..10f898c5a3 100644 ---- a/sysdeps/powerpc/powerpc64/power7/strncmp.S -+++ b/sysdeps/powerpc/powerpc64/power7/strncmp.S -@@ -28,6 +28,7 @@ - const char *s2 [r4], - size_t size [r5]) */ - -+ .machine power7 - ENTRY_TOCLESS (STRNCMP, 5) - CALL_MCOUNT 3 - -diff --git a/sysdeps/powerpc/powerpc64/power8/fpu/s_llround.S b/sysdeps/powerpc/powerpc64/power8/fpu/s_llround.S -index a22fc63bb3..84c76ba0f9 100644 ---- a/sysdeps/powerpc/powerpc64/power8/fpu/s_llround.S -+++ b/sysdeps/powerpc/powerpc64/power8/fpu/s_llround.S -@@ -26,6 +26,7 @@ - - /* long long [r3] llround (float x [fp1]) */ - -+ .machine power8 - ENTRY_TOCLESS (__llround) - CALL_MCOUNT 0 - frin fp1,fp1 /* Round to nearest +-0.5. */ -diff --git a/sysdeps/powerpc/powerpc64/power8/strcasecmp.S b/sysdeps/powerpc/powerpc64/power8/strcasecmp.S -index 3a2efe2a64..eeacd40c7f 100644 ---- a/sysdeps/powerpc/powerpc64/power8/strcasecmp.S -+++ b/sysdeps/powerpc/powerpc64/power8/strcasecmp.S -@@ -91,21 +91,7 @@ - 3: \ - TOLOWER() - --#ifdef _ARCH_PWR8 --# define VCLZD_V8_v7 vclzd v8, v7; --# define MFVRD_R3_V1 mfvrd r3, v1; --# define VSUBUDM_V9_V8 vsubudm v9, v9, v8; --# define VPOPCNTD_V8_V8 vpopcntd v8, v8; --# define VADDUQM_V7_V8 vadduqm v9, v7, v8; --#else --# define VCLZD_V8_v7 .long 0x11003fc2 --# define MFVRD_R3_V1 .long 0x7c230067 --# define VSUBUDM_V9_V8 .long 0x112944c0 --# define VPOPCNTD_V8_V8 .long 0x110047c3 --# define VADDUQM_V7_V8 .long 0x11274100 --#endif -- -- .machine power7 -+ .machine power8 - - ENTRY (__STRCASECMP) - #ifdef USE_AS_STRNCASECMP -@@ -265,15 +251,15 @@ L(different): - #ifdef __LITTLE_ENDIAN__ - /* Count trailing zero. */ - vspltisb v8, -1 -- VADDUQM_V7_V8 -+ vadduqm v9, v7, v8 - vandc v8, v9, v7 -- VPOPCNTD_V8_V8 -+ vpopcntd v8, v8 - vspltb v6, v8, 15 - vcmpequb. v6, v6, v1 - blt cr6, L(shift8) - #else - /* Count leading zero. */ -- VCLZD_V8_v7 -+ vclzd v8, v7 - vspltb v6, v8, 7 - vcmpequb. v6, v6, v1 - blt cr6, L(shift8) -@@ -291,7 +277,7 @@ L(skipsum): - /* Merge and move to GPR. */ - vmrglb v6, v6, v7 - vslo v1, v6, v1 -- MFVRD_R3_V1 -+ mfvrd r3, v1 - /* Place the characters that are different in first position. */ - sldi rSTR2, rRTN, 56 - srdi rSTR2, rSTR2, 56 -@@ -301,7 +287,7 @@ L(skipsum): - vslo v6, v5, v8 - vslo v7, v4, v8 - vmrghb v1, v6, v7 -- MFVRD_R3_V1 -+ mfvrd r3, v1 - srdi rSTR2, rRTN, 48 - sldi rSTR2, rSTR2, 56 - srdi rSTR2, rSTR2, 56 -@@ -320,15 +306,15 @@ L(null_found): - #ifdef __LITTLE_ENDIAN__ - /* Count trailing zero. */ - vspltisb v8, -1 -- VADDUQM_V7_V8 -+ vadduqm v9, v7, v8 - vandc v8, v9, v7 -- VPOPCNTD_V8_V8 -+ vpopcntd v8, v8 - vspltb v6, v8, 15 - vcmpequb. v6, v6, v10 - blt cr6, L(shift_8) - #else - /* Count leading zero. */ -- VCLZD_V8_v7 -+ vclzd v8, v7 - vspltb v6, v8, 7 - vcmpequb. v6, v6, v10 - blt cr6, L(shift_8) -@@ -343,10 +329,10 @@ L(skipsum1): - vspltisb v10, 7 - vslb v10, v10, v10 - vsldoi v9, v0, v10, 1 -- VSUBUDM_V9_V8 -+ vsubudm v9, v9, v8 - vspltisb v8, 8 - vsldoi v8, v0, v8, 1 -- VSUBUDM_V9_V8 -+ vsubudm v9, v9, v8 - /* Shift and remove junk after null character. */ - #ifdef __LITTLE_ENDIAN__ - vslo v5, v5, v9 -diff --git a/sysdeps/powerpc/powerpc64/power8/strcasestr.S b/sysdeps/powerpc/powerpc64/power8/strcasestr.S -index 9fc24c29f9..e10f06fd86 100644 ---- a/sysdeps/powerpc/powerpc64/power8/strcasestr.S -+++ b/sysdeps/powerpc/powerpc64/power8/strcasestr.S -@@ -73,18 +73,8 @@ - vor reg, v8, reg; \ - vcmpequb. v6, reg, v4; - --/* TODO: change these to the actual instructions when the minimum required -- binutils allows it. */ --#ifdef _ARCH_PWR8 --#define VCLZD_V8_v7 vclzd v8, v7; --#else --#define VCLZD_V8_v7 .long 0x11003fc2 --#endif -- - #define FRAMESIZE (FRAME_MIN_SIZE+48) --/* TODO: change this to .machine power8 when the minimum required binutils -- allows it. */ -- .machine power7 -+ .machine power8 - ENTRY (STRCASESTR, 4) - CALL_MCOUNT 2 - mflr r0 /* Load link register LR to r0. */ -@@ -291,7 +281,7 @@ L(nullchk1): - vcmpequb. v6, v0, v7 - /* Shift r3 by 16 bytes and proceed. */ - blt cr6, L(shift16) -- VCLZD_V8_v7 -+ vclzd v8, v7 - #ifdef __LITTLE_ENDIAN__ - vspltb v6, v8, 15 - #else -diff --git a/sysdeps/powerpc/powerpc64/power8/strcmp.S b/sysdeps/powerpc/powerpc64/power8/strcmp.S -index 15e7351d1b..d592266d1d 100644 ---- a/sysdeps/powerpc/powerpc64/power8/strcmp.S -+++ b/sysdeps/powerpc/powerpc64/power8/strcmp.S -@@ -31,6 +31,7 @@ - 64K as default, the page cross handling assumes minimum page size of - 4k. */ - -+ .machine power8 - ENTRY_TOCLESS (STRCMP, 4) - li r0,0 - --- -2.41.0 diff --git a/contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch b/contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch deleted file mode 100644 index ab8ae9c023..0000000000 --- a/contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch +++ /dev/null @@ -1,78 +0,0 @@ -Note that this has been modified from the original commit, to use __has_include -instead of __has_include__, as the later was causing build failures with GCC 10. -See also: http://lists.busybox.net/pipermail/buildroot/2020-July/590376.html. - -https://sourceware.org/git/?p=glibc.git;a=commit;h=0b9c84906f653978fb8768c7ebd0ee14a47e662e - -This patch can be dropped when we are building with glibc 2.28+. - -From 562c52cc81a4e456a62e6455feb32732049e9070 Mon Sep 17 00:00:00 2001 -From: "H.J. Lu" <hjl.tools@gmail.com> -Date: Mon, 31 Dec 2018 09:26:42 -0800 -Subject: [PATCH] riscv: Use __has_include__ to include <asm/syscalls.h> [BZ - #24022] - -<asm/syscalls.h> has been removed by - -commit 27f8899d6002e11a6e2d995e29b8deab5aa9cc25 -Author: David Abdurachmanov <david.abdurachmanov@gmail.com> -Date: Thu Nov 8 20:02:39 2018 +0100 - - riscv: add asm/unistd.h UAPI header - - Marcin Juszkiewicz reported issues while generating syscall table for riscv - using 4.20-rc1. The patch refactors our unistd.h files to match some other - architectures. - - - Add asm/unistd.h UAPI header, which has __ARCH_WANT_NEW_STAT only for 64-bit - - Remove asm/syscalls.h UAPI header and merge to asm/unistd.h - - Adjust kernel asm/unistd.h - - So now asm/unistd.h UAPI header should show all syscalls for riscv. - -<asm/syscalls.h> may be restored by - -Subject: [PATCH] riscv: restore asm/syscalls.h UAPI header -Date: Tue, 11 Dec 2018 09:09:35 +0100 - -UAPI header asm/syscalls.h was merged into UAPI asm/unistd.h header, -which did resolve issue with missing syscalls macros resulting in -glibc (2.28) build failure. It also broke glibc in a different way: -asm/syscalls.h is being used by glibc. I noticed this while doing -Fedora 30/Rawhide mass rebuild. - -The patch returns asm/syscalls.h header and incl. it into asm/unistd.h. -I plan to send a patch to glibc to use asm/unistd.h instead of -asm/syscalls.h - -In the meantime, we use __has_include__, which was added to GCC 5, to -check if <asm/syscalls.h> exists before including it. Tested with -build-many-glibcs.py for riscv against kernel 4.19.12 and 4.20-rc7. - - [BZ #24022] - * sysdeps/unix/sysv/linux/riscv/flush-icache.c: Check if - <asm/syscalls.h> exists with __has_include__ before including it. ---- - sysdeps/unix/sysv/linux/riscv/flush-icache.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/sysdeps/unix/sysv/linux/riscv/flush-icache.c b/sysdeps/unix/sysv/linux/riscv/flush-icache.c -index d612ef4c6c..0b2042620b 100644 ---- a/sysdeps/unix/sysv/linux/riscv/flush-icache.c -+++ b/sysdeps/unix/sysv/linux/riscv/flush-icache.c -@@ -21,7 +21,11 @@ - #include <stdlib.h> - #include <atomic.h> - #include <sys/cachectl.h> --#include <asm/syscalls.h> -+#if __has_include (<asm/syscalls.h>) -+# include <asm/syscalls.h> -+#else -+# include <asm/unistd.h> -+#endif - - typedef int (*func_type) (void *, void *, unsigned long int); - --- -2.31.1 - diff --git a/contrib/guix/patches/glibc-2.27-guix-prefix.patch b/contrib/guix/patches/glibc-guix-prefix.patch index dc515907ff..60e12ca525 100644 --- a/contrib/guix/patches/glibc-2.27-guix-prefix.patch +++ b/contrib/guix/patches/glibc-guix-prefix.patch @@ -4,19 +4,13 @@ hash for the same package will differ when on different architectures. In order to be reproducible regardless of the architecture used to build the package, map all guix store prefixes to something fixed, e.g. /usr. -We might be able to drop this in favour of using --with-nonshared-cflags -when we begin using newer versions of glibc. - --- a/Makeconfig +++ b/Makeconfig -@@ -992,6 +992,10 @@ object-suffixes := +@@ -1007,6 +1007,7 @@ object-suffixes := CPPFLAGS-.o = $(pic-default) # libc.a must be compiled with -fPIE/-fpie for static PIE. CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) $(pie-default) -+ -+# Map Guix store paths to /usr +CFLAGS-.o += `find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;` -+ libtype.o := lib%.a object-suffixes += .o ifeq (yes,$(build-shared)) 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/macdeploy/README.md b/contrib/macdeploy/README.md index 78f61685e1..d47ee6774e 100644 --- a/contrib/macdeploy/README.md +++ b/contrib/macdeploy/README.md @@ -56,30 +56,22 @@ The `sha256sum` should be `c0c2e7bb92c1fee0c4e9f3a485e4530786732d6c6dd9e9f418c28 ## Deterministic macOS App Notes -macOS Applications are created in Linux using a recent LLVM. +macOS Applications are created on Linux using a recent LLVM. -Apple uses `clang` extensively for development and has upstreamed the necessary -functionality so that a vanilla clang can take advantage. It supports the use of `-F`, -`-target`, `-mmacosx-version-min`, and `-isysroot`, which are all necessary when -building for macOS. +All builds must target an Apple SDK. These SDKs are free to download, but not redistributable. +See the SDK Extraction notes above for how to obtain it. -To complicate things further, all builds must target an Apple SDK. These SDKs are free to -download, but not redistributable. See the SDK Extraction notes above for how to obtain it. +The Guix build process has been designed to avoid including the SDK's files in Guix's outputs. +All interim tarballs are fully deterministic and may be freely redistributed. -The Guix process builds 2 sets of files: Linux tools, then Apple binaries which are -created using these tools. The build process has been designed to avoid including the -SDK's files in Guix's outputs. All interim tarballs are fully deterministic and may be freely -redistributed. - -As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a requirement in -order to satisfy the new Gatekeeper requirements. Because this private key cannot be -shared, we'll have to be a bit creative in order for the build process to remain somewhat -deterministic. Here's how it works: +Using an Apple-blessed key to sign binaries is a requirement to produce (distributable) macOS +binaries. Because this private key cannot be shared, we'll have to be a bit creative in order +for the build process to remain somewhat deterministic. Here's how it works: - Builders use Guix to create an unsigned release. This outputs an unsigned ZIP which - users may choose to bless and run. It also outputs an unsigned app structure in the form - of a tarball. + users may choose to bless, self-codesign, and run. It also outputs an unsigned app structure + in the form of a tarball. - The Apple keyholder uses this unsigned app to create a detached signature, using the - script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs). -- Builders feed the unsigned app + detached signature back into Guix. It uses the - pre-built tools to recombine the pieces into a deterministic ZIP. + included script. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs). +- Builders feed the unsigned app + detached signature back into Guix, which combines the + pieces into a deterministic ZIP. diff --git a/contrib/macdeploy/gen-sdk b/contrib/macdeploy/gen-sdk index b73f5cba14..86a6262b5c 100755 --- a/contrib/macdeploy/gen-sdk +++ b/contrib/macdeploy/gen-sdk @@ -8,21 +8,6 @@ import gzip import os import contextlib -# monkey-patch Python 3.8 and older to fix wrong TAR header handling -# see https://github.com/bitcoin/bitcoin/pull/24534 -# and https://github.com/python/cpython/pull/18080 for more info -if sys.version_info < (3, 9): - _old_create_header = tarfile.TarInfo._create_header - def _create_header(info, format, encoding, errors): - buf = _old_create_header(info, format, encoding, errors) - # replace devmajor/devminor with binary zeroes - buf = buf[:329] + bytes(16) + buf[345:] - # recompute checksum - chksum = tarfile.calc_chksums(buf)[0] - buf = buf[:-364] + bytes("%06o\0" % chksum, "ascii") + buf[-357:] - return buf - tarfile.TarInfo._create_header = staticmethod(_create_header) - @contextlib.contextmanager def cd(path): """Context manager that restores PWD even if an exception was raised.""" diff --git a/contrib/seeds/.gitignore b/contrib/seeds/.gitignore index d9a2451f70..4e0ee74a0b 100644 --- a/contrib/seeds/.gitignore +++ b/contrib/seeds/.gitignore @@ -1,2 +1,3 @@ seeds_main.txt +seeds_test.txt asmap-filled.dat diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md index ad1ac4a64d..10945e5b68 100644 --- a/contrib/seeds/README.md +++ b/contrib/seeds/README.md @@ -8,13 +8,20 @@ and remove old versions as necessary (at a minimum when SeedsServiceFlags() changes its default return value, as those are the services which seeds are added to addrman with). -The seeds compiled into the release are created from sipa's DNS seed and AS map -data. Run the following commands from the `/contrib/seeds` directory: +The seeds compiled into the release are created from sipa's, achow101's and luke-jr's +DNS seed, virtu's crawler, and asmap community AS map data. Run the following commands +from the `/contrib/seeds` directory: ``` curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt -curl https://bitcoin.sipa.be/asmap-filled.dat > asmap-filled.dat +curl https://mainnet.achownodes.xyz/seeds.txt.gz | gzip -dc >> seeds_main.txt +curl https://21.ninja/seeds.txt.gz | gzip -dc >> seeds_main.txt +curl https://luke.dashjr.org/programs/bitcoin/files/charts/seeds.txt >> seeds_main.txt +curl https://testnet.achownodes.xyz/seeds.txt.gz | gzip -dc > seeds_test.txt +curl https://raw.githubusercontent.com/asmap/asmap-data/main/latest_asmap.dat > asmap-filled.dat python3 makeseeds.py -a asmap-filled.dat -s seeds_main.txt > nodes_main.txt -cat nodes_main_manual.txt >> nodes_main.txt +python3 makeseeds.py -a asmap-filled.dat -s seeds_test.txt > nodes_test.txt +# TODO: Uncomment when a seeder publishes seeds.txt.gz for testnet4 +# python3 makeseeds.py -a asmap-filled.dat -s seeds_testnet4.txt -m 30000 > nodes_testnet4.txt python3 generate-seeds.py . > ../../src/chainparamsseeds.h ``` 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/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 7fd0f7158e..0f22046625 100755 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -10,6 +10,7 @@ import argparse import collections import ipaddress from pathlib import Path +import random import re import sys from typing import Union @@ -25,7 +26,7 @@ MAX_SEEDS_PER_ASN = { 'ipv6': 10, } -MIN_BLOCKS = 730000 +MIN_BLOCKS = 840000 PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$") PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$") @@ -41,11 +42,13 @@ PATTERN_AGENT = re.compile( r"0.19.(0|1|2|99)|" r"0.20.(0|1|2|99)|" r"0.21.(0|1|2|99)|" - r"22.(0|1|99)|" - r"23.(0|1|99)|" - r"24.(0|1|99)|" - r"25.(0|1|99)|" - r"26.(0|99)|" + r"22.(0|1|99).0|" + r"23.(0|1|99).0|" + r"24.(0|1|2|99).(0|1)|" + r"25.(0|1|2|99).0|" + r"26.(0|1|99).0|" + r"27.(0|1|99).0|" + r"28.(0|99).0|" r")") def parseline(line: str) -> Union[dict, None]: @@ -86,6 +89,8 @@ def parseline(line: str) -> Union[dict, None]: if m.group(1) in ['::']: # Not interested in localhost return None ipstr = m.group(1) + if ipstr.startswith("fc"): # cjdns looks like ipv6 but always begins with fc + net = "cjdns" sortkey = ipstr # XXX parse IPv6 into number, could use name_to_ipv6 from generate-seeds port = int(m.group(2)) else: @@ -152,6 +157,7 @@ def filterbyasn(asmap: ASMap, ips: list[dict], max_per_asn: dict, max_per_net: i ips_ipv46 = [ip for ip in ips if ip['net'] in ['ipv4', 'ipv6']] ips_onion = [ip for ip in ips if ip['net'] == 'onion'] ips_i2p = [ip for ip in ips if ip['net'] == 'i2p'] + ips_cjdns = [ip for ip in ips if ip["net"] == "cjdns"] # Filter IPv46 by ASN, and limit to max_per_net per network result = [] @@ -176,6 +182,7 @@ def filterbyasn(asmap: ASMap, ips: list[dict], max_per_asn: dict, max_per_net: i # Add back Onions (up to max_per_net) result.extend(ips_onion[0:max_per_net]) result.extend(ips_i2p[0:max_per_net]) + result.extend(ips_cjdns[0:max_per_net]) return result def ip_stats(ips: list[dict]) -> str: @@ -185,12 +192,13 @@ def ip_stats(ips: list[dict]) -> str: if ip is not None: hist[ip['net']] += 1 - return f"{hist['ipv4']:6d} {hist['ipv6']:6d} {hist['onion']:6d} {hist['i2p']:6d}" + return f"{hist['ipv4']:6d} {hist['ipv6']:6d} {hist['onion']:6d} {hist['i2p']:6d} {hist['cjdns']:6d}" def parse_args(): argparser = argparse.ArgumentParser(description='Generate a list of bitcoin node seed ip addresses.') argparser.add_argument("-a","--asmap", help='the location of the asmap asn database file (required)', required=True) argparser.add_argument("-s","--seeds", help='the location of the DNS seeds file (required)', required=True) + argparser.add_argument("-m", "--minblocks", help="The minimum number of blocks each node must have", default=MIN_BLOCKS, type=int) return argparser.parse_args() def main(): @@ -205,9 +213,10 @@ def main(): with open(args.seeds, 'r', encoding='utf8') as f: lines = f.readlines() ips = [parseline(line) for line in lines] + random.shuffle(ips) print('Done.', file=sys.stderr) - print('\x1b[7m IPv4 IPv6 Onion I2P Pass \x1b[0m', file=sys.stderr) + print('\x1b[7m IPv4 IPv6 Onion I2P CJDNS Pass \x1b[0m', file=sys.stderr) print(f'{ip_stats(ips):s} Initial', file=sys.stderr) # Skip entries with invalid address. ips = [ip for ip in ips if ip is not None] @@ -216,17 +225,18 @@ def main(): ips = dedup(ips) print(f'{ip_stats(ips):s} After removing duplicates', file=sys.stderr) # Enforce minimal number of blocks. - ips = [ip for ip in ips if ip['blocks'] >= MIN_BLOCKS] + ips = [ip for ip in ips if ip['blocks'] >= args.minblocks] print(f'{ip_stats(ips):s} Enforce minimal number of blocks', file=sys.stderr) # Require service bit 1. ips = [ip for ip in ips if (ip['service'] & 1) == 1] print(f'{ip_stats(ips):s} Require service bit 1', file=sys.stderr) - # Require at least 50% 30-day uptime for clearnet, 10% for onion and i2p. + # Require at least 50% 30-day uptime for clearnet, onion and i2p; 10% for cjdns req_uptime = { 'ipv4': 50, 'ipv6': 50, - 'onion': 10, - 'i2p' : 10, + 'onion': 50, + 'i2p': 50, + 'cjdns': 10, } ips = [ip for ip in ips if ip['uptime'] > req_uptime[ip['net']]] print(f'{ip_stats(ips):s} Require minimum uptime', file=sys.stderr) @@ -244,7 +254,7 @@ def main(): # Sort the results by IP address (for deterministic output). ips.sort(key=lambda x: (x['net'], x['sortkey'])) for ip in ips: - if ip['net'] == 'ipv6': + if ip['net'] == 'ipv6' or ip["net"] == "cjdns": print(f"[{ip['ip']}]:{ip['port']}", end="") else: print(f"{ip['ip']}:{ip['port']}", end="") diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index be7607c0f7..d68a5b8d57 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -1,534 +1,1069 @@ -1.253.159.19:8333 # AS9318 -2.152.74.211:8333 # AS12430 +[fc1f:22c3:95dc:a3af:4a93:8251:beb9:1858]:8333 +[fc6d:f562:86a0:791d:8a20:7aa2:8879:2176]:8333 +[fc70:de9d:7fe2:b32:5828:1a3c:d0f:83ec]:8333 +[fc95:6edb:af65:9ea3:cd27:21ef:f5e2:29c6]:8333 +[fca0:151:79ac:8992:b51e:bdc4:6ed9:41be]:8333 +[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333 +[fccb:248:11a6:1042:bca:1218:f7ce:7d3d]:8333 +[fcf1:22ff:3070:582f:a873:61bc:4bc1:81bf]:8333 +23zqyu5dxq3gilx5dihlyjh6tbkwombyaks4pbeyg2pqjvv7putq.b32.i2p:0 +26wyxyscoasntccp6k3earcilrykkgzfrdit2zfw5m4patocvuqq.b32.i2p:0 +26xo6ouiqida6fivk7cfirvyss4eqoiefoim6pecdqietfwxnulq.b32.i2p:0 +2dsyxnxzwo6ltuo3hndnoop2qc2pj2czfgmjbjnqrnnxffmr2oaa.b32.i2p:0 +2eshemvuvyahgshefs47wt3eqg3vvxw5jzlxm6lidye5d6zgclja.b32.i2p:0 +2fkjb2o7p4gdj6hjiytgkhvitqwjrn7kmdxzduwiskpycnzhvkwa.b32.i2p:0 +2hjwtokw4mxvtkm5po63kjhyo7lfsarfcgqp2hp5i4epx3qvtnua.b32.i2p:0 +2jgfxxzts6rfr5m2iwklltya2kmuejnkufpt4bavwjhi2j7fmyma.b32.i2p:0 +2jt5aukq3ik7bu4frugi5udkwlckhhgxrzjhjvfzieomkx4agxqq.b32.i2p:0 +2k3lztzfal3k6dl7yrh2jykfa3xpmou2c7cm2ewo4qctkkvbhfvq.b32.i2p:0 +2kb3aja6lo6pu2b27tos64tgo4kxzate2z4ew3mpmksqh6wzjsta.b32.i2p:0 +2muk57255tdm4g273fy7aitrmqnturut6krqojxz76jssrqm2rsa.b32.i2p:0 +2o4zoex2pqqybdyxuwoimn3ke23aqo4fnaglmr4hwhaubhneppoq.b32.i2p:0 +2od4gsib5knkq5fhbmysp3nbehts67nfa26jv6gkesehwycv7tfa.b32.i2p:0 +2ot7eiaasbxhha2txgsjd4e6inugidh6yronjdkiyba5ss3kty2q.b32.i2p:0 +2rbmv3hyr4l42ysvj62dgozlmosdsr65x4dqgvx3axfzyw2uytnq.b32.i2p:0 +2v5nr3u3scbyxd3nkqxinw2pvqqe66y4hc3u6gotil2sgbyivruq.b32.i2p:0 +2vslelcwzyxvvm3rzr2irbvaw7eyillztwfrdd24zshhwhf5rmjq.b32.i2p:0 +2vwlmwbsnm6fiffcl5ngz4g7r4tyieu7j4xmpwlmc2xxl2myd2zq.b32.i2p:0 +2xnwvq4msaylv2aom7nhufsjyqho7qh3gpiej2wbl6imdfalyroq.b32.i2p:0 +2z4qckqjkz2xjwrohij664qlaraxo2ryascslw4ehfjxtltwolzq.b32.i2p:0 +37tmwq2dy4smqg46qkgvs5poca3hceoephgk5onjrgjxyph4ddlq.b32.i2p:0 +3ctq5jucmugxjum2xammfbzgdmsx23ak3peuk64b7vgq5w4z7hqq.b32.i2p:0 +3d5hlguo3yzbzwb7ek46uck2m67u4yuup456wywdvzhzazcu43vq.b32.i2p:0 +3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0 +3hziidrpzqvns4jwfqhzb7nydw4mtnnkawperfvnaru3zpup2ihq.b32.i2p:0 +3iixvywxqwns477r6axhylfcteq5bwggy7cmrbutqred54kigwoa.b32.i2p:0 +3jqjyte2k6xnoetygm6gfakisuz3eqxr3fcu4l5kmu3zifpnkhvq.b32.i2p:0 +3oa5fycx3tyechdfgootxcpap7sx7p3sawenrbzyyxrty74rt7zq.b32.i2p:0 +3r7m5mbeogkr6sy66f6g325nsf2jiimtfdn5v6wpxz6uqmsybqja.b32.i2p:0 +3s7zmamgfmlhwvrn5ov32uugbldoka7jxbetu6tjsq3bzkrb5dca.b32.i2p:0 +3uudj6lfywjqrbiplgwoaxpeb2k4ma75mlmpiq7owv3bofwlvadq.b32.i2p:0 +3y4oiw7cglzzshasapfmlte7ixbgpl4js7w2afsd4znemu4ddefa.b32.i2p:0 +42guqsvdee4tmq3qa5mjw5vjkzkkuk5eainecsrsdfex3wyf7twq.b32.i2p:0 +44qb3nfsrer2f4eyh54s7qdvwxiykjrer76jjevcbpdn3i6uayba.b32.i2p:0 +44vneaemid75co5t7rjnp3ofpar52gg2hbqy7cmolfnl2yhjcmpq.b32.i2p:0 +45eh6rxbfli4ju26cqaf63vfs5xx6zgt7hn3uzzz3nem45d4ps6q.b32.i2p:0 +46xory66pc6qxd6glapmcrxujp6wc5swghhbnhybvewxffo37gaq.b32.i2p:0 +47jrlqld6m7abax6mmly23pg4hyapckmx4hhzzsozkgaswqu3nbq.b32.i2p:0 +4b7mcou7wtazoxwxpm5tl4tk7qaalnabd6i7wvnmpv5omvo7ogla.b32.i2p:0 +4dduiytop3qjiodb2jnwvhvnyr6w3y5axz3vzk5qrfefur4fg6qq.b32.i2p:0 +4dixsgdl3bpnkiahm7uanupycpfg53hxobxgm5fsnsvpt2yhalqa.b32.i2p:0 +4lfukvzjcupsvjdtoyealabzbdsp3ar4tjbhxtwypbb2l7m2cpwq.b32.i2p:0 +4lmhn2xqfineeyquxxv5ixozqkn4eyuzcclk626q67impx5hnnhq.b32.i2p:0 +4lommnxazy6c734yycbmzqkodlzcxpwsby5wlmhnhcbygamgwrxa.b32.i2p:0 +4miplwxnwh3lnaag2pjehdyxyzgrfz6yc6vwulbug6jr4rnetzjq.b32.i2p:0 +4nxdyltgdwpfkautpralacdlolzlpwr43cj4ig4gozn5y43gk6nq.b32.i2p:0 +4ripix2seo5ac3bjb4a5louhtbycghyf3leysidy22wnbak7tzjq.b32.i2p:0 +4ro6okb3x64g7u4khhc7rqalmkwkkumbavkcx7vqpcvki2una72a.b32.i2p:0 +4s37ey3w4lncs6xxycnxksbhatfvx2ttgc3obdvpirir4zzjassq.b32.i2p:0 +57shcfzia75ketlrqrnvgxvaijhbtn3snrjw663ank5baj7qr25a.b32.i2p:0 +5agylbfkuwwqnyiqwtgxgqlybokkqfvoxwjbkc732cbot5f2z4nq.b32.i2p:0 +5bqnpm3tqlkygqgu5lnzxxuw6bbjdzqkdbbmlfbzn434qpyj7mtq.b32.i2p:0 +5emthm7lukjah2pnqourmnhjk6zhujrgzjqdevezdf6d6valclia.b32.i2p:0 +5f2sx5ne2cd5mtobr2abegmzwh2o6iie3ylrhgjdkbivjqbdmpeq.b32.i2p:0 +5ikjy5pzgjk37hh7fcknyyhx5v5lkchjqknx7hyrffrj7hv7lybq.b32.i2p:0 +5kog73uwths255tdrwee7dc2pshq6xlukbxtpgn3bbwunm52jwdq.b32.i2p:0 +5mcxlytzx54cd5w6oumos3ab7yya3wxazrqct4uc62f2d2ts3zaq.b32.i2p:0 +5nvlednvsjhp75f75pmlyzaujkzsvwckvvsyuavrslfcq5zgj3ta.b32.i2p:0 +5pjaaexikmlyhl5dihzvqbykuec6uzkyujvvs5bjoi6htlb3oxzq.b32.i2p:0 +5puvvkyv6qr2kaqb2avbqxzhdyiquhk2767omhoa2s52gcnfcx4q.b32.i2p:0 +5rojgskvcimuseeaxpjiohmb6b5r5vs6v6hheay3kemraqvmg6iq.b32.i2p:0 +5unuudrnxqkdgqsrfbsmx3i6iwwthivngtfm7sddptjizpqxphbq.b32.i2p:0 +5xsuuiufbmoncdvwk55rd4qs24oemoutharh5hn62y7pn6rzk6ea.b32.i2p:0 +62srw23f4rrxzs3253g7mb2lbop3pfpsu56g5iiptrao3qoasd4a.b32.i2p:0 +6dkvhlhwoiwpdjpebuemxq66soh6os6xa2sq42dwhfbp3d4sdzga.b32.i2p:0 +6e3bigypatmvcutfntlonhrhpfc5y4hbl4cyabgjv2wt6fhwjx3q.b32.i2p:0 +6hqodynvvfa3yflrcvmpniyn5v3idtkctx7gijdlv5wdd37xnq4a.b32.i2p:0 +6jh4xdqs35lkhqnynxctyhqikcnyplvs4juvgbjt4zdlzrt4uphq.b32.i2p:0 +6mhlke4onpdqcfkae6yi23mefnt24xgvipbo24kqluz2yx6fcuoq.b32.i2p:0 +6mroga77egf2fzs7y46huhxwesppxx6k72jc7h2cznq2fmcaelsq.b32.i2p:0 +6nhfpjg54gdwz2jlp3qzt6mdvkk5fp7jr4bc35ph3k5q7dn6cnfq.b32.i2p:0 +6nhgac6wpmchhcmoy36ypaeu6ubc7fq4sui6phin4zpakj3mmbxa.b32.i2p:0 +6nxoamjjskfftfulrxss5mvob56yuif4fxhix6xsw25igu4h7eea.b32.i2p:0 +6rb4nnnlaatjspeoqx53gi7p2y4fagwtuchl2m2l32hherjgkaya.b32.i2p:0 +6vvxiiqmpcaazzfx5h23a6hppgtmsa75g3oeiil5f5hyvgneq2ha.b32.i2p:0 +6vxaw4dduy3hfoff4atqfkt4dc3yd73wimldeempfrfrh6qyfdxa.b32.i2p:0 +6wtsedonta5yojby77ateqk2opazkduz7bur7loo7ds3r2u6xvaq.b32.i2p:0 +6wxenlvtjz4e74cp5dcy6ew2swj4lgcw4wqt46xbeyzegwfs2eaq.b32.i2p:0 +6ycdrrj4shtvp5y5o5nagxth6e75nrlpngeswptxlzaxaq5ttqja.b32.i2p:0 +76objhdrw6swklvz62by5vfdldugdmjz7rifbkbuae72scbdoj6q.b32.i2p:0 +7767yywxn22on4vt6elw66ondhcck7lqcadp34b22mufecj2wyma.b32.i2p:0 +77dalsgr4vbjkdn3frhiklvegub6abglscaqraiuqwn33c3vtw7a.b32.i2p:0 +7ccbhxe3ojas5ek6gtyqg64mqcdcqkrze43nuwdlofeh5t3frdoq.b32.i2p:0 +7d3mfvmjbyvxtaigtz25w7rbnbqszutcgvoai4glh3zuv34glpxa.b32.i2p:0 +7dqje2cdumk5yef346ws7w5t63cm3jjiib3zmtdxxknaqv5axsua.b32.i2p:0 +7e6xz5pfnwsns43cxi7qygyasyvlfrk7gjeqlm6asl6pbn4xf3kq.b32.i2p:0 +7etpy33vv4lz6wmmn4o3o7hubggsigxnla3eoc4ymcy6deoctwhq.b32.i2p:0 +7fddpunmty7eruhumq2iqa2yw5ckcn6xpsw26pj6csnhnty3jcqa.b32.i2p:0 +7fq6qhlxkxc2zbtshlhef3fv6sodqis4sa4ojf5ehilho6d3kvnq.b32.i2p:0 +7g6nadgsvdk6helddu7nczhhspvb54wgovhxb3djkpd4vbtkydtq.b32.i2p:0 +7hpvrb7clik652nf3s6whlkx4pjxowtpidlz273uzn2st5bymzpa.b32.i2p:0 +7iiic2ikrwmchsnlvw6jn75vpvtuugx7mqebbl6ynl4yit7a6jlq.b32.i2p:0 +7jwvx7eged34ctrgyrt5y6x5p7xzkfpidvwrxjplqywqa5dqlg3a.b32.i2p:0 +7l6l47l7pwi7vfe7romlkpnoqu76dr4gphrdmic4tzdkgiifgz5q.b32.i2p:0 +7owux5a335qgy57z7levn7efo5pnzvlvmbht46ua7cwi5jq6rhwa.b32.i2p:0 +7q2p3tvy4fw335pnmpcykdujnkg273mhqc4ou2iunqsia52bgjoa.b32.i2p:0 +7qsw6acv762ofynms5z2e354tvp2k4527l6ifor7w3uklzaitd3q.b32.i2p:0 +7r4gaxkb2iwndafis2dczac3a2mfssxekexfvf53p7siizugg2wa.b32.i2p:0 +7r4ri53lby2i3xqbgpw3idvhzeku7ubhftlf72ldqkg5kde6dauq.b32.i2p:0 +7rbqtt4zauewbonbcvaiimflvxjkipb5t7gusyp7mfdqlepnkbdq.b32.i2p:0 +7trydzxax7oh34p3totxie57k3xiqvbdc3b2gbpjuda7oyeqo5ia.b32.i2p:0 +7ttjllhoemvcjwg4qzgrcrq2uy3c43ungndomb4eahcsjy25euyq.b32.i2p:0 +7utc6ztzqaljtirabf3l5ynvf3akmzofayid4caia6nd6z6a2ebq.b32.i2p:0 +7wgrywhskd24kqqjvodx6bxnjnv374xlnrwssy7zqd4wza5drqmq.b32.i2p:0 +7wp4rrff3fbrudrj5uzsvq4xofktj5tj7omnpcqw4m7rcjshs3za.b32.i2p:0 +a2zioocy4z3jijn6qzl2grifqd7hvuk6kagjv5maoqrnxwoucdoq.b32.i2p:0 +a57uc45crgyttfs6ij3fr44q4w5ij6yy6fmhbky374au7rtq4s2a.b32.i2p:0 +abxmmqkduni73ki6aazyl5z3b6ebh63cfse43zo2fgvpqo75l7rq.b32.i2p:0 +admfhd2d3gu3vevarjd6tbty7rq7fburhkj74x5uagc4oguvmtzq.b32.i2p:0 +aho2rjopjdeh33fi67pbk3ylrf7gynvxzmw6mpuwufcqyzyxgzba.b32.i2p:0 +ajol74c46igadlezendhvwt56gcmrdcahu4jdabt7o6n4vn2xv6q.b32.i2p:0 +aoop5n4khqbob6fvc2nxyyoleenefrykudtrbtjsh3acsqjjkdqa.b32.i2p:0 +aopnrdf454a46vqnvgcx7gk3k5ua5gvmhtovqodnqgzcc65hf7ha.b32.i2p:0 +aorbiqlyf3gwukti7w2cpe3msp2ak6d4qelya2umhph2gfa4d53a.b32.i2p:0 +aqj2d5wykbhure5yfaudeedomwho4gbz2lg3lhbmd6odhy47edta.b32.i2p:0 +aqtqmjzm6tvrodvmnijfwcn7guwmgshb6yccflkpfi7nacfl5fqa.b32.i2p:0 +asisbyliqgpny4tsgdov6tvmluezz7vukut4yqkpgpxkrl5da7ja.b32.i2p:0 +auceh5qut5hck4gzlh2xjtw5qodginqixew4oteqoziwtg4oc44a.b32.i2p:0 +aue5ldovw4zb2ai3nsjiesdhjhdngga2jofptptao3gdiujcqdfq.b32.i2p:0 +awwhyxxxs7kkb2pvgr563c4n4mazrivrmofw7rdx2zdu34lwzswa.b32.i2p:0 +ay4che3hbd2p6ma5qeo6kb5ghin4dt2nh4bsppcekvjwqfckn7ya.b32.i2p:0 +ayn7r3jdijhcl6t6gexmq45dw2tap2l67rn7xgoisaenkel74wha.b32.i2p:0 +azftalqowzsrodgik4xc3hjfglff5gqxzc5midgvweyv4pruyk3a.b32.i2p:0 +b66s2rpt67dfmhwlsbhkipn6znkc27dfth5j35f3r2ps3ne65awq.b32.i2p:0 +basycxslwal7fte36essc4rp6soksye7elii6erptb2lfrnd2ysq.b32.i2p:0 +bblpml6yi6sfzopy2fr25lstes7f34lignkwue3aun5km6iubw4q.b32.i2p:0 +bfpeg5qpkber4dz5lttdbyto76nsgfno3keozwgm6tozazktaroq.b32.i2p:0 +bh54jdffg6zs3h5cyeqsj62zhi5thxpqnzv2vrhsldr4sbckshoa.b32.i2p:0 +binnt2wbflhyw2yctpudz27dhnxhg6mowmbuxx2tbh4bbpqbzzwa.b32.i2p:0 +bjjzj5jn6eb3ssrw73p52dc7ypr4vmvcf4yezmwojwmkirl72jyq.b32.i2p:0 +bmryplm5iyirjvpgqk7ifhmhbpgjw3qifnlprqmvihtimn2iovhq.b32.i2p:0 +bo6qcl6cofs3cr6ilbxeuskrofdj2ksbhugtocrebapfr3lbqs3a.b32.i2p:0 +brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0 +bsn5rlu4h3a4xpklhhymxorogxpdgudstloclzshghb4deiui3rq.b32.i2p:0 +btdvfwxmrgnqkhh3rpscp7szj6yybm6w7whxa676rsxia4mta7ta.b32.i2p:0 +bujcpgdp7c35xxqdmly4dyxywaovxfoif7c52j32rvcs33gefeyq.b32.i2p:0 +bwg6m4agxu2fiv3dk5ys424b27wjzbh24d3ewtsb4ed5albmk5pa.b32.i2p:0 +byoucerid5rb2dducaqwepaytvkw4b4l2wmbfkbfgicflfcd4dta.b32.i2p:0 +c3wke4uh6wbgpwzo2zs3l3rfsr2ibsfxernlhxgyrxseuglrd5za.b32.i2p:0 +c3zbgt32o4foia7wdxgc3o42mutmeghhe36glmmnyzs256g77lxq.b32.i2p:0 +c5fk6xjwbfdurepihkdjvligexlzwu64zh2e5sjd5pmhvv34kmaq.b32.i2p:0 +c6c6c6deskut33e6zmoyxwhta6aadtjattbis4pqew2ghnv4gpga.b32.i2p:0 +c6sdbzckovbl7hd5bq5pfkkwc2xtdkx7b357bk3v4vdspzmy34cq.b32.i2p:0 +carg765pk5ef25vhvpu7phus75yp2xmwf4juphulsksqrho5krsa.b32.i2p:0 +cbnfpra6rok5v6z4crifqutx7iwwnwwblczz5tfmq4lkkdj6s5ga.b32.i2p:0 +cdwp7pxcqisoet4klai4ttemesjovum7zqcp2lbcynweol3kqfna.b32.i2p:0 +ciwvimts7zzoyrknhlowmzh35mzx4cluq7uycw3ffcckuov4tjjq.b32.i2p:0 +cmfgxulstg5trnmmssjvdrq5e7taqfta6jpuiqzakqujddhljs4a.b32.i2p:0 +cqdfflsgncsl3ypnwdc6ddwdoev7zcdjseddplzp2ytxhm5wkfia.b32.i2p:0 +csielmejcwnoj6djt7oo5o4amrp6pxpzvfgphbfysf7lwd73ig4a.b32.i2p:0 +cxfxj42wboxtkwkjuakree45xcfdmthek4i7qxruz6jpyff6souq.b32.i2p:0 +cy4wamhhjqg7amanxeifn3jmes2jnuactvjtxovbqqj6x6zveqba.b32.i2p:0 +czarxkemfnh5npq3jvgeaaygz2p3dnmntgu3njz64eo5fzuv2rba.b32.i2p:0 +czr6xr2b6mxgkym6fjabegjzgcixq4ajcgexxw2mhsuu3uvhhxga.b32.i2p:0 +d4ep754ddqs4xxdhkgxzss4a7mbfa23eavmmnghgjsefnzckt6yq.b32.i2p:0 +d6dnfifawlzft2qgv2pgb2h7dekx7r4fjp6vog32hqpriy66pwka.b32.i2p:0 +day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0 +ddq7hqixl72qxppylrwnmi57zlguqrcwjurf6myvwqmtb3l2f4ja.b32.i2p:0 +ddtuamdoynsa4r543psethu4ygfuwvcc7ftlb24ak2n35gnmekha.b32.i2p:0 +dmed6el2h56j5kno7xocalj6k7ehosyr2fbwcrk5yf62c3edcodq.b32.i2p:0 +dod6rjcelojfcjyyasqscgae5wvriru2fwdog63pxvkxmuneswoq.b32.i2p:0 +doz2ddulyddrium7kvkbfmsj65b7d2tunrj6kyzhzgsbka6ylsnq.b32.i2p:0 +dsi67lqt3t6uhkqyptlnaib3ja3y2o32umwcbluls2aiozf2qf2q.b32.i2p:0 +duivxnrpflxpwa2nd5uijndlfupqdpu6g7c4wnmxfl2uncevsocq.b32.i2p:0 +dw7oovp44knhrikivfmt3hs2lz2trlpb7xout6dlinfnzxeac3sa.b32.i2p:0 +dy2ch6am32vyobauxiv4vfdrijzzh2a3vaumaaip25m3gosmxoma.b32.i2p:0 +dzfqla37in4xpg3pa4auekc4vpjt6pa74zfd3rhiew2jurffk6aq.b32.i2p:0 +dzkszdiwq3vretzqitqabbxrdv35itzr3dlcfjskw54eya6cwcta.b32.i2p:0 +e2rqlug3nweslh2f4egq5jtbgfpfxvjwjxtxunka2ijszeuyq3ea.b32.i2p:0 +e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0 +e6qoyaetj3zf5jmavn44avsjdynx6oc6lxdgxfsq2bq3zue4nyeq.b32.i2p:0 +eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0 +ecxzxtzwyfwvm5yyaibc5w3ui66fri5a6m7tdsoqhupzqqpsmxnq.b32.i2p:0 +edo6wfaor7oa6rmyayeisqd7kfnbyzllbysvzijhmskgxxdjw7ta.b32.i2p:0 +efj265k4vn5t3vq3vup7zkkoa7dlqbwlhhy7pvxjrqlin3n2hwoq.b32.i2p:0 +eg4j6ftn4bkovxxlazghurrgntw2pmzwvegfnbl3cocdausdawia.b32.i2p:0 +ehgib44c4gpp4oonk2tbrgsns64gx2ituv3426ztv6unryxwlhda.b32.i2p:0 +ejq34wotitjk7o5xmxdlx6zakrxchwwtk4vggpfpxx2abyacrh2q.b32.i2p:0 +ekiqvbeqqbnl6iyf5nfk4kjwcmq23whgmpkp4kawahygzz35jfwa.b32.i2p:0 +eomxrmmgfcqcr7zt6zltzu3l2pgev7sdmfjmsp2mp5cwt3y2wfxa.b32.i2p:0 +erbey2sswwn64gurd76youjvn2eamgff5hasriomgq67ocdm67hq.b32.i2p:0 +ety7tckj2ecrjizdcgjfczkc6wmabd7lwlwkc2loel5j3yzqaqaq.b32.i2p:0 +eubmbzk6rtpu3utz4crdwvm2jy564cywwwrw6dz7l2kfzvaiyuha.b32.i2p:0 +euzazzt6gnefk4y4bx44wcfgmublb64s443iih5t2bypioljw6tq.b32.i2p:0 +eyf6do7m3decbzpcr56brke5xmkxwpaa6ohexqx7atq67ceswvra.b32.i2p:0 +ezypdnfzphgy34e5kum2vxc4jk4ufc3vyl7xpnrshbigktfahuga.b32.i2p:0 +fbiz5d5suop3oecitb5gxytiggogivc56cztyb24xxjybb5gxgea.b32.i2p:0 +fbueucoovpqcd7k4klzfeflkduquqbtmqsjewpxl33kogiamtsga.b32.i2p:0 +fegsqsam453itjjhbxdoubeczzf7imdunegspi25efiswcrqmcgq.b32.i2p:0 +filwk3wdvtdeea7hgill2jc6mtnktesmp5jgc6g6ttr4x5cfy3aq.b32.i2p:0 +fjokxa2rjo5e7prepab3sezr7ii7jcuczu6hltgvddjbxp7njnha.b32.i2p:0 +fk26lfbo2hpfhmzkn3gm6kxjsd2wcszx6arbzv3z2f7c4hs4nkea.b32.i2p:0 +fkp4yg7glca6aicbec6p6n3ubb75cnyliruc5wluczsmit3manrq.b32.i2p:0 +fmuobwciypvans7dywogex6zmb7ld3k7g34rxknwvam6jicdthua.b32.i2p:0 +fnwnlkjfysevosm3skxf6lnc2a5ff3lywvustjkpib52f5gprteq.b32.i2p:0 +foc3ole3bfsxzz6sxufnwzhx72cijco6oefwggh6a7mx7kytbk3a.b32.i2p:0 +fqirohoqilnpkpgsrmbv36urfl4rmpbtabyrujihndaes44o7yzq.b32.i2p:0 +furug6s4djbinoeocgat6rybo7pvvkyfwzbxmgsndjxm2xl4rcea.b32.i2p:0 +futppfdivsek32sxzumcnok5pozmkxmybisd42mazwtdiovmtwla.b32.i2p:0 +fviyvz6qwaktg6vltzzad4osrxciipuvepu3v66gw7lo736cohca.b32.i2p:0 +fxoblyaiu6wgo4ltza3tjvsa3kdzyhbiiinlmrlbztsiwbfmilxq.b32.i2p:0 +g26gn3gslz3qhaasluxrz2ldpa5dhqvbcwunmxafpwb5ct4ghl2a.b32.i2p:0 +g5ayhhbanipee5wyehvfsf5cuqn2djl6xvrcmuv2r7us6mrcl7da.b32.i2p:0 +g5yzfhaelbngq3zqfpufdrpntpqr5urnoteaxmnzqkcsfuqs5svq.b32.i2p:0 +g6fd7bu2oae43dui7zzw34n47bnhbt3mjokfajf46zgf6ta7wbja.b32.i2p:0 +g6zvxkdudv6jandpsod7b5ys4k5omzcm2jv5ga33ze6vunhqufra.b32.i2p:0 +ga25oahtxga27pmece3snv2vlpcim4gitvzjl42mc3oxkhclxgja.b32.i2p:0 +gd5r6jobykemsb3beip7kaham3tyfr23w7lrkjvo3zagrgbrgnjq.b32.i2p:0 +gehtac45oaghz54ypyopim64mql7oad2bqclla74l6tfeolzmodq.b32.i2p:0 +gevhyfmgocdedifop2e6chs3xesb3dufjpwwsqyhjh7mf6qx22jq.b32.i2p:0 +gfartwr6pkbz4a356heez436fw5im4thimitetn6sdsq55prb74q.b32.i2p:0 +gffp4p6gsjptgrji5bm7bxybnaqctjosmdso2i3peqpuwwdjdezq.b32.i2p:0 +gfysvso2uoeulc7t4djkgpafxdko3kr5mvucidibgja2sc3aod5q.b32.i2p:0 +ghuf53y3dxdnxgjjxast56jcsjohoxffc45mbx5wvx23mt6q6nkq.b32.i2p:0 +ghvmoyhep4sayhgen7c2pcg575aiihrwlcngm7lxxqtbymbgmiha.b32.i2p:0 +ghvxfggh6bhu4qmqkepurafpvvqmab534zsbv4qrz5x6pt6wgfuq.b32.i2p:0 +gmdyky27756xd4dcky734kuqiojgwdbhavz6ou73dpkg2xhwjrsq.b32.i2p:0 +gmsk6rh4ya4qtsniu2uhehxavxarfmeojbe7sbj22opq6g2rsmha.b32.i2p:0 +gqerl5bp6brqik4pxagwldb6d2sy5enbxav7y2a4ttgeczlk6dzq.b32.i2p:0 +gracsh4efegi54gsmgqpvkqpmqxumrw2hnjuouvawg24hl7ffbea.b32.i2p:0 +gt3w2l4fdh5xq3vtcgz2qr64lx6wi2zqgrxju7dxrroejemn4x5q.b32.i2p:0 +gya5qjekil4fezub57z73pwccsshktot2bnr7wckhmbfwx5mzmja.b32.i2p:0 +gyde2opnhd3wvwalasugxmelkhd3f7tsesyuhppo7sbzz5wsaemq.b32.i2p:0 +h4x4ur4lr5rcspnenmzy6i5pa3e3pdtsyvnff5u5lh3vedv63qvq.b32.i2p:0 +h4yswxrmlmep4m3qu4fp6od2p7lioodmjp4zripxph7bfvmy34la.b32.i2p:0 +h5rbl7ltuivi6gx4iop4icjpvkp2rtm6tnweddkrqkbcwldhz35q.b32.i2p:0 +h63rqifntenj6titygonng376oval5vgp2gtz72uuzxfzjy7g24q.b32.i2p:0 +hcv5zizlrdemafcezwzchu7klydbrquutmdvr5vwaawdcpcwouyq.b32.i2p:0 +hgb3jvlzx2lqrgwshzkzqchw3kmwdlpam5y6j6wlwajqo3sbmdba.b32.i2p:0 +hhneoshcc76hb5pa5vq2pg7va4xe3ikbnacdzurbzbdsygbihiia.b32.i2p:0 +hj6kfjp6yusezysuvaxendfv2byw2erniku6lztfka736g5ia7qq.b32.i2p:0 +hlz7kz7pkh6tr7buzfgnysrwnhkhp7mu76hbmh2nn7b22l5vs5rq.b32.i2p:0 +hnmrabzioiwxj64ih237rxf2zbdttfndiepp7vikt2jko7ovvrkq.b32.i2p:0 +hnxxsx7stxzesijof4fgr4xxysunipnivnxc3lqj2lefs7k7dqfa.b32.i2p:0 +hpalvgj7fh3by7n2v6ha3qsv6hv7qf4jcovtegbqlttgto33fc7a.b32.i2p:0 +hvafnot34y5uycrdkkue3grpa5smiosvl3nhoeiqk6b6en325yoa.b32.i2p:0 +hxoaugx3mwnypgjkm33vidgp4vt6thpckrfaqfgifyn2bzkyjmfa.b32.i2p:0 +hxw6inru6crfmkui4xjjucwdj5pffej5ke67zynbg6hw3bgrehoq.b32.i2p:0 +hyrmdeqafuv63ydnihuwnuhaanblitletw57qu4ytgkgus5eszca.b32.i2p:0 +hyxogpxrpnrjysofu4gr5jdptftwjjlz6thqxefsafctct2hcxwq.b32.i2p:0 +i2k32sb3fmkhemu2gzm7h4m24ubcgqdohhgq44qya7zbkrgw6mua.b32.i2p:0 +i2x72j2oejknudedxsbaxl6amq6a7phifs63bfnvnuxxfd2de7xq.b32.i2p:0 +i2yx56vnsicamm5nzszd6atxgxy2ltjufva6jkfujer3a3pojcja.b32.i2p:0 +i4cebpfoieapy7uxny7rjvnz7jl7rqv53sflga54papl4qycl7ea.b32.i2p:0 +i7ygposcafodsmzuiotuup7qjgyklv3tuah2r7rzuwwk4mmjb4tq.b32.i2p:0 +if5nrcqnju2by5r6n2mxmggq6zw2qdsctj3edpqmjmvqk6ndtkaa.b32.i2p:0 +ihaiw7hs6obvpj4eho6yqagi4ecuf5ber6hlvouprif4zfxr72ga.b32.i2p:0 +ii7ra5loq7nw43kxjtr6tdhf6clvtnfqqatnaz2mtr6pf5hyelbq.b32.i2p:0 +ilsxmoyndew4ed2gglf5mbwoo4we5tt6qmp4kzvzyzvwev2isf7q.b32.i2p:0 +inwsvefcxszherj6bxn7ou7svsitty25637hz4ifyn7xzrbh74tq.b32.i2p:0 +iub2v6hygn4znn34nw2zuihupczrcpniq2bdilvslldlsucfrrqa.b32.i2p:0 +ixhgawpp5anrlwxxgfun4zl3m5xhlxassszncph4i4e6aymb5fqq.b32.i2p:0 +j225nrmndwviihpe7ib6mm5h723cg62wrb7vnwofopv472ue3zwa.b32.i2p:0 +j26gpaan5ablb56k4rtbeamv3ihd4vdzdv74dw4kkevxruapwarq.b32.i2p:0 +jh7ev4a5zfzmeyekinhtbqfi6c7xhvc4msdpyi67j3sxl6r44ukq.b32.i2p:0 +jhxhwfiqysrj5dipbtdokif25ahsj75atdqrbloy564me5lxeada.b32.i2p:0 +jkszx66voakpa72effkj2xxjn4qglsidwejmxomqychvnypgq7fa.b32.i2p:0 +jl4vr5kac7njyltivn7ut5afyq5ipzc5woxl4523emodxixci3zq.b32.i2p:0 +jlczqz5nill3vscbjx4jfm5ogxdk3fznvssytzjano2uhem4wvra.b32.i2p:0 +jndr5i4qhxs6aa2bqvufrgttq6enavyghi54dqfuku2qnstdqa5a.b32.i2p:0 +jprlg3owt37gubh33q2hlz2kx34vdxu464p5pqa4yhwafxnpupma.b32.i2p:0 +jrert3o2rhbkpquybwg7tq4bdvlxeh6lnlcr5ddexkuguvi2l2pq.b32.i2p:0 +jrgzkopi5pqtnb4weo7yti2igm7g2ene4aggzdcrrjxlg3nln7ra.b32.i2p:0 +jrvg22xvbmjyrkqg7mr622zhnda3ijtua65cqngwrven7sf5zd7q.b32.i2p:0 +jsg4dsxvgjcqz3c2qgtwi4ip3l4n4hlxodbvgukwaipycwo26zua.b32.i2p:0 +jsjuwfzebgcyehvh5m33iv6d6cdpokeakfh3vnsqvpubicc73qna.b32.i2p:0 +jvaoh33cpczp626ldwr4azh4hb5cjmxlbz3dq3cxisdlzn7z25eq.b32.i2p:0 +jwqlvqmfvodnrslde2idqt25qxiyvgqdlr2q4uod5s6lkmlempya.b32.i2p:0 +jxqyize2ct6mm3jvvzavm2zbccsoe5qd4ekqo7zgt75rzz3mni3q.b32.i2p:0 +k5oyn7higpqwarsh3ukdgmx3z6tvqcwju4xawrge6aaswrdnoo3a.b32.i2p:0 +k5vjrlzt33dhk3wossfn5depmvy5txbivpvz3wr52maaijgxhztq.b32.i2p:0 +kbawcieyelwwitrjow537zpmdkncwiq42rhjgayw5o7u562mk23a.b32.i2p:0 +khxruoaom7juockko2tbxqo3bnrjmoqjhdoady3yyr4qacz4somq.b32.i2p:0 +klsaj4g2jh7w7gxwctniktg3hqwspm7zlkwtsaxw4nu35jssjasq.b32.i2p:0 +km3b5j6cqrcqewdpuveibptw5gguwktwan36jlow4xykpg2dgr6a.b32.i2p:0 +koh74kvbfguiam33fsefdlks5htuckvb3hy36vhbmvwhrqlxpbma.b32.i2p:0 +kteedl3k6kw7kgn5gbrqbdlxvmqbgiataunqrqtni6uw7uykof6q.b32.i2p:0 +kw3v6gq5semgt4gg6itum3qtaylanyof7wn6bnbngdeby4xixuoa.b32.i2p:0 +l6o5pefljcg2ffdrbvatzc37a2dkxrnd25z7vxkim2t3zmszwshq.b32.i2p:0 +lc54ao2ovn6awezl6ogpxd3xakew46otdu7uly5agtbdmifkgp4q.b32.i2p:0 +liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0 +lknjmixwvxzla3cgvb5qmpbehqpfflujcapn5mhkku63xaagxgsa.b32.i2p:0 +llavu6nhg2opvap2l35ufi277z7ew2wntepvornuav4t6fmpmfza.b32.i2p:0 +lmxiapsgob5aqje6ofu4npxoc5gnjtbfdgys5ceb4hbscortlzyq.b32.i2p:0 +lpektonr2uyiohuzi35shtj3oaa77rklmqsivuydxkcxkea2dwuq.b32.i2p:0 +lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0 +lrfcts7yrwq4qtrabl3ai5ljxnhgbza4ojb2oknzoobdvdnzhp6q.b32.i2p:0 +lvdbqavgdom5h5denwkmdwslfzxckf6eddwflelbog7tgo2m7usa.b32.i2p:0 +lwjrapkfexjyjqf2rrdr4ghhxmlr3jdygsonetgtheglvmru5x6q.b32.i2p:0 +lxh4dszgwvjzfjpy32eridbn2yxzmcbcfs6xham7272rd3dmitya.b32.i2p:0 +lyg26sjkcx5ied5a4a7jdxmfeplfcnux3fux5rsxzkm5mgbbsllq.b32.i2p:0 +lzanccluo7lzsg5zzlyomj44eabqvopb27vlbsargetjbib7shdq.b32.i2p:0 +lzrg3vee3wbz7qa2d4mvaijzebynhx3567rpjhdvebeevfhfrp6a.b32.i2p:0 +mbyf5d3vhlykjmqpkdiw42spbb7u4c7vu7juvs3yfbwaqtjnqn5q.b32.i2p:0 +mbz4wyfeqtllccary2crak2qfovnaq2366vdddro76ihxcaavfpq.b32.i2p:0 +mcvkdet26xzsz47hluq5zgaymyjvz2z6nisc5etmnpkoudzkyliq.b32.i2p:0 +mqvyz64lyw5okdpsfjfffabu5u2leob6usqmfd5at5eaa7r37dfq.b32.i2p:0 +mwevh5r5dkzddlo2ol6bojpdds3kno4xqoy6p6ulid3paamgrtla.b32.i2p:0 +mwyjzdrgtypbwjyulw4ifetejz6xusqstvzylztsphpg2r2zf7ua.b32.i2p:0 +mxglgq5ic4r2migtume54owf2pkolj4rwrgklv5qsd5amb5vmiza.b32.i2p:0 +n3p5dki4vkjmvq7mgp5behafe5crvl6q5pekcfchrwyts7d6dbbq.b32.i2p:0 +n3xexp2kjvcqrd5xsmgodps2ihvvskcqiupl2dozdzbrzea6jnqq.b32.i2p:0 +n5hids757nhhjm4efinnfvgb5kmgxwvt6adgbh645g5fjbphch7q.b32.i2p:0 +n7jorimlqrjfsdbsvwozme6eicpui353co3oqb2iupfew6wljnjq.b32.i2p:0 +naox7zpagk3z2zcrcnrvnjsuqbgmhstb3z5gznpndw3hlb4x5zaa.b32.i2p:0 +nc2dn6nife7jemcbkcl3igpywuuzi55stqev3svcnnuj2atjowlq.b32.i2p:0 +ndd3remf3idc47ueuyph33ce2dgqwpirxaqomvg22vn7dffw2l6a.b32.i2p:0 +ndtoi53fz7e6ml6v6jn33675nwciw7mu5msn7afzbhebprusqg7a.b32.i2p:0 +nipevh5opcg7stsmf64dvtk5bn45orckoa2r36gcntf5i3hs3jdq.b32.i2p:0 +nkj2zabj5b4vhold33nz3kgp2x3i3es2l3iz64rxx7em7rkgubaq.b32.i2p:0 +nluwsgpbk3cplcb2fpnfpjrhot2w7a6mtjggkqikudspysqlsceq.b32.i2p:0 +nm2dusg3py77m23cr3nt2j4q7ukwzvqgv6h635pw4slgwwptekfa.b32.i2p:0 +npofpbbruz2qa4bvchlal363r3uii6gjmgfpc5rregb2oi5lcakq.b32.i2p:0 +ntpnfr2cmxzlmsznvgfv32rw2pdvbz7mxut3bgphe4o24dqlvd4a.b32.i2p:0 +nuwphtuudfrswids22qjq63zgxh5wu7erafl36jyniuxhz75ikyq.b32.i2p:0 +nwfdwlblhudom3oqe32yzzuuj2sb37tjvlmimiru4coazi5freeq.b32.i2p:0 +nxhs7kh72gtex73hhu5a7tgjul5zm6q7dxejqflvdq6boq6a4miq.b32.i2p:0 +nz4lq7pmswngaevv2uqyainqzutfxlkavxgde2w2slo2p6e2kcfq.b32.i2p:0 +o2rckrq7jejk6zfxqu3zed5vyjpqagk6ogqspq767evacer2twaq.b32.i2p:0 +o4tkad7wdeyarefuew2d3ytpwc45twkca5vobgidhuv6h74r3sfq.b32.i2p:0 +o5s5j3ghhi7jipsd4j5jcb7qjbsatkwxcvotgjjygtcj3liajoya.b32.i2p:0 +oanp5s4ols5idrplaomlkjo6x6eaaji2xbu5knlouxahmwizqipq.b32.i2p:0 +oayctm7vxtagndwapn5sojqw23odgnzn3c47zlwc5xalcrnffykq.b32.i2p:0 +od6xadvvlqedl7vje5auuop4pnwf26pfj46mxxucvt34rl5x5o4a.b32.i2p:0 +odm4oxozmmg5vfhz7c7vlppikb2s7t6rnhk5ibz5vgje7m3igc5a.b32.i2p:0 +oggn6qbpmbag224gumagzgno53mgozb65tpzt5lezjbfbbiqky4q.b32.i2p:0 +ohparrugvj2lqhjd52f3bdm3wa4mme25ozjqjqgcgjnu4sswyjaa.b32.i2p:0 +oikfcbxug34vtfnkflh6ogncxpvzs5jzfhaai24xuvzynfsi3slq.b32.i2p:0 +oiusghp3k343ofsyw2ym6iejviznukx5lrhafxzdasmjky24ixba.b32.i2p:0 +okfxeoh6itu4f5f43dhbzvkqwfrvm5c66lj6lvjj4q2b35i4pk4q.b32.i2p:0 +omkilp7edzk7fpmml2fylar64pc5okaxuizv7tfqk2qmsfdokp4a.b32.i2p:0 +orzhfle7yenbiesrtg37lklyukcjyjcvfdrpk3pnrrshtl6sdcrq.b32.i2p:0 +ovkjylbsfe2756cpphzx2zvhhmtbetr5ci6swmydqc5itajqxm7a.b32.i2p:0 +owexluejb3eszx4p3b6zuxyggsxxtkxfgxoylkagfecs3bgfnpja.b32.i2p:0 +p3qxhtoxajkmt7tgc6stv55msievc5323rtrsiwstvtf37iwi4dq.b32.i2p:0 +p4tsqwvdpaitvlgaujfr2m2qbr36qiwusas5zkiut7w2wjcp3sqa.b32.i2p:0 +p6l4k3yl6hmsep4shr47nexwzd5m4t7ddz6yepl2sqmkicxvfbba.b32.i2p:0 +perwhflptmjkumfb2q3mtxqkzhkyqp723lbl4ct2zivhymupktuq.b32.i2p:0 +pleconnukdt4fp7cjcjh7af2a3nzsnkfqjgx2s7jb5xyhq3b5xaa.b32.i2p:0 +pomodyf3nnav7yeu2usrshzq7dvdqawrhoau3uxlimivhy46lmaq.b32.i2p:0 +pouelx3dkoqn5dvlb2veazhiiknwvtvadbbzkprk3nmvl4vqpcma.b32.i2p:0 +ppez53yrs6lanyvyxuxblqxiuvhnqvvtafmwaid2kgp2dx2v5iaq.b32.i2p:0 +pqnqwxl7jsrok7vgpgcvlxwlkg6yckx33n3g4xf5lvuntwn63b6a.b32.i2p:0 +pqpjrjnvbrlzzznv3rn24pkfemv62suddrtf5kzxxl3abek5xf3q.b32.i2p:0 +pt3ikblq2ytoqecetxdui3excysnrbzj2rwr4qbxqtlcklskjo5a.b32.i2p:0 +puhesrcq5ojcvpendpjv5hi7kfxvy64hlpgcokfwiq3cekomhr6a.b32.i2p:0 +pv6g7uin653rerdiivdgtoirjvokjowi4b3fwatszdlteyos3i2a.b32.i2p:0 +pvqyvn2lpvoeyhgcgunoqtetkrkp76iegyoii2af4crnlto6gb2q.b32.i2p:0 +pxn6af3w4p6auglktieukus6uzz2pbp2eya4ouvr7lzlxh2grz4q.b32.i2p:0 +q52c3eye3gvaepqhu45nt4ihgqfuzsr5hh5m5ngqtrhqmwjejjnq.b32.i2p:0 +q7mnmpgl54cbaorenckaybhwnh5ovyakcvthmjdsmvquip5ef4na.b32.i2p:0 +qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0 +qfbughfr5hhgoomasyviwk3zin24uerpl6urz5smzxc2div5ixxa.b32.i2p:0 +qksthizqtfdjjxcrahqxkl3bev75k24blagrkoszxen45zelijpa.b32.i2p:0 +qm6vfq4pfvjg3r4g22xkg47xc4d2y5c7qlsoqyhfppsvh3grjfka.b32.i2p:0 +qmqsbya7yhpdkgxyqtzcmxajihednp6smhngx7s2n4gx5murt6wa.b32.i2p:0 +qnqojlthym7z4gwizcblhpd2thy7v4a6ifme57bzyl3nxzkj6ica.b32.i2p:0 +qpa5np77mrgjmmhh72bqjnhlxq5jj3annthoqwc72sz7u4j4zkgq.b32.i2p:0 +qqmxvujwi4ktgj2cuqmw4kiujkf7ukrkoe5ryy4bjb7tyleplsja.b32.i2p:0 +qqrvyctuomsxqiqkwtzpfxtdopzrdqmaxnwnhnuzzl2lrdcw7gpa.b32.i2p:0 +qwbmjxgnwnitin27gawtu5weiybo5nnlgs4trrh5vi5225fezmiq.b32.i2p:0 +qwhvlprhk3ntswr5xntnc2hhgmvd3bbgzgkbombiibhrsj7k6gyq.b32.i2p:0 +qwtpmh6ssnkeowocnvl7uveuhfodht3hsgwwydhy3v4xmwqbwveq.b32.i2p:0 +qxwd3nu4kicwuyhoje4dagdhbif4bxem4sk5etvvigycbe52ofia.b32.i2p:0 +r6hd3knqi2p6kaw7hybrcf2q5lcarulcczs3sgcuz4yc2saj3gya.b32.i2p:0 +r7bug6wbhevqqlbavouj3ggpa7e57sbd3oivkzqeyagrtxshmjpa.b32.i2p:0 +ra7ztq7oq7jcozpui7c4zv76gh7rjwhq5fkpxp7dvw7ritick66q.b32.i2p:0 +rb7tyjd6gi7evmt5mzvtboramqip43sh72zjxnwhj5k72zfi3g6a.b32.i2p:0 +rbciwwoimo3v55a7n4xb2yhyxeruvzyt2cdfeng3h3aragq4iziq.b32.i2p:0 +refo4v727jmff6ylrpbkvd5emlfr2hamaeh7zho6oval5dmnwlta.b32.i2p:0 +rfgsjhyvqbunef5b5r2emjuoxx2i7rcsl7gathy2n4gwjyyat6bq.b32.i2p:0 +riqrkj7zhuwqbpdluelijgyuvyubeqez2ndnvi6zezmvcwqmyxsq.b32.i2p:0 +rj37gjtx2umqccclxwmtfdgdxkfswp4pgrngrvhqq4fhhjqeud7a.b32.i2p:0 +rls6o23iz5wdado2nxsdxwxskf6mctsf623ki6ukuprdf2lfcbva.b32.i2p:0 +rm6vjhtun5zji3fegbvu2zmdlo67tuvda2dbveqi2vmqqxdrbsla.b32.i2p:0 +rqmwy4cazwtmkvluwxzz7k2ly5jwcoibar6vfxpr52aamlrm5wea.b32.i2p:0 +rrm2pems425buhonptp7lbtbprmwwjhbftey4ujvk25nclx7rerq.b32.i2p:0 +rs4exny4th3a7ngigrgpllsgoesxoxzqqk5upzzu24gdfv6rjacq.b32.i2p:0 +rtwm6njef5tifwv5ols3b4nsboniig5kdw32ik5qbv3wmhoo3pba.b32.i2p:0 +s2j2rv2dcizg3ibmrwzcvqe5cgtadezawown76l6sfqdtkfnzzja.b32.i2p:0 +sbalp2doxyedtr52kj57va2rmbi5npspv4drk4vxnujag72gtpiq.b32.i2p:0 +scfyzzdnycppb2vs4iae7wwjrbtywtuf4iyydaiolkvzy2d6b3ta.b32.i2p:0 +segnvtkjqqhzo52njxma3jgerwblnpvqrojjyeuqgzav7dwjlzoa.b32.i2p:0 +senbs2vd3mjgsf2nvpjcne63pzcfolnk2vtf2jxa7pxecuepfjjq.b32.i2p:0 +sgkdf2nk62slx6gtrnrxeoiknpdhfjjznqrcetdnu2j5iiltx6ca.b32.i2p:0 +sh5hww42vwlsl57cdropaeqmmwozinnr2tg6wq4prg5wrkusvxja.b32.i2p:0 +shh2ewyegnuwnmdse5kl5toybdvzkvk2yj4zcowz6iwhhh3ykdfa.b32.i2p:0 +sirb7csejtk7xwr6qymggudtft6cwd5d4iroj4vlajhiipt2hiaq.b32.i2p:0 +sjs76j7kaulnplp6wjs5nokshdowgfb7c6npmmtnnqimgzxxrh2q.b32.i2p:0 +sle3cbbdom6rknc3drqtawctpy635ica5d5gerjjdahfymkok4ma.b32.i2p:0 +solinsdewyzdgqbe4xso6wk5i6su4gcwas6zxd4q3om4ljvjv42a.b32.i2p:0 +spncsew2zgynatyvvl5mb4tuysd73oxmaztbiwjnocleyxuexyuq.b32.i2p:0 +stltasmf4b54srrjb3mf7hjtjvmvvms26btxakccdtllgrm2qzgq.b32.i2p:0 +su7d4biurihkyr3qeea7makkxzikxr5zi4znvryh3bjespppfhxq.b32.i2p:0 +sya6ydi4i6dslzjxmllugs5gyosg7rpwwfgalrzhd247k42xrcbq.b32.i2p:0 +syhxehvl6rublw6k5ysmzcsqrzdsnd7eqrbwalfkvhgfccpu2osq.b32.i2p:0 +sykjw3jnb7n6bo574wnpiaxhp2nm4gc6hc4jh4v6trsbpboysooa.b32.i2p:0 +szqvwf4yxnqvpprv6uzxkn7voxab2i5wega7kn56oru2i6wpzutq.b32.i2p:0 +t4notlid4bejwz2tzucpvednkeuskenpnu5sqcbdhh3lqouigqxa.b32.i2p:0 +t66iyinlubtg4znht2a6gwwcyiftjosuq7xbur4gfekkhwymxoda.b32.i2p:0 +td6ecor7qphgru56xt2ydih6k6taj3tvp77zhimoj42t3lo5u7na.b32.i2p:0 +temfakn3i7wa2dekclbg47smybf52o3kyw4cnywcmrhrq3dajnwa.b32.i2p:0 +tetoqjagsf7fpejajiwm4rosqscy5huqbz5hcqgfuha5tdfnlrnq.b32.i2p:0 +tf4tozh5unsgyzpdsmrdcpbgekw2agu7tp5jvyclzcs5kjudwwpa.b32.i2p:0 +tjfdp6mel3wzdpxkhbyhrmfrha7gekv3gghalnxezrmvnhy2ncra.b32.i2p:0 +tmc54rhj6yxnezeg6rovgtkyd7kwleinb7cj4ytdatwhdel4vswq.b32.i2p:0 +tpys7fw73bmglnjtitxebprgxthg6ew4gnhp54uc23cneef7si2q.b32.i2p:0 +trucvlawpufrszky4zzhhxtddnhio4mnqawzc47n7kik6i444m2q.b32.i2p:0 +tumvq4vpa25z5z4phsl2odrgswtf3lhayrftqsdhvejzzp7y2zla.b32.i2p:0 +tv3x4kddbu753tnlghgh3txogp26tlydt47rl5scx7eoxgnocf4a.b32.i2p:0 +twwjmbvrcfkl7s3hh473jwmxdys2zxo2ozlfivsjvbh2kobl3vsq.b32.i2p:0 +tx75t5cfpc5usmipedmn5w7sxnmeofolxyk3srcsd4yupkkgsu5q.b32.i2p:0 +txmrkbijumgxdhr35gbyqscfb4a3y7lbrl2da2nyqrdtilqpe56a.b32.i2p:0 +u4enqhila7pkwbwuyfbfd36qllbyv7y3p4nelxekrf3fizp4htza.b32.i2p:0 +u635477uxqs7z4uvwx224u6ojn3c3ewcb66f3j7qlbzqyrrevxja.b32.i2p:0 +ua4fdaez7efn74yivvlyg2qooscqskviuovygiujgh3jyn6pfama.b32.i2p:0 +ucgc3ocprcieyjj3kjlysa5y2yzfekvtpmeg46t4htvviaet5evq.b32.i2p:0 +uczz22yiczuydnoqddryai65547al4kc23ev7u6cmgjdnwxqwcna.b32.i2p:0 +ue4j4hkw6dy4bqx5l4gws5kdseqto2y6yxbadh32yipwcywsf4pa.b32.i2p:0 +uegl5ai5v2ddzfeq6eda7k3ul254ecbyjj5lqlct7nsrljjxksha.b32.i2p:0 +uf62jvb56gmhzfvy4q3rrripw3ga2gpeutp6zyplferc4uu7j2ia.b32.i2p:0 +uhkfrosqc2uqczwcktbb7ups5b5t2up7yhmicryrzqknkj334rnq.b32.i2p:0 +ujbl6syp4h7whbgmqfbshln7xvmsiorjq5xj25wvl6wpcymbwwaq.b32.i2p:0 +ujg6b4cyxhi5pf4puwvwupur3iddm23uibapigpwl4bstvlt4cva.b32.i2p:0 +ulwhvqmfei6zvxnusl5yqyjxgb6cxoxofa2egp5ecvrp5hxpmqrq.b32.i2p:0 +umlbkwpm35dpp66ggxt23tdzsqh3t2ancdyrga5nxidn2lnkdgxq.b32.i2p:0 +undzufsjeb4qlf7y5llh56tji6zlhtshlsyht4yjdsa2k4ayx7vq.b32.i2p:0 +upcwcphup3eoiq4oqcing5rplkcl64legnv63rxxr2v26at6i3hq.b32.i2p:0 +uqfpr4d4vcbs7nd5l5o4s3mzl3dptascgesfirfuuhvuadzdn26a.b32.i2p:0 +uv44mjoqrj3m3gzz5wxlnszt5pvgk3iqlc3pmqfe6un6gxays2cq.b32.i2p:0 +uyboj62kmr2qe3pma7lej42wgcxk2i6jztimkw4deb7yf55om7ba.b32.i2p:0 +v7pncuqxlofwmhxi2rebbxvjr3cqddzewbzxgsmsz57i5rsj4zea.b32.i2p:0 +vavpoevto45dv5spd4csk3ut3afe5cldtzvoceuiix4ingmfhxla.b32.i2p:0 +vcksnyuyw3i6hfviob5yzoynq7okxi677bw7224273fjhsk2kgra.b32.i2p:0 +vkz72iimesw6klnurujjyoyaphgxfj74wg7hjuiyr3jhqu7fo3rq.b32.i2p:0 +vlpktuqjkol5yvvjjtamlb5k5t2ywrssy2nivancn3er4ymnyxiq.b32.i2p:0 +vo22o2zy6gb4nsmcteelpyoa4khh3hogoe3jsgis6yglyrtxzloq.b32.i2p:0 +vq5vh45dihzuxkgvu5le6mauvdlmk3pjzfobncvaelumwf56d4wq.b32.i2p:0 +vqt22x4nnflmbgitjhenfagzhkmqekbjoim6vxjmayco4ewdnxsq.b32.i2p:0 +vran2pe26rju2bol6dllrhmgrud6eutmh6i2dotlv4gnk3yuk2yq.b32.i2p:0 +vuqk76jvxfk55bkovqcmmkvycmndee7j3tuv7ezdb2slrfpjyvoa.b32.i2p:0 +vurewltyyuo7s6xznj7udjtoqlcm65k7zbf2jdjublcmiueobauq.b32.i2p:0 +vzvt4ddkoz7scjmjzu4dvankrkxx3bstfsjuice6466bleuegjsq.b32.i2p:0 +w25qtnu5zo5s4eczoiidyxjyx2gw62nitaek3uotaawarvdj35da.b32.i2p:0 +w2mgaza75amrvfocl7wt6v7eimprlasuj3bi4xezdr2wyqhkxzwq.b32.i2p:0 +w2uruwbfqmuroj4s2konb7jctqd7mt47yqwsggy65he7fvfrsgwa.b32.i2p:0 +w3hyqnlueb4yv5lkzj3wlnrjp7fzpxnig6x6m3w5du2ptfjcm2jq.b32.i2p:0 +w3r5hrvyb2ppiwulw5s2r5wwiv6x5xvirpftdugvtvartkeifsbq.b32.i2p:0 +w4zymjmq7fxpecyc6b3pscasjbi3kj4ggfucb7gh4woeycnjsxma.b32.i2p:0 +wacfewi6ehmfxvftxqmracfh7se2t7ozl62u4hsuyd4c5xfzuajq.b32.i2p:0 +weck2efmesdewefhddub35opskzw55thubvqcjfabnmuahzuls6a.b32.i2p:0 +wfrvnaeqad6zevflyme66n3p77b4axymni33fu42bhsaei6cmrpa.b32.i2p:0 +wl36w4dicaovalv6w4vijn3jwws6wur35vnlhid5r76hal2ou5yq.b32.i2p:0 +woc63cuawux33zg2co5fidtw3alfqfc3mov3bjk65ip4ge4dz4eq.b32.i2p:0 +wpau3xgpkr72r2ysbanhet77xhtawm5mrm6a6mvjnv4oq4kypxva.b32.i2p:0 +wsbf5tpo7ecsafusflyym72k6tbyclgvqav56qafvyc4j3spzdoq.b32.i2p:0 +wtfebbwmsxoywu6nw5cowlxqhtokxrxftve2zee6flvrpqg4j6ma.b32.i2p:0 +wuikfwkext6lbl6urhoysr2abcyff5lkm2ojr6mfenqq25nzlluq.b32.i2p:0 +wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0 +wwwrx7f3urm4g2b5v3rtcxcijdefjireyqycl6dcoyap6vav2sqa.b32.i2p:0 +wy2udklgydh7iknnffbzvldoiwsct6dy3o7fjcsjcdjoq4b65vha.b32.i2p:0 +wylodalll6bd3l3vjfazlvmtsymgn5bokdwydmbzp5ncww35jpsa.b32.i2p:0 +x3mabmgx32hljbx46xqjobh6l3tvrridnxgrla4q7s2bgkk63aqa.b32.i2p:0 +xasewpiqpzhyggxwsajmnkrppi2ozmapqv6673zuuymoueq67tla.b32.i2p:0 +xbnl2smr777bqkflwbzstuwmlvu7evlxl4me3ynphcs3e72rlg5a.b32.i2p:0 +xf4xjhiry3x57gs73xhcfswulggzazfouszkbg5uo7oakc7cu3oq.b32.i2p:0 +xfyzfugo3qtfpq3s5zccbbqrxfkgy3ttlqhz6t6ovmtgrsuyce7q.b32.i2p:0 +xhzoxaskarhu5xsa6sat7kbxpce6tlvc2wfq6imdmfqgwbbyqypq.b32.i2p:0 +xjtrrpbdo5dvqjzsr7dhoyjocrrljfkutoyrmcyajfzbpozlytsa.b32.i2p:0 +xnb3pxtmai6ofbarycclwwueaarn4r3zt3zgkeepo4pgmswqvfcq.b32.i2p:0 +xnivz7w6yhjhvrvytupf4d7edydnfvzmfpqv6ndhxfcpkcz46yca.b32.i2p:0 +xofaehrg3ptjydgglyzkw36cxi6cgogkdt7yc4lmbng6vpnoegxq.b32.i2p:0 +xtxh4wtmbjls76wxnehe57etubuqvsdiunwgve6kwjt4acwswnjq.b32.i2p:0 +xuivvnpcj2rhsxmkyyjzmyq6a7gwgusnqwdklgimamvkzu7rnnmq.b32.i2p:0 +xvdqgttjov3jzgmke3owof4y63jwitxtbxflspxp7gqf4t2vobvq.b32.i2p:0 +xvpzaqftlfx2etqys733mndm7jr3l2j3if3wskfljzaow5s4rrfq.b32.i2p:0 +xzkwbpxki3prsrmylrjzyg5z3akjtvw4iu5zhevmz5aedgb2nn5q.b32.i2p:0 +y3occl5rqc2mz64esu5mqzoyfzlbxop7tttf2b3gyxjust57txfq.b32.i2p:0 +y45xhqkb43ncokfwhsmr4z6fwykuit6o3p2kbso3emv7stpiwwoq.b32.i2p:0 +y7cahac3wyh6kxubwikyrobe46bm5hhe4ovxn4ex6zf2ojkkawrq.b32.i2p:0 +y7flfkirmnbzzvwjyf4l5pgeqzjgxr3h2ds63lc7klx4byineowq.b32.i2p:0 +ybdhpsgmtw4eewreo7kswclgexdztzk32a5x4pbr5ws6nm42gpoq.b32.i2p:0 +ycntiiypllboyp3ikl6njjy47gxkfycvwcvmbyikshnjx3l2bvva.b32.i2p:0 +yemrkyqmjzwwn2yast2ga6dcnsovnxwip2rjpid56grdg7itugpa.b32.i2p:0 +yf2ny2doz2qirgwlzc6gebk6eifqvzeozcesreme7u76umfmva4a.b32.i2p:0 +yj3v3ocgldnackxptsjmwasa4xzxj3it6rtuhmlpxvwlq5kmyytq.b32.i2p:0 +ykv62rivlxurq2wkecagzs76tulfor765c237bsjn7jt4436kn2q.b32.i2p:0 +yl2y3q4k63d4a7tvqjmbtq2uyzmrjqgnhl5xatcamjen6faaxroq.b32.i2p:0 +yllvqk2utimxjtoyzk7l24s4n5sqp5dbn5vwsbt3g3dd6h4dxseq.b32.i2p:0 +ylxiqtda5q3ioliyff4cswzly4bvbaaabpic6chrclwjkt33tdaq.b32.i2p:0 +yodn52qhw4v5aoaoqfsunvfecbbl6cyk5j4aq2pfm4otu63qlp6a.b32.i2p:0 +yophu2fzfwls6dmpnhy3hzpfefz3sunu63bt5oi3zx6wyfheaouq.b32.i2p:0 +yosnjs5hintkbjrwyrvbs6myc2zd7gpfsrg7t7bprntwyilqnfnq.b32.i2p:0 +ypdrun7wxb3ah5rp7cycnizg6hnkduioqac7p75lklstuczoijjq.b32.i2p:0 +yphmy6w3myyy3am5awdksfyhbmmleqmblru3pfoajhjdilktwdca.b32.i2p:0 +ywkrrbyzwgc5b2lub4i5z5iwtedfz2byghh753vzlr4lxskwrsnq.b32.i2p:0 +yx6ghqhj7c5q3dfmwtmpg46dquicigagnwhw6aw3guzig4yrdwta.b32.i2p:0 +z2jyij2spdcwjqqfz6thpa4a6bp4lyg2jbaqkniiyyd4hocblwgq.b32.i2p:0 +z34pw5tlowwi3gpj3ycb2dptgyuq65bpj7w36xahslgikggo5eaa.b32.i2p:0 +z3j2xshl4tpbxaybcprhzq7cuz6urboqoxvvpnfriv4n2lq72jsq.b32.i2p:0 +z3pgyfiwfzcd2g7v4rs6el5tvc55y7a3tai4gcbpso6flaejckea.b32.i2p:0 +z6g6lmwuhnldiazyf72zlsvtwbql5mfvpmyaipuvjfwnb6slel6a.b32.i2p:0 +z6gf7u676kcbjcf3xydssjaxe77vatqr7lr4356usgdvsuh54jpa.b32.i2p:0 +zcwgqw7hlw7437a7au6n6obljdb4arnshoibdqo6voree4xiznoq.b32.i2p:0 +zh34uj3cwyr7zs2uc4aeyrhffgumxd5uzpfpbmbuyetqkd3xy4ia.b32.i2p:0 +znt6mdvmstxcdaqeiuo67k2ug4e422gjftrnm7ov2izaeuh73d5q.b32.i2p:0 +zqhoqgf3enj2pv74sjov6dthpr6jqafw5qqzzsvnfdqzycychxpq.b32.i2p:0 +zr744lzxu2lvzncuccwbo2p5rpocsidorh5nug2it2yfsppbcjsa.b32.i2p:0 +ztmhh3h46uvwd5pmuauzjhcsybo6tqgx5a4pmhpolwtxyeiud6xa.b32.i2p:0 +zxr2swmk37nxncdkzh3aym6bke3wnkf66zffv6k4wivce6smbreq.b32.i2p:0 +zyirlmzsnhkyhbs2lya5mnbvzbvnx2tqqnmplksa2ehs7s4yxcsq.b32.i2p:0 +2.39.163.191:8333 # AS30722 +2.83.248.77:8333 # AS3243 +2.87.72.235:8333 # AS6799 +3.9.188.44:8333 # AS16509 +3.76.143.185:8333 # AS16509 +3.231.154.195:8333 # AS14618 5.2.23.226:8333 # AS21472 +5.45.72.11:8333 # AS50673 +5.78.71.173:8333 # AS212317 +5.78.116.127:8333 # AS212317 5.128.87.126:8333 # AS31200 -5.157.103.202:8333 # AS35612 +5.144.88.83:8333 # AS61349 +5.172.132.104:8333 # AS15600 +5.186.60.13:8333 # AS44869 5.188.62.18:8333 # AS34665 -5.253.18.218:8333 # AS58073 -5.255.109.160:8333 # AS60404 -8.129.184.255:8333 # AS37963 +5.255.97.92:8333 # AS60404 8.209.70.77:8333 # AS45102 -8.210.18.56:8333 # AS45102 -12.34.98.148:8333 # AS7018 -18.27.79.17:8333 # AS3 -23.93.170.118:8333 # AS46375 -23.154.136.144:8333 # AS54002 -23.175.0.212:8333 # AS395502 +14.203.57.50:8333 # AS7545 +15.235.82.178:8333 # AS16276 +18.183.87.240:8333 # AS8987 +20.89.243.139:8333 # AS8075 +23.134.94.82:8333 # AS63023 +23.142.145.238:8333 # AS210000 23.175.0.222:8333 # AS395502 -24.84.164.50:8333 # AS6327 -24.86.90.127:8333 # AS6327 -24.101.126.194:8333 # AS27364 -24.183.75.154:8333 # AS20115 -27.124.108.19:8333 # AS58511 -27.148.206.140:8333 # AS4134 -31.25.98.16:8333 # AS48635 -31.41.23.249:8333 # AS31287 -31.47.202.112:8333 # AS34385 -31.156.128.248:8333 # AS30722 -31.164.160.162:8333 # AS6730 -31.201.190.134:8333 # AS50266 -31.208.34.61:8333 # AS29518 -34.78.14.25:8333 # AS15169 -34.80.134.68:8333 # AS15169 -35.137.133.225:8333 # AS7843 -35.193.192.48:8333 # AS396982 -35.194.39.250:8333 # AS396982 -37.15.60.144:8333 # AS12479 -37.60.228.251:8333 # AS31214 -37.60.229.117:8333 # AS31214 -37.110.132.94:8333 # AS42610 -37.120.179.29:8333 # AS47147 -37.139.102.73:8333 # AS35816 +24.6.89.155:8333 # AS33651 +24.36.96.14:8333 # AS7992 +24.76.199.86:8333 # AS6327 +24.116.163.227:8333 # AS11492 +24.119.41.234:8333 # AS11492 +24.146.33.13:8333 # AS7992 +24.148.52.108:8333 # AS6079 +24.156.42.154:8333 # AS19108 +27.148.206.140:8333 # AS133774 +31.19.205.19:8333 # AS3209 +31.30.59.201:8333 # AS16019 +31.189.24.188:8333 # AS24608 +35.170.77.206:8333 # AS14618 +35.208.62.130:8333 # AS15169 +35.213.159.168:8333 # AS15169 +35.228.210.193:8333 # AS396982 +35.244.9.182:8333 # AS396982 +37.60.246.82:8333 # AS51167 37.157.192.94:8333 # AS197019 -37.220.135.151:8333 # AS41206 -38.9.81.160:8333 # AS16904 -38.21.221.252:8333 # AS40545 -38.54.14.89:8333 # AS138915 -38.91.106.111:8333 # AS63023 -38.102.85.36:8333 # AS174 -42.2.162.218:8333 # AS4760 -43.129.75.20:8333 # AS132203 +37.221.197.208:8333 # AS197540 +38.38.192.248:8333 # AS394432 +38.40.110.66:8333 # AS398721 +38.75.215.250:8333 # AS397377 +38.75.235.97:8333 # AS397142 +38.102.85.36:8333 # AS26832 +38.111.114.155:8333 # AS62563 +38.254.140.40:8333 # AS54936 +40.160.13.7:8333 # AS16276 43.159.61.16:8333 # AS132203 -43.225.62.107:8333 # AS63953 -43.245.196.214:8333 # AS63916 -45.13.7.221:8333 # AS60377 -45.44.213.123:8333 # AS54198 -45.48.75.224:8333 # AS20001 -45.79.76.12:8333 # AS63949 -45.94.209.127:8333 # AS13789 -45.130.23.57:8333 # AS3214 -45.132.118.25:8333 # AS208451 -45.144.249.207:8333 # AS203936 -45.145.40.43:8333 # AS63213 -45.155.169.30:8333 # AS62000 -46.17.99.13:8333 # AS57043 -46.17.99.26:8333 # AS57043 -46.21.250.25:8333 # AS24875 -46.28.204.161:8333 # AS197988 -46.128.199.26:8333 # AS16097 -46.164.59.139:8333 # AS21283 -46.166.142.2:8333 # AS43350 -46.172.233.241:8333 # AS6752 -46.252.5.112:8333 # AS206774 -47.28.85.71:8333 # AS20115 -47.176.248.250:8333 # AS5650 -47.198.60.180:8333 # AS5650 -50.27.22.141:8333 # AS19108 -50.39.170.149:8333 # AS20055 -50.53.250.162:8333 # AS20055 -51.154.62.103:8333 # AS15796 -51.158.150.155:8333 # AS12876 +43.198.159.17:8333 # AS8987 +43.225.143.17:8333 # AS136907 +45.45.27.233:8333 # AS5769 +45.88.106.107:8333 # AS204601 +45.129.84.136:8333 # AS206264 +45.129.181.107:8333 # AS197540 +45.130.20.177:8333 # AS3214 +45.142.235.46:8333 # AS206238 +45.150.66.10:8333 # AS200195 +45.207.43.110:8333 # AS133861 +46.10.211.143:8333 # AS8866 +46.23.87.218:8333 # AS60131 +46.28.205.68:8333 # AS197988 +46.32.178.82:8333 # AS196925 +46.39.167.49:8333 # AS31246 +46.59.40.91:8333 # AS8473 +46.148.235.36:8333 # AS49505 +46.150.161.43:8333 # AS49106 +46.175.178.3:8333 # AS56427 +46.229.238.187:8333 # AS29405 +47.12.228.122:8333 # AS20115 +47.184.159.236:8333 # AS5650 +47.254.178.44:8333 # AS45102 +50.4.18.90:8333 # AS12083 +50.30.36.140:8333 # AS30083 +50.45.128.28:8333 # AS27017 +50.79.86.113:8333 # AS33489 +50.126.96.22:8333 # AS27017 +50.144.135.40:8333 # AS33657 +51.154.26.11:8333 # AS15796 51.174.206.76:8333 # AS29695 -54.217.136.122:8333 # AS16509 -54.253.15.33:8333 # AS16509 -57.128.96.115:8333 # AS8220 -57.128.148.169:8333 # AS8220 -58.6.46.171:8333 # AS7545 -58.96.77.114:8333 # AS10143 -58.96.123.120:8333 # AS38195 -58.168.253.35:8333 # AS1221 -59.167.191.60:8333 # AS4739 -60.205.205.119:8333 # AS37963 -60.212.189.151:8333 # AS4837 -61.74.99.193:8333 # AS4766 -62.24.76.122:8333 # AS16019 -62.106.70.249:8333 # AS8100 +51.194.13.25:8333 # AS5607 +58.229.105.38:8333 # AS9318 +59.188.108.150:8333 # AS9381 +62.12.168.100:8333 # AS15623 62.168.65.42:8333 # AS5578 -62.171.129.32:8333 # AS51167 -62.245.75.70:8333 # AS16019 -62.248.8.167:8333 # AS16010 -64.23.150.211:8333 # AS3064 -64.98.119.136:8333 # AS32133 -65.24.75.34:8333 # AS7843 -65.175.185.101:8333 # AS11776 -66.45.141.46:8333 # AS11232 -66.58.163.185:8333 # AS8047 -66.85.133.182:8333 # AS12189 -66.206.22.26:8333 # AS29802 -67.40.102.33:8333 # AS209 -67.43.210.62:8333 # AS394883 -67.82.136.177:8333 # AS6128 -67.193.87.50:8333 # AS7992 +62.177.111.78:8333 # AS29208 +62.210.207.63:8333 # AS12876 +64.20.45.42:8333 # AS19318 +64.31.61.150:8333 # AS46475 +64.42.176.234:8333 # AS63018 +64.46.58.172:8333 # AS20161 +64.68.203.11:8333 # AS16686 +64.156.192.61:8333 # AS21581 +64.185.225.26:8333 # AS18450 +64.187.168.198:8333 # AS11404 +64.253.104.118:8333 # AS4364 +66.18.13.162:8333 # AS13767 +66.29.129.233:8333 # AS22612 +66.35.84.30:8333 # AS2734 +66.194.38.45:8333 # AS35863 +66.228.28.63:8333 # AS11233 +67.145.204.18:8333 # AS19901 +67.205.190.143:8333 # AS14061 67.210.228.203:8333 # AS7819 -67.211.211.118:8333 # AS19318 -67.231.246.58:8333 # AS40244 -68.6.84.222:8333 # AS22773 -68.48.136.216:8333 # AS7922 -68.69.170.92:8333 # AS6315 -69.4.94.226:8333 # AS36352 -69.8.175.201:8333 # AS21766 -69.57.160.49:8333 # AS22612 -69.112.103.124:8333 # AS6128 +67.217.61.213:8333 # AS19318 +67.251.135.17:8333 # AS12271 +68.39.190.185:8333 # AS33491 +68.75.195.2:8333 # AS17235 +68.102.134.227:8333 # AS22773 +68.219.242.34:8333 # AS8075 +69.4.94.226:8333 # AS55286 +69.142.28.54:8333 # AS33287 +69.146.62.1:8333 # AS33588 +69.176.188.251:8333 # AS18988 +69.180.170.215:8333 # AS13367 +69.181.64.87:8333 # AS33651 69.196.152.33:8333 # AS5645 -71.19.148.180:8333 # AS6939 -73.227.153.213:8333 # AS1351 -74.50.81.93:8333 # AS19318 -74.101.205.214:8333 # AS701 -74.118.137.119:8333 # AS20326 -74.213.175.108:8333 # AS21949 -74.213.251.239:8333 # AS14978 +70.35.98.12:8333 # AS32264 +70.67.139.204:8333 # AS6327 +70.121.50.147:8333 # AS11427 +70.172.132.78:8333 # AS22773 +71.224.201.224:8333 # AS33287 +72.18.53.189:8333 # AS40545 +72.46.131.18:8333 # AS36114 +72.50.220.5:8333 # AS10242 +72.71.209.96:8333 # AS13977 +73.35.246.175:8333 # AS33650 +73.98.107.37:8333 # AS33654 +73.98.178.236:8333 # AS33660 +73.117.132.138:8333 # AS7016 +73.131.209.70:8333 # AS33660 +73.157.112.178:8333 # AS33650 +73.228.173.21:8333 # AS13367 +73.253.55.217:8333 # AS7015 +74.73.229.148:8333 # AS12271 +74.112.115.197:8333 # AS11525 +74.118.138.124:8333 # AS20326 +74.118.143.8:8333 # AS20326 +74.133.90.251:8333 # AS10796 +74.213.251.233:8333 # AS14978 74.220.255.190:8333 # AS23175 -77.20.48.144:8333 # AS3209 -77.21.149.160:8333 # AS204028 -77.37.240.209:8333 # AS42610 -77.43.14.68:8333 # AS5396 -77.111.57.109:8333 # AS3212 -77.162.190.90:8333 # AS1136 -77.173.132.140:8333 # AS1136 -77.202.10.220:8333 # AS15557 -78.27.139.13:8333 # AS6723 -78.31.71.190:8333 # AS24961 -78.35.147.203:8333 # AS8422 -78.42.144.24:8333 # AS51185 -78.43.153.185:8333 # AS51185 -78.56.89.146:8333 # AS8764 -78.70.208.53:8333 # AS3301 -79.109.120.38:8333 # AS12430 -79.116.56.89:8333 # AS57269 -79.124.7.253:8333 # AS203380 -79.136.250.162:8333 # AS9049 -80.83.186.25:8333 # AS33891 -80.98.75.248:8333 # AS21334 -80.229.28.60:8333 # AS2856 -80.244.26.192:8333 # AS35432 -81.4.110.168:8333 # AS198203 +76.113.120.246:8333 # AS33654 +76.127.211.90:8333 # AS7015 +76.154.162.182:8333 # AS33652 +77.33.144.156:8333 # AS44869 +77.38.3.90:8333 # AS3212 +77.100.20.178:8333 # AS5089 +77.109.112.223:8333 # AS9031 +77.165.250.62:8333 # AS1136 +77.223.120.139:8333 # AS50340 +77.240.190.41:8333 # AS24641 +78.30.57.78:8333 # AS15704 +78.157.91.120:8333 # AS21211 +79.54.240.124:8333 # AS3269 +79.116.53.50:8333 # AS57269 +79.134.99.114:8333 # AS16302 +79.156.138.107:8333 # AS3352 +80.60.120.119:8333 # AS1136 +80.64.211.102:8333 # AS200295 +80.64.211.103:8333 # AS200295 +80.90.4.178:8333 # AS20546 +80.108.219.153:8333 # AS8412 +80.209.231.126:8333 # AS62282 +80.241.194.147:8333 # AS8881 81.7.17.202:8333 # AS35366 -81.19.10.2:8333 # AS24641 81.83.214.134:8333 # AS6848 -81.170.142.100:8333 # AS8473 -81.171.22.143:8333 # AS60781 -81.242.239.139:8333 # AS5432 +81.197.182.195:8333 # AS719 +81.229.234.87:8333 # AS3301 +82.10.250.130:8333 # AS5089 +82.64.49.27:8333 # AS12322 82.66.10.11:8333 # AS12322 -82.66.204.177:8333 # AS12322 -82.96.96.40:8333 # AS29686 -82.149.225.249:8333 # AS29551 -82.155.148.211:8333 # AS8657 -82.181.218.133:8333 # AS16086 -83.99.247.25:8333 # AS24651 +82.71.47.216:8333 # AS13037 +82.73.188.178:8333 # AS33915 +82.85.110.20:8333 # AS8612 +82.124.33.119:8333 # AS3215 +82.174.142.202:8333 # AS50266 +82.195.237.251:8333 # AS1836 +82.218.34.162:8333 # AS8339 +83.49.10.227:8333 # AS3352 +83.78.112.142:8333 # AS3303 83.136.232.21:8333 # AS29182 -83.192.226.66:8333 # AS3215 +83.144.180.88:8333 # AS2860 +83.150.2.128:8333 # AS8758 +83.168.65.186:8333 # AS31304 83.208.193.242:8333 # AS5610 -83.240.118.196:8333 # AS31246 -84.7.219.130:8333 # AS15557 -84.52.64.82:8333 # AS25408 -84.64.99.78:8333 # AS5378 -84.112.60.16:8333 # AS8412 +83.218.160.161:8333 # AS31543 +84.32.248.63:8333 # AS16125 +84.75.0.178:8333 # AS6730 84.113.129.195:8333 # AS8412 -84.211.187.211:8333 # AS41164 -84.217.134.213:8333 # AS2119 -84.247.128.15:8333 # AS49788 -84.247.132.27:8333 # AS29286 -84.247.173.117:8333 # AS29286 -84.247.179.51:8333 # AS49788 -84.255.245.194:8333 # AS34779 -85.145.79.26:8333 # AS50266 -85.173.165.66:8333 # AS12389 -85.195.196.86:8333 # AS13030 -85.214.118.71:8333 # AS6724 -86.22.20.13:8333 # AS5089 -86.45.238.115:8333 # AS5466 -86.182.223.189:8333 # AS2856 -86.215.168.115:8333 # AS3215 -87.79.94.221:8333 # AS8422 -87.90.94.120:8333 # AS5410 -87.92.171.53:8333 # AS16086 +84.195.116.26:8333 # AS6848 +84.246.200.122:8333 # AS42455 +84.255.238.120:8333 # AS34779 +85.14.79.26:8333 # AS31242 +85.146.115.136:8333 # AS50266 +85.159.237.71:8333 # AS43350 +85.195.83.50:8333 # AS20773 +85.214.161.252:8333 # AS6724 +85.214.223.36:8333 # AS6724 +85.215.75.210:8333 # AS8560 +85.234.145.132:8333 # AS29550 +85.246.38.150:8333 # AS3243 +85.252.216.146:8333 # AS2116 +86.41.130.108:8333 # AS5466 +86.101.92.93:8333 # AS21334 +86.104.228.12:8333 # AS45021 +86.104.228.36:8333 # AS45021 +86.109.12.60:8333 # AS54825 +86.111.48.71:8333 # AS50304 +86.111.48.72:8333 # AS50304 +86.124.145.184:8333 # AS8708 +86.133.133.82:8333 # AS2856 +87.120.8.239:8333 # AS34224 +87.179.122.129:8333 # AS3320 87.236.195.198:8333 # AS35592 -87.236.199.197:8333 # AS35592 -88.6.31.66:8333 # AS3352 -88.9.73.252:8333 # AS3352 -88.84.223.30:8333 # AS21453 -88.146.114.173:8333 # AS29208 -89.35.142.177:8333 # AS34977 -89.44.41.142:8333 # AS56478 -89.116.25.234:8333 # AS398465 -89.117.58.113:8333 # AS1239 -89.117.172.121:8333 # AS3320 -89.165.232.242:8333 # AS48161 -89.190.142.56:8333 # AS38919 -89.216.91.120:8333 # AS31042 -89.247.224.28:8333 # AS8881 -90.146.207.67:8333 # AS12605 -90.156.26.148:8333 # AS12741 -90.163.172.78:8333 # AS12479 -90.192.118.202:8333 # AS5607 -90.208.159.11:8333 # AS5607 -90.247.70.31:8333 # AS5378 -91.86.25.207:8333 # AS47377 -91.123.182.164:8333 # AS51648 -91.123.183.219:8333 # AS51792 -91.134.145.202:8333 # AS16276 -91.135.0.187:8333 # AS12496 -91.152.122.36:8333 # AS6667 -91.184.174.191:8333 # AS9063 -91.204.149.5:8333 # AS42765 -91.206.17.195:8333 # AS13259 -91.209.51.131:8333 # AS48239 -91.215.91.254:8333 # AS48078 -91.231.182.53:8333 # AS44103 -91.236.251.137:8333 # AS57944 -91.236.251.139:8333 # AS57944 -91.237.88.218:8333 # AS56813 -92.27.150.46:8333 # AS13285 -92.27.150.47:8333 # AS13285 -92.42.110.219:8333 # AS1273 -92.43.187.34:8333 # AS8359 -92.206.105.31:8333 # AS20880 -92.233.2.59:8333 # AS5089 -92.240.181.45:8333 # AS16246 -93.51.13.120:8333 # AS12874 -93.57.81.162:8333 # AS12874 -93.71.19.130:8333 # AS30722 -93.81.254.159:8333 # AS8402 -93.90.82.227:8333 # AS47626 -93.100.35.189:8333 # AS35807 -93.103.13.1:8333 # AS34779 -93.123.180.164:8333 # AS35539 +88.85.88.133:8333 # AS35415 +88.88.58.251:8333 # AS2119 +88.99.71.213:8333 # AS24940 +88.119.128.36:8333 # AS8764 +88.134.41.88:8333 # AS3209 +88.210.15.24:8333 # AS25308 +88.212.53.246:8333 # AS42841 +88.218.226.91:8333 # AS48314 +89.1.104.97:8333 # AS8422 +89.39.106.26:8333 # AS49981 +89.179.240.133:8333 # AS8402 +89.207.131.19:8333 # AS62370 +89.233.207.67:8333 # AS29518 +90.26.82.45:8333 # AS3215 +90.173.118.109:8333 # AS12479 +90.250.10.165:8333 # AS5378 +91.90.166.203:8333 # AS214815 +91.92.144.226:8333 # AS44901 +91.92.154.18:8333 # AS61098 +91.202.4.65:8333 # AS43641 +91.228.45.130:8333 # AS197895 +91.239.130.62:8333 # AS62240 +91.240.84.52:8333 # AS29182 +92.42.110.214:8333 # AS29066 +92.84.188.206:8333 # AS9050 +92.205.232.47:8333 # AS21499 +92.206.105.31:8333 # AS16202 +92.247.49.210:8333 # AS29580 +93.16.43.241:8333 # AS198949 +93.38.127.179:8333 # AS12874 +93.115.26.6:8333 # AS16125 93.177.188.74:8333 # AS16010 -93.188.102.53:8333 # AS43989 -94.19.7.55:8333 # AS35807 -94.63.75.74:8333 # AS12353 -94.72.141.61:8333 # AS57344 -94.72.143.47:8333 # AS203380 -94.105.53.124:8333 # AS47377 -94.181.46.106:8333 # AS9049 -94.231.253.18:8333 # AS35224 -95.42.140.142:8333 # AS8866 -95.82.130.223:8333 # AS31246 -95.88.61.176:8333 # AS204028 +94.19.128.204:8333 # AS35807 +94.131.0.73:8333 # AS8772 +94.136.2.126:8333 # AS48943 +94.156.128.153:8333 # AS44901 +94.203.133.251:8333 # AS15802 +94.210.55.89:8333 # AS33915 +94.241.90.251:8333 # AS42908 95.105.172.171:8333 # AS15962 -95.110.234.93:8333 # AS31034 -95.164.182.44:8333 # AS29632 -95.191.130.100:8333 # AS12389 -96.3.53.254:8333 # AS11232 -97.75.144.9:8333 # AS22709 -98.17.95.93:8333 # AS398465 -98.128.230.186:8333 # AS8473 -98.163.242.149:8333 # AS22773 -98.229.126.23:8333 # AS1351 -99.233.20.215:8333 # AS812 -99.246.87.2:8333 # AS812 -101.51.138.194:8333 # AS38040 -102.130.113.94:8333 # AS328364 -103.99.170.210:8333 # AS54415 -103.99.170.220:8333 # AS54415 -103.156.165.171:8333 # AS63859 -103.219.169.49:8333 # AS13335 -104.171.202.244:8333 # AS30496 -104.225.220.33:8333 # AS29802 -104.244.73.6:8333 # AS53667 -104.244.79.131:8333 # AS53667 -108.49.65.132:8333 # AS701 -109.86.60.33:8333 # AS13188 -109.91.141.145:8333 # AS3209 -109.99.63.159:8333 # AS9050 -109.120.194.136:8333 # AS34569 -109.196.124.182:8333 # AS196883 -109.201.168.32:8333 # AS41750 +95.169.196.247:8333 # AS201133 +95.211.152.100:8333 # AS60781 +95.213.145.218:8333 # AS49505 +96.41.133.58:8333 # AS20115 +96.74.179.132:8333 # AS33491 +97.113.140.223:8333 # AS209 +98.13.77.64:8333 # AS11351 +98.156.108.211:8333 # AS11427 +99.95.54.159:8333 # AS7018 +99.229.106.225:8333 # AS812 +99.240.98.36:8333 # AS812 +101.32.127.143:8333 # AS132203 +101.100.139.249:8333 # AS9790 +103.37.205.47:8333 # AS56068 +103.45.247.202:8333 # AS41436 +103.76.205.213:8333 # AS58610 +103.99.169.110:8333 # AS54415 +103.101.203.44:8333 # AS36007 +103.231.42.36:8333 # AS18229 +103.233.83.28:8333 # AS4213 +104.128.64.58:8333 # AS36007 +104.128.201.183:8333 # AS13428 +104.172.235.227:8333 # AS20001 +104.219.214.211:8333 # AS398823 +104.221.34.226:8333 # AS5769 +104.229.101.78:8333 # AS11351 +104.238.220.199:8333 # AS23470 +107.148.56.81:8333 # AS399195 +107.148.68.174:8333 # AS394432 +107.155.67.210:8333 # AS29802 +107.191.33.82:8333 # AS20473 +108.26.149.161:8333 # AS701 +108.225.195.53:8333 # AS7018 +109.150.129.227:8333 # AS2856 +109.207.79.248:8333 # AS44709 109.224.84.149:8333 # AS197197 -111.90.140.46:8333 # AS45839 -112.139.10.25:8333 # AS10010 -114.34.130.206:8333 # AS3462 -116.58.171.67:8333 # AS2514 -116.86.195.192:8333 # AS4657 -119.31.179.202:8333 # AS17408 -119.42.55.203:8333 # AS133159 +109.235.247.122:8333 # AS205950 +111.90.158.123:8333 # AS45839 +111.90.158.137:8333 # AS45839 +115.140.124.99:8333 # AS17858 +116.86.195.192:8333 # AS55430 +117.48.133.67:8333 # AS140292 +118.24.37.253:8333 # AS45090 120.226.39.100:8333 # AS9808 -120.226.39.103:8333 # AS9808 -121.6.69.73:8333 # AS9506 -121.99.240.87:8333 # AS9790 -122.148.147.136:8333 # AS4826 -122.199.40.21:8333 # AS38195 -123.60.213.192:8333 # AS55990 -123.202.193.121:8333 # AS9269 -124.170.182.194:8333 # AS7545 -124.197.54.113:8333 # AS9790 -125.168.110.28:8333 # AS4826 -125.227.178.68:8333 # AS3462 +121.98.22.147:8333 # AS9790 +122.40.25.57:8333 # AS17858 +128.0.98.214:8333 # AS42652 128.0.190.26:8333 # AS30764 -129.13.189.215:8333 # AS34878 -130.44.176.111:8333 # AS6079 -130.204.161.3:8333 # AS8717 -131.153.232.139:8333 # AS12189 -131.188.40.47:8333 # AS680 -134.65.193.149:8333 # AS19037 -135.19.41.208:8333 # AS5769 -135.19.253.101:8333 # AS5769 -135.23.204.98:8333 # AS5645 -135.181.215.237:8333 # AS24940 -136.55.46.15:8333 # AS16591 -136.62.58.224:8333 # AS16591 -136.175.8.175:8333 # AS14315 -136.244.19.126:8333 # AS397412 -137.226.34.46:8333 # AS680 -138.59.20.209:8333 # AS28201 -139.59.70.163:8333 # AS14061 -140.238.220.99:8333 # AS31898 -141.193.68.11:8333 # AS396998 -142.54.181.218:8333 # AS32097 +128.2.12.38:8333 # AS9 +129.10.85.103:8333 # AS156 +129.80.192.20:8333 # AS31898 +129.126.172.115:8333 # AS17547 +130.180.211.123:8333 # AS199636 +130.250.7.252:8333 # AS394901 +131.153.203.205:8333 # AS20454 +131.153.232.199:8333 # AS19437 +131.153.238.121:8333 # AS19437 +133.3.249.155:8333 # AS2504 +133.5.165.199:8333 # AS2508 +133.125.50.180:8333 # AS7684 +134.65.193.149:8333 # AS44486 +134.195.196.65:8333 # AS62563 +136.49.31.88:8333 # AS16591 +136.62.152.251:8333 # AS16591 +136.169.52.139:8333 # AS20910 +138.2.110.216:8333 # AS31898 +138.75.131.48:8333 # AS4773 +140.186.199.14:8333 # AS11232 +141.0.155.19:8333 # AS56478 142.115.140.2:8333 # AS577 -142.188.125.200:8333 # AS577 -143.110.252.124:8333 # AS14061 -144.24.236.64:8333 # AS31898 -144.137.29.181:8333 # AS1221 -146.71.69.103:8333 # AS7782 -149.28.159.141:8333 # AS20473 -149.143.32.26:8333 # AS15435 -149.202.79.199:8333 # AS16276 -149.248.1.254:8333 # AS20473 -151.248.221.197:8333 # AS8821 -152.44.137.83:8333 # AS11404 -152.230.180.115:8333 # AS14259 -154.26.137.105:8333 # AS174 -154.92.111.100:8333 # AS141356 -157.131.20.174:8333 # AS46375 -158.129.140.201:8333 # AS5479 -158.181.114.196:8333 # AS8821 -158.220.85.82:8333 # AS8556 -158.220.121.93:8333 # AS8556 -159.2.191.175:8333 # AS855 -159.224.238.145:8333 # AS13188 -161.97.167.10:8333 # AS51167 -162.213.119.12:8333 # AS2711 -162.226.61.8:8333 # AS7018 -162.254.171.209:8333 # AS17210 -163.114.159.205:8333 # AS15830 -163.172.84.134:8333 # AS12876 -165.255.241.184:8333 # AS327693 -167.179.147.155:8333 # AS4764 -169.150.206.206:8333 # AS60068 -170.17.151.235:8333 # AS3303 -170.254.147.116:8333 # AS265398 -172.92.102.115:8333 # AS11404 -172.105.21.216:8333 # AS63949 -172.219.229.252:8333 # AS852 -172.251.101.27:8333 # AS20001 -173.12.119.133:8333 # AS7922 -173.19.176.228:8333 # AS30036 -173.181.35.50:8333 # AS395570 -173.212.98.0:8333 # AS11260 -173.241.227.243:8333 # AS19009 -173.246.31.114:8333 # AS1403 -174.20.57.30:8333 # AS209 -175.27.247.104:8333 # AS45090 -175.136.174.174:8333 # AS4788 -176.9.17.121:8333 # AS24940 -176.37.82.83:8333 # AS39608 +142.202.48.124:8333 # AS63023 +143.0.142.156:8333 # AS264009 +144.2.104.35:8333 # AS57370 +144.2.104.189:8333 # AS57370 +144.126.147.252:8333 # AS40021 +147.28.211.75:8333 # AS54825 +147.32.95.62:8333 # AS2852 +149.7.216.178:8333 # AS174 +149.28.116.34:8333 # AS20473 +149.50.101.15:8333 # AS201814 +149.50.101.28:8333 # AS201814 +152.117.88.43:8333 # AS30600 +152.165.38.160:8333 # AS2527 +153.92.93.114:8333 # AS41998 +154.7.1.114:8333 # AS139646 +154.26.130.95:8333 # AS141995 +154.26.154.73:8333 # AS141995 +154.38.167.152:8333 # AS40021 +154.65.14.19:8333 # AS37628 +155.4.142.33:8333 # AS8473 +157.143.21.102:8333 # AS8758 +157.147.131.251:8333 # AS2527 +158.248.34.141:8333 # AS29695 +159.138.87.18:8333 # AS136907 +159.196.227.196:8333 # AS4764 +159.246.25.53:8333 # AS30491 +160.16.110.6:8333 # AS9370 +160.80.12.16:8333 # AS137 +160.80.97.66:8333 # AS137 +161.97.151.9:8333 # AS51167 +162.0.226.60:8333 # AS22612 +162.55.122.93:8333 # AS24940 +162.219.38.94:8333 # AS10099 +162.245.196.45:8333 # AS23314 +164.152.167.208:8333 # AS59253 +165.22.229.88:8333 # AS14061 +166.70.211.78:8333 # AS6315 +166.78.241.20:8333 # AS19994 +166.78.241.25:8333 # AS19994 +167.88.11.203:8333 # AS20278 +167.248.185.196:8333 # AS398721 +169.155.170.211:8333 # AS44486 +171.101.73.128:8333 # AS7470 +172.81.182.240:8333 # AS174 +172.92.31.45:8333 # AS11404 +172.93.106.85:8333 # AS23470 +172.233.211.171:8333 # AS63949 +172.234.95.35:8333 # AS63949 +172.241.70.236:8333 # AS7979 +173.66.197.19:8333 # AS701 +173.87.234.220:8333 # AS5650 +173.181.35.50:8333 # AS852 +173.183.130.47:8333 # AS852 +173.197.244.157:8333 # AS10838 +174.21.76.8:8333 # AS209 +174.57.136.72:8333 # AS33659 +174.63.171.76:8333 # AS33661 +174.88.243.94:8333 # AS577 +175.110.115.120:8333 # AS49981 176.74.136.237:8333 # AS35613 +176.99.2.90:8333 # AS197695 +176.114.248.225:8333 # AS202618 176.118.220.29:8333 # AS60042 -176.138.233.166:8333 # AS5410 -177.32.50.167:8333 # AS28573 -178.21.118.178:8333 # AS49544 -178.41.11.254:8333 # AS6855 -178.79.83.147:8333 # AS3212 -178.88.189.254:8333 # AS9198 -178.154.222.104:8333 # AS200350 -178.159.98.133:8333 # AS202390 -178.198.23.120:8333 # AS3303 -178.250.232.111:8333 # AS31197 -182.229.145.161:8333 # AS3786 -183.88.223.208:8333 # AS45758 -183.129.178.205:8333 # AS4134 -185.25.48.184:8333 # AS61272 -185.26.99.171:8333 # AS44066 -185.31.136.246:8333 # AS47605 -185.52.93.45:8333 # AS39449 -185.69.53.153:8333 # AS62282 -185.84.224.116:8333 # AS8816 -185.107.83.55:8333 # AS43350 -185.116.94.239:8333 # AS39184 -185.140.209.159:8333 # AS44901 -185.148.3.227:8333 # AS47605 -185.152.138.74:8333 # AS6697 -185.153.196.14:8333 # AS15836 -185.153.196.162:8333 # AS15836 -185.156.37.30:8333 # AS202605 -185.156.154.129:8333 # AS41897 -185.158.113.172:8333 # AS28917 -185.165.170.19:8333 # AS3223 -185.190.24.72:8333 # AS9002 -185.199.209.52:8333 # AS49666 -185.203.41.148:8333 # AS9009 +176.126.116.7:8333 # AS207586 +176.136.243.63:8333 # AS5410 +176.205.158.198:8333 # AS5384 +178.38.6.52:8333 # AS6730 +183.88.223.208:8333 # AS45629 +184.56.122.69:8333 # AS10796 +184.95.32.130:8333 # AS20454 +184.105.131.181:8333 # AS6939 +184.171.208.109:8333 # AS40788 +185.8.106.179:8333 # AS204770 +185.11.61.33:8333 # AS57523 +185.19.30.242:8333 # AS61098 +185.26.99.171:8333 # AS44051 +185.31.136.166:8333 # AS60414 +185.31.136.246:8333 # AS60414 +185.63.97.216:8333 # AS50825 +185.64.125.16:8333 # AS59921 +185.65.93.104:8333 # AS201730 +185.68.67.42:8333 # AS6772 +185.70.43.193:8333 # AS62371 +185.78.209.28:8333 # AS202128 +185.88.229.254:8333 # AS20963 +185.112.144.119:8333 # AS44925 +185.137.173.125:8333 # AS13030 +185.140.246.140:8333 # AS48602 +185.144.83.131:8333 # AS9009 +185.148.3.227:8333 # AS203003 +185.150.162.111:8333 # AS34197 +185.156.202.35:8333 # AS56388 +185.163.44.36:8333 # AS39798 +185.197.30.66:8333 # AS63473 +185.197.160.61:8333 # AS60144 185.209.12.76:8333 # AS212323 -185.210.125.33:8333 # AS205671 -185.233.189.210:8333 # AS61303 -185.250.36.66:8333 # AS1239 -185.254.97.164:8333 # AS44486 -186.235.86.249:8333 # AS263097 -188.27.79.235:8333 # AS8708 -188.35.167.14:8333 # AS34123 -188.68.53.44:8333 # AS47147 -188.119.67.137:8333 # AS9002 -188.127.243.41:8333 # AS56694 -188.138.112.60:8333 # AS20773 -188.142.199.17:8333 # AS21334 -188.155.72.160:8333 # AS6730 -188.214.129.52:8333 # AS16125 -188.214.129.139:8333 # AS16125 -188.215.62.122:8333 # AS203600 -188.237.167.51:8333 # AS8926 -188.246.224.12:8333 # AS49505 -189.6.221.37:8333 # AS28573 -190.2.146.90:8333 # AS49981 -190.17.18.190:8333 # AS7303 -190.210.98.253:8333 # AS16814 -192.3.11.24:8333 # AS36352 -192.69.53.18:8333 # AS11142 -192.146.137.44:8333 # AS25376 -193.22.128.12:8333 # AS39647 -193.39.142.89:8333 # AS60781 -193.46.74.252:8333 # AS395003 -193.46.74.254:8333 # AS395003 -193.95.249.3:8333 # AS5603 -193.149.176.200:8333 # AS40676 -193.151.155.122:8333 # AS49666 -193.187.90.122:8333 # AS3399 -193.196.37.62:8333 # AS34878 -194.35.184.95:8333 # AS9063 -194.165.30.20:8333 # AS35162 -194.191.232.153:8333 # AS1836 -195.32.108.164:8333 # AS3269 -195.56.63.11:8333 # AS5483 +185.239.221.23:8333 # AS61282 +185.243.218.19:8333 # AS56655 +185.243.218.106:8333 # AS56655 +185.248.160.163:8333 # AS43350 +188.12.149.216:8333 # AS3269 +188.63.158.192:8333 # AS3303 +188.138.88.47:8333 # AS8972 +188.138.112.60:8333 # AS8972 +188.213.92.39:8333 # AS206238 +188.243.71.145:8333 # AS35807 +189.32.136.9:8333 # AS28573 +190.53.100.34:8333 # AS27773 +190.64.134.52:8333 # AS6057 +191.13.128.58:8333 # AS27699 +191.251.32.162:8333 # AS18881 +191.255.221.37:8333 # AS27699 +192.3.11.20:8333 # AS36352 +192.3.11.26:8333 # AS36352 +192.34.87.86:8333 # AS33083 +192.161.48.47:8333 # AS8100 +192.187.121.46:8333 # AS33387 +192.227.73.9:8333 # AS13886 +192.243.215.102:8333 # AS63297 +193.22.128.23:8333 # AS56469 +193.72.32.187:8333 # AS33965 +193.84.116.22:8333 # AS2852 +193.176.1.74:8333 # AS24961 +193.200.206.14:8333 # AS49747 +193.218.118.13:8333 # AS207656 +193.222.130.14:8333 # AS29208 +194.0.157.6:8333 # AS25099 +194.14.246.9:8333 # AS50066 +194.67.64.229:8333 # AS49352 +194.67.208.191:8333 # AS209641 195.56.63.12:8333 # AS5483 -195.123.217.63:8333 # AS21100 -195.128.248.153:8333 # AS25229 -195.140.226.154:8333 # AS35614 -195.160.222.81:8333 # AS31148 -195.206.105.7:8333 # AS9009 -199.36.253.252:8333 # AS16713 -199.58.100.115:8333 # AS25961 -202.90.242.93:8333 # AS4764 -202.112.238.128:8333 # AS4538 -202.186.38.99:8333 # AS9930 -203.12.0.167:8333 # AS134697 -203.12.10.224:8333 # AS134697 -203.210.193.21:8333 # AS45899 -204.228.142.211:8333 # AS6315 -205.178.182.133:8333 # AS396998 -206.55.178.157:8333 # AS10242 -206.192.203.0:8333 # AS7029 -207.98.253.88:8333 # AS12083 -207.115.84.47:8333 # AS18530 -207.255.193.47:8333 # AS11776 -208.104.92.74:8333 # AS14615 -209.38.244.87:8333 # AS2914 -209.204.29.18:8333 # AS395439 +195.154.172.177:8333 # AS12876 +195.181.245.149:8333 # AS62282 +195.189.97.38:8333 # AS59642 +197.155.6.43:8333 # AS37199 +198.27.174.140:8333 # AS1299 +198.98.117.238:8333 # AS21949 +198.154.93.110:8333 # AS55081 +199.7.144.151:8333 # AS21949 +199.36.253.252:8333 # AS396952 +200.122.181.26:8333 # AS3790 +200.180.197.188:8333 # AS8167 +202.7.254.250:8333 # AS136994 +202.186.41.219:8333 # AS9930 +203.11.72.118:8333 # AS401199 +203.11.72.199:8333 # AS401199 +203.34.58.43:8333 # AS7545 +203.51.11.167:8333 # AS1221 +204.15.11.35:8333 # AS13331 +204.194.220.39:8333 # AS20055 +204.194.220.40:8333 # AS20055 +206.125.169.164:8333 # AS25795 +206.204.106.8:8333 # AS212947 +207.66.71.46:8333 # AS399220 +207.90.192.54:8333 # AS26832 +207.182.146.130:8333 # AS10297 +208.93.231.240:8333 # AS29893 +209.141.37.57:8333 # AS53667 +209.177.138.245:8333 # AS7832 209.205.204.218:8333 # AS55081 -209.237.133.54:8333 # AS53859 -210.6.95.127:8333 # AS9269 -210.205.146.114:8333 # AS9318 211.221.42.143:8333 # AS4766 -212.5.157.40:8333 # AS8866 -212.51.136.50:8333 # AS13030 +212.10.229.240:8333 # AS39642 +212.29.41.158:8333 # AS15763 +212.51.129.60:8333 # AS13030 +212.68.218.124:8333 # AS12392 212.86.32.106:8333 # AS15366 -212.162.152.149:8333 # AS24875 -212.227.150.147:8333 # AS8560 -212.227.155.170:8333 # AS8560 -212.251.162.190:8333 # AS2119 -213.109.236.129:8333 # AS47702 -213.141.154.201:8333 # AS12714 -213.193.83.251:8333 # AS6830 -213.193.83.252:8333 # AS6830 -213.202.225.122:8333 # AS24961 +212.158.133.185:8333 # AS1299 +213.165.95.142:8333 # AS8560 +213.174.156.81:8333 # AS39572 +213.174.156.86:8333 # AS39572 +213.217.210.90:8333 # AS12709 +213.227.147.244:8333 # AS60781 216.83.150.142:8333 # AS5048 -216.186.236.98:8333 # AS12083 -216.232.33.24:8333 # AS395570 +216.226.128.189:8333 # AS13706 +217.11.240.4:8333 # AS21430 +217.20.131.64:8333 # AS5483 217.64.47.138:8333 # AS39324 217.64.47.200:8333 # AS39324 -217.76.61.78:8333 # AS39597 -217.92.55.246:8333 # AS3320 -217.113.121.169:8333 # AS8416 217.155.244.170:8333 # AS13037 -217.170.124.170:8333 # AS35401 -217.173.236.25:8333 # AS8447 -217.180.192.116:8333 # AS30600 217.180.221.162:8333 # AS30600 -218.43.123.236:8333 # AS4713 -219.77.79.128:8333 # AS4760 -223.18.222.210:8333 # AS9304 -223.167.75.165:8333 # AS4837 -[2001:1620:5566:100::62c]:8333 # AS13030 -[2001:1620:a21:0:da5e:d3ff:fee3:68a0]:8333 # AS13030 +217.230.42.55:8333 # AS3320 +219.79.200.233:8333 # AS4760 +220.92.141.84:8333 # AS4766 +222.239.166.108:8333 # AS9318 +[2001:13d8:1c01:21:215:17ff:fe63:2a7e]:8333 # AS3790 +[2001:1528:111:ffff:214::207]:8333 # AS15685 +[2001:1620:542c:210::100]:8333 # AS13030 +[2001:18b8:0:100:0:b00b:420:69]:8333 # AS29789 +[2001:19f0:0:4f89:5400:4ff:fea0:3837]:8333 # AS20473 [2001:19f0:4401:e8a:5400:4ff:fe8e:d398]:8333 # AS20473 +[2001:19f0:5000:1a80:5400:4ff:fe71:aac5]:8333 # AS20473 +[2001:19f0:5:2b12:5400:4ff:fe6e:3afe]:8333 # AS20473 +[2001:19f0:5:5b81:5e6f:69ff:fe57:94d0]:8333 # AS20473 +[2001:19f0:6801:6ec:2::1]:8333 # AS20473 +[2001:19f0:c800:2ce5:5400:4ff:fed7:663d]:8333 # AS20473 [2001:1bc0:c1::2000]:8333 # AS29686 +[2001:1c03:3911:d900:4b0c:5f2:138a:5212]:8333 # AS33915 +[2001:1c04:1308:3100::985]:8333 # AS33915 +[2001:1c04:4008:6300:8a5f:2678:114b:a660]:8333 # AS33915 [2001:4060:4419:8001::42]:8333 # AS6772 -[2001:41d0:203:8f46::]:8333 # AS16276 -[2001:41d0:30e:8e00::]:8333 # AS16276 -[2001:41d0:403:3d61::]:8333 # AS16276 -[2001:41d0:405:6e00::]:8333 # AS16276 -[2001:41d0:8:83cf:195b:b202:9271:cc5b]:8333 # AS16276 -[2001:41d0:8:ed7f::1]:8333 # AS16276 -[2001:41d0:a:69a2::1]:8333 # AS16276 -[2001:41d0:a:6b4d::1]:8333 # AS16276 -[2001:470:1b55::]:8333 # AS6939 -[2001:470:1b62::]:8333 # AS6939 -[2001:470:1f09:b14::11]:8333 # AS6939 -[2001:470:1f0a:89a::2]:8333 # AS6939 -[2001:470:1f1b:5a6:216:3eff:fe24:1162]:8333 # AS6939 -[2001:470:75e9:1::10]:8333 # AS6939 +[2001:41d0:1004:24be::]:8333 # AS16276 +[2001:41d0:203:52c2::]:8333 # AS16276 +[2001:41d0:203:ba6c::]:8333 # AS16276 +[2001:41d0:303:146e::]:8333 # AS16276 +[2001:41d0:403:c20::]:8333 # AS16276 +[2001:41d0:700:1c4d::]:8333 # AS16276 +[2001:41d0:700:70a4::]:8333 # AS16276 +[2001:41d0:c:4b8::102]:8333 # AS16276 +[2001:428:5002:600:80be:7bff:fec4:9c43]:8333 # AS209 +[2001:470:1a34:2:a804:86ff:fec2:863a]:8333 # AS6939 +[2001:470:26:472::b7c]:8333 # AS6939 +[2001:470:28:b17::2]:8333 # AS6939 +[2001:470:71:358:6083:be0b:cbaa:a97]:8333 # AS6939 +[2001:470:7:b74::2]:8333 # AS6939 [2001:470:88ff:2e::1]:8333 # AS6939 -[2001:470:8ca0:2:7646:a0ff:fe9b:e662]:8333 # AS6939 +[2001:470:8a71:2::200]:8333 # AS6939 [2001:470:a:c13::2]:8333 # AS6939 -[2001:470:c:1077::2]:8333 # AS6939 +[2001:470:da72::2:3]:8333 # AS6939 [2001:4dd0:3564:0:30b7:1d7b:6fec:4c5c]:8333 # AS8422 [2001:4dd0:3564:0:88e:b4ff:2ad0:699b]:8333 # AS8422 [2001:4dd0:3564:0:9c1c:cc31:9fe8:5505]:8333 # AS8422 @@ -536,1213 +1071,986 @@ [2001:4dd0:3564:0:fd76:c1d3:1854:5bd9]:8333 # AS8422 [2001:4dd0:3564:1::7676:8090]:8333 # AS8422 [2001:4dd0:3564:1:b977:bd71:4612:8e40]:8333 # AS8422 +[2001:4dd0:af0e:3564:0:69:90:8333]:8333 # AS8422 [2001:4dd0:af0e:3564::69:1]:8333 # AS8422 [2001:4dd0:af0e:3564::69:90]:8333 # AS8422 -[2001:560:441f:1::4]:8333 # AS18530 -[2001:5a8:40c7:f500:7a0d:d50:255e:dbac]:8333 # AS46375 +[2001:569:5079:abd2::c9]:8333 # AS852 +[2001:5a8:40c7:f500:2601:7cdc:1a2d:661c]:8333 # AS1299 +[2001:5a8:40c7:f501:e0af:1c:1468:e272]:8333 # AS1299 +[2001:5a8:40db:2000:8668:a702:c89:bdd4]:8333 # AS1299 +[2001:5a8:40db:2000:867b:8aa6:2010:879a]:8333 # AS1299 +[2001:5a8:60c0:d500::7840]:8333 # AS1299 [2001:638:a000:4140::ffff:47]:8333 # AS680 -[2001:67c:26b4:ff00::44]:8333 # AS25376 -[2001:67c:440:688:91:236:251:137]:8333 # AS57944 -[2001:67c:440:688:91:236:251:139]:8333 # AS57944 +[2001:638:a000:b101::2b3d]:8333 # AS680 +[2001:648:2800:131:4b1f:f6fc:20f7:f99f]:8333 # AS5470 +[2001:678:68c:fffb::195]:8333 # AS13259 +[2001:678:d78:22d0:5065:c1ff:fef2:3f65]:8333 # AS8298 +[2001:67c:1220:808::93e5:81f]:8333 # AS197451 +[2001:67c:1254:d1:a7b7::1]:8333 # AS4455 +[2001:67c:1254:d2:6b9c::1]:8333 # AS4455 +[2001:67c:26b4:ff00::44]:8333 # AS57672 +[2001:67c:2db8:6::36]:8333 # AS39798 [2001:7c0:2310:0:f816:3eff:fe6c:4f58]:8333 # AS34878 -[2001:861:c62:2fd0:ca7f:54ff:fece:6d9]:8333 # AS5410 +[2001:7d0:8410:df00::1488]:8333 # AS3249 +[2001:8003:d117:3500:bfc5:7e90:9da5:a8c0]:8333 # AS1221 +[2001:818:df59:5800:f8a4:ceff:fefd:d63a]:8333 # AS12353 [2001:871:23d:d5d1:5a47:caff:fe71:c8d]:8333 # AS8447 +[2001:871:25f:ef0d:5e55:dad6:fe43:1e63]:8333 # AS8447 +[2001:8b0:1301:1000::60]:8333 # AS20712 +[2001:8e0:140b::94]:8333 # AS8758 +[2001:8f8:1b69:15e5:da9e:f3ff:fe75:d10d]:8333 # AS8966 [2001:910:109d:2c03:d217:c2ff:fe07:2cd9]:8333 # AS20766 +[2001:b011:8013:3a06:e6a:7f23:65d3:f1df]:8333 # AS3462 +[2001:b030:2422::208d]:8333 # AS3462 +[2001:b07:2e9:5bb0:a2d5:2db3:8af4:4bf]:8333 # AS12874 +[2001:b07:5d26:7fb3:6ad1:350a:b65e:88dd]:8333 # AS12874 [2001:b07:6461:7811:489:d2da:e07:1af7]:8333 # AS12874 -[2001:b07:646b:8074:32e8:9243:a337:e60a]:8333 # AS12874 +[2001:b07:646d:caf:3c06:693f:73a9:e71b]:8333 # AS12874 +[2001:b07:6474:51d8:c27e:427e:fe37:6356]:8333 # AS12874 +[2001:b07:6474:51d8:f31f:fdc:1c90:67ac]:8333 # AS12874 +[2001:b07:aa7:f93a:21b8:eee1:4973:edf9]:8333 # AS12874 +[2001:bc8:1201:701:ca1f:66ff:fec9:221c]:8333 # AS12876 [2001:bc8:1201:715:ca1f:66ff:fec9:5ff0]:8333 # AS12876 [2001:bc8:1201:71a:2e59:e5ff:fe42:52f4]:8333 # AS12876 [2001:bc8:1600:0:208:a2ff:fe0c:8a2e]:8333 # AS12876 -[2003:dc:2f4a:eb00:4ecc:6aff:fe25:c9a3]:8333 # AS3320 -[2003:f6:3f31:600:4c9f:7620:8324:d4a7]:8333 # AS3320 -[2400:6180:100:d0::848:5001]:8333 # AS14061 -[2400:6180:100:d0::940:4001]:8333 # AS14061 -[2400:6180:100:d0::953:8001]:8333 # AS14061 -[2400:6180:100:d0::a02:2001]:8333 # AS14061 -[2400:6180:100:d0::a0f:9001]:8333 # AS14061 -[2400:6180:100:d0::a3d:b001]:8333 # AS14061 -[2400:6180:100:d0::a3f:1001]:8333 # AS14061 -[2400:6180:100:d0::a49:a001]:8333 # AS14061 -[2400:6180:100:d0::a56:d001]:8333 # AS14061 -[2400:6180:100:d0::a56:e001]:8333 # AS14061 -[2401:b140:1::100:210]:8333 # AS54415 +[2001:bc8:3e54:6b02::1]:8333 # AS12876 +[2001:bc8:6005:1d:208:a2ff:fe0c:6cc2]:8333 # AS12876 +[2001:bc8:610:9:46a8:42ff:fe0c:d385]:8333 # AS12876 +[2001:bc8:700:2313::1]:8333 # AS12876 +[2001:bc8:701:409:b683:51ff:fe06:75f4]:8333 # AS12876 +[2001:bc8:701:40d:ae16:2dff:fea6:e868]:8333 # AS12876 +[2001:d08:d9:7a02:9e6b:ff:fe56:e9b3]:8333 # AS9534 +[2001:df0:a280:1001::5:1]:8333 # AS139225 +[2001:e68:5425:2834:618e:9069:a977:5c66]:8333 # AS4788 +[2001:ee0:4b4f:d480:2e0:4cff:fe08:8998]:8333 # AS45899 +[2001:f40:95c:8d55:7038:f146:d2d4:118]:8333 # AS9930 +[2001:f40:95c:8d55:7270:fcff:fe05:3cd]:8333 # AS9930 +[2001:f40:987:1182:6f:a46e:ec5a:48aa]:8333 # AS9930 +[2003:d5:b703:eb00:b241:6fff:fe10:312c]:8333 # AS3320 +[2003:dc:2f4a:c200:4ecc:6aff:fe25:c9a3]:8333 # AS3320 +[2003:e6:7f42:a900:e65f:1ff:feac:cbfc]:8333 # AS3320 +[2003:ec:2f04:b100:211:32ff:fef7:beef]:8333 # AS3320 +[2003:f0:df08:ec02:aaa1:59ff:fe57:7779]:8333 # AS3320 +[2400:2411:3e05:cc00:46a:1744:4d0f:d26b]:8333 # AS17676 +[2400:2411:a3e1:4900:85c8:62de:e8cc:6875]:8333 # AS17676 +[2400:4053:1203:3f00:1:1:1:134]:8333 # AS4713 +[2400:6180:0:d1::14e:b001]:8333 # AS14061 +[2400:8901::f03c:92ff:fe3e:e1d6]:8333 # AS63949 +[2400:8901::f03c:92ff:fe4e:95f3]:8333 # AS63949 +[2400:8901::f03c:93ff:fe5a:685c]:8333 # AS63949 +[2400:8905::f03c:94ff:fecc:1466]:8333 # AS48337 +[2400:8907::f03c:94ff:fed9:9696]:8333 # AS63949 +[2401:2500:204:1149:133:125:50:180]:8333 # AS7684 [2401:b140:1::100:220]:8333 # AS54415 -[2402:e280:3d17:945:1889:d3c6:8e85:d3c4]:8333 # AS134674 -[2403:6200:8821:2fdf:3903:a2b1:9f:c897]:8333 # AS20473 +[2401:b140:3::44:110]:8333 # AS54415 +[2401:b140:3::44:120]:8333 # AS54415 +[2401:d002:2103:400:211:32ff:fe9e:7ae3]:8333 # AS38195 +[2401:d002:3902:700:d72c:5e22:4e95:389d]:8333 # AS38195 +[2401:d002:602:7800:289b:8dab:d50e:dea2]:8333 # AS38195 +[2402:a7c0:8100:a015::6f2:79a5]:8333 # AS59253 +[2402:b801:287c:800:1218:45cf:2d05:cbe4]:8333 # AS18371 +[2403:580c:c505:0:6955:67d3:6229:88e7]:8333 # AS4764 +[2403:5816:c8a3:0:2677:3ff:fe03:9422]:8333 # AS4764 +[2403:71c0:2000:b3e0::100]:8333 # AS3258 +[2403:71c0:2000:b3e0::101]:8333 # AS3258 +[2403:71c0:2000:b3e0::7693]:8333 # AS3258 +[2404:4408:6397:8201::250]:8333 # AS9790 +[2405:6582:de0:4400:8ce:2b80:2960:7b4e]:8333 # AS4685 +[2405:6582:de0:4400:f:854d:5057:4fc9]:8333 # AS4685 +[2405:aa00:2::40]:8333 # AS7712 +[2406:3003:2002:3a69:387e:3c9a:8166:106b]:8333 # AS55430 [2406:3400:216:8b00:211:32ff:feca:336b]:8333 # AS10143 -[2406:da14:335:b600:eb14:5fd:2072:3653]:8333 # AS16509 -[2406:da1c:50b:cd00:3cae:1728:ecfc:4334]:8333 # AS16509 -[2406:da1c:50b:cd03:36d6:13fa:eba8:6543]:8333 # AS16509 -[2406:da1e:a4e:8a03:d90a:fbb0:23d3:ccb4]:8333 # AS16509 +[2406:8c00:0:3422:133:18:228:108]:8333 # AS24282 +[2406:da12:ce1:f000:afcd:2e3a:11f6:67c0]:8333 # AS16509 +[2406:da12:ce1:f001:2f6e:891:55f0:55e1]:8333 # AS16509 +[2406:da12:ce1:f001:8974:8c19:bae2:5213]:8333 # AS16509 +[2406:da12:ce1:f001:a791:ac49:22a4:fd2]:8333 # AS16509 +[2406:da1a:5b2:ea00:f17a:1319:baed:1582]:8333 # AS16509 +[2406:da1a:5b2:ea01:58c:5fb:ae7c:484c]:8333 # AS16509 [2407:3640:2107:1278::1]:8333 # AS141995 -[2407:7000:9f71:2d00:1c5a:5292:5108:c734]:8333 # AS9500 -[2408:8207:2655:fae0::10b]:8333 # AS4837 -[2408:8207:5456:d8d0::5c6]:8333 # AS4837 -[2409:250:60a0:2600:a971:1cdd:3d5b:654d]:8333 # AS55392 +[2407:c800:4f12:5e7:95e3:4bf5:b37:86f7]:8333 # AS9365 +[2408:8207:5455:8d00::704]:8333 # AS4808 +[2409:8a28:ec1:6840:f7a3:88c8:cacc:fe0a]:8333 # AS56041 +[2409:8a7c:1e42:2a50:45d9:11d8:b04:cbd7]:8333 # AS9808 [240d:1a:4b1:e700:19:d9ef:7f3:8e75]:8333 # AS2527 -[2600:1700:3948:82f:ce04:d382:5226:4cac]:8333 # AS7018 -[2600:1f16:a08:b900:4bfe:2f81:ae31:5f5]:8333 # AS16509 +[240e:38a:3e3a:cf00:a771:2e91:51a7:2fb4]:8333 # AS4134 +[2600:1700:3101:b00f:2c96:27a0:452c:f186]:8333 # AS7018 +[2600:1700:38d5:140f:f64d:30ff:fe63:504e]:8333 # AS7018 +[2600:1700:488:10::421]:8333 # AS7018 +[2600:1700:539e:b00f:5054:ff:fe1b:2913]:8333 # AS7018 +[2600:1700:5453:69e::109]:8333 # AS7018 +[2600:1700:5af3:2c10:46a8:42ff:fe08:5835]:8333 # AS7018 +[2600:1700:6b0:d200::ff]:8333 # AS7018 +[2600:1700:944c:e00f:2a27:f664:1801:599f]:8333 # AS7018 +[2600:1700:ec7b:5730::46]:8333 # AS7018 +[2600:1700:ec7b:5730:f2b6:1eff:fe70:7583]:8333 # AS7018 +[2600:1900:4000:4cc4:0:13::]:8333 # AS396982 +[2600:1900:4020:65f:0:1::]:8333 # AS396982 +[2600:1900:4030:a25e::]:8333 # AS396982 +[2600:1900:40b0:3af2:0:5::]:8333 # AS396982 +[2600:1900:40b0:3af2::]:8333 # AS396982 +[2600:1900:40c0:2210::]:8333 # AS396982 +[2600:1900:40e0:41fa:0:4::]:8333 # AS396982 +[2600:1900:41a0:af83::]:8333 # AS396982 +[2600:1900:5400:6e4:0:3::]:8333 # AS396982 +[2600:1901:8180:5c1::]:8333 # AS396982 +[2600:1f14:40e:e300:cea2:19ef:fa3a:e125]:8333 # AS16509 +[2600:1f16:a08:b900:2321:e069:cde4:67fb]:8333 # AS16509 +[2600:1f18:64d9:1603:4436:871e:2bfe:7403]:8333 # AS14618 +[2600:1f18:66fc:d700:9b71:f45:f3c9:c43b]:8333 # AS14618 +[2600:1f18:66fc:d701:d68d:ea70:77a0:4072]:8333 # AS14618 +[2600:1f18:719a:e301:773d:1375:24fb:bf24]:8333 # AS14618 +[2600:1f18:719a:e302:2758:8042:929f:a384]:8333 # AS14618 +[2600:1f18:719a:e302:4c90:e1e6:2a59:82c4]:8333 # AS14618 +[2600:1f18:719a:e302:e6c0:8878:401c:27c2]:8333 # AS14618 +[2600:1f18:719a:e302:ef0c:40ab:f8f:6d6c]:8333 # AS14618 +[2600:1f18:719a:e302:fa9e:86ad:e463:ae17]:8333 # AS14618 [2600:1f1c:2d3:2401:6989:b1fd:d2a6:fbc8]:8333 # AS16509 -[2600:1f1e:2fe:3601:63a8:ebf6:83e4:1932]:8333 # AS16509 [2600:2104:1003:c5ab:dc5e:90ff:fe18:1d08]:8333 # AS11404 -[2600:3c00::f03c:91ff:fe4b:c52]:8333 # AS63949 -[2600:3c00:e002:2e32::1:c8]:8333 # AS63949 -[2600:3c02::f03c:94ff:fecc:c99c]:8333 # AS63949 -[2600:6c4e:a00:cd0:428d:5cff:fe58:4884]:8333 # AS20115 +[2600:3c00::f03c:92ff:fe92:2745]:8333 # AS63949 +[2600:3c00::f03c:94ff:feb7:4dd7]:8333 # AS63949 +[2600:3c00::f03c:94ff:fed1:1d3d]:8333 # AS63949 +[2600:3c01::f03c:93ff:fee6:2146]:8333 # AS63949 +[2600:3c02::f03c:92ff:fe5d:9fb]:8333 # AS63949 +[2600:3c02::f03c:94ff:fe12:8938]:8333 # AS63949 [2600:6c54:7100:1ad1:c92e:36d:651:bd18]:8333 # AS20115 -[2601:184:300:156c:ba4c:30:9da:6c06]:8333 # AS7922 -[2601:185:8302:12f0:1ab2:2840:9de4:1550]:8333 # AS7922 -[2603:3003:11b:e100:20c:29ff:fe38:bbc0]:8333 # AS7922 -[2603:3004:6a1:3800:851f:584d:7aba:affb]:8333 # AS7922 -[2603:3024:18ee:8000:20e:c4ff:fed1:ef15]:8333 # AS7922 -[2603:8080:1f07:6fdd:7de2:d969:78c9:b7ea]:8333 # AS7843 +[2600:6c67:2100:670:b179:be4c:8cca:e8f0]:8333 # AS33588 +[2600:6c67:8a3f:e191:4261:86ff:fe4f:aac]:8333 # AS33588 +[2600:70ff:eaad:beef::2]:8333 # AS6939 +[2600:8801:2f80:b2::141c]:8333 # AS22773 +[2600:8806:2300:460:a0e6:7e10:c3a8:bb47]:8333 # AS22773 +[2601:152:497f:2a38::7b]:8333 # AS33657 +[2601:185:8302:12f0:1ab2:2840:9de4:1550]:8333 # AS7015 +[2601:18c:9002:3de5:219:d1ff:fe75:dc2f]:8333 # AS7015 +[2601:19c:417e:3a11:20e7:b3ff:fecf:a99]:8333 # AS7015 +[2601:243:820:5824:4216:8de:e04a:fb54]:8333 # AS33491 +[2601:280:5c00:43d:4aba:4eff:fef8:6e5d]:8333 # AS33652 +[2601:603:5300:83b7:0:ff:fe00:4209]:8333 # AS33650 +[2602:fec3:0:1::69]:8333 # AS62563 +[2602:fec3:2:5::5:73]:8333 # AS62563 +[2602:ffb6:4:4d3d:f816:3eff:fec6:c15]:8333 # AS174 +[2602:ffb6:4:739e:f816:3eff:fe00:c2b3]:8333 # AS174 +[2602:ffb6:4:7b8e:f816:3eff:fe9d:9dc2]:8333 # AS174 +[2602:ffc5:200:1e01:241d:e589:9650:c773]:8333 # AS20473 +[2603:3003:11b:e100:20c:29ff:fe38:bbc0]:8333 # AS33657 +[2603:3003:11b:e100::f202]:8333 # AS33657 +[2603:3004:717:5800:485b:39ff:feab:1d54]:8333 # AS33490 +[2603:3005:1503:700::8af2]:8333 # AS7015 +[2603:3007:701:8000:b7d9:9e1e:8e0d:52fa]:8333 # AS7016 +[2603:300a:912:627a:be24:11ff:fe7b:39c3]:8333 # AS33491 +[2603:3015:e21:6800:15b3:d692:a536:12ff]:8333 # AS33668 +[2603:3024:1c07:e00::8c2d]:8333 # AS33651 +[2603:3024:2005:8000::f41b]:8333 # AS33651 +[2603:6011:af41:7214::5]:8333 # AS10796 +[2603:6080:9003:2fbc:60b1:6a4e:e364:c85d]:8333 # AS11426 +[2603:8001:3300:7d75::c48]:8333 # AS20001 +[2603:8080:1f07:6fdd:7de2:d969:78c9:b7ea]:8333 # AS11427 +[2603:8081:6c00:77:215:5dff:fe02:1555]:8333 # AS11427 +[2603:80a0:700:1886::39]:8333 # AS11427 [2604:4080:1036:80b1:50e1:43ff:fe0e:9df5]:8333 # AS11404 +[2604:4500:6:285::18]:8333 # AS29802 +[2604:86c0:3001:5::12:73]:8333 # AS63023 +[2604:a00:3:2098:216:3eff:fe28:c447]:8333 # AS19318 +[2604:a00:50:39:c514:becd:bece:ad3a]:8333 # AS19318 +[2604:a880:400:d0::1c96:e001]:8333 # AS14061 +[2604:a880:400:d0::1d46:c001]:8333 # AS14061 +[2604:a880:400:d0::1def:8001]:8333 # AS14061 +[2604:a880:400:d0::1dfe:a001]:8333 # AS14061 +[2604:a880:400:d1::849:6001]:8333 # AS14061 +[2604:a880:4:1d0::31:e000]:8333 # AS14061 +[2604:a880:4:1d0::c5:6000]:8333 # AS14061 +[2605:1080:0:f00::70]:8333 # AS23367 +[2605:21c0:2000:11:204:194:220:40]:8333 # AS20055 +[2605:59c8:1800:2596:c26c:e780:26fd:fcf8]:8333 # AS14593 +[2605:59c8:2a99:9d00:5377:7333:efde:d32]:8333 # AS14593 +[2605:59c8:61f:3900:2efd:a1ff:fedc:f8d4]:8333 # AS14593 [2605:6400:30:f220::]:8333 # AS53667 -[2605:6400:30:fd6f::4]:8333 # AS53667 -[2605:c000:2a0a:1::102]:8333 # AS7393 +[2605:6440:3001:2f:3eec:efff:fe91:f840]:8333 # AS396356 +[2605:6440:3001:2f::2]:8333 # AS396356 +[2605:6440:3001:49:7ec2:55ff:fea8:31cc]:8333 # AS396356 +[2605:6440:3001:49::2]:8333 # AS396356 +[2605:6f80:0:7:fc1b:ccff:fe8a:d822]:8333 # AS36114 +[2605:ae00:203::203]:8333 # AS7819 [2606:6d00:100:5102:3d2:f06a:c2e8:a54]:8333 # AS1403 -[2607:5300:60:2e54::1]:8333 # AS16276 -[2607:5300:61:854::1]:8333 # AS16276 +[2607:5300:203:46ea::]:8333 # AS16276 +[2607:5300:60:314c::1]:8333 # AS16276 [2607:9280:b:73b:250:56ff:fe14:25b5]:8333 # AS395502 [2607:9280:b:73b:250:56ff:fe21:9c2f]:8333 # AS395502 [2607:9280:b:73b:250:56ff:fe21:bf32]:8333 # AS395502 [2607:9280:b:73b:250:56ff:fe33:4d1b]:8333 # AS395502 [2607:9280:b:73b:250:56ff:fe3d:401]:8333 # AS395502 -[2620:a6:2000:1:1:0:d:3015]:8333 # AS27566 -[2620:a6:2000:1:2:0:3:266c]:8333 # AS27566 -[2620:a6:2000:1:2:0:9:930b]:8333 # AS27566 -[2620:a6:2000:1:2:0:b:3011]:8333 # AS27566 -[2800:150:11d:2426:62b:b164:704a:6962]:8333 # AS22047 -[2800:300:8251:b50::d]:8333 # AS27651 -[2800:300:8251:b50:e92:64f5:22af:c31e]:8333 # AS27651 -[2800:40:15:6ad:48e8:2200:a882:e08e]:8333 # AS16814 -[2803:5180:4100:4000::2]:8333 # AS52468 -[2803:9800:9447:84bb:cab8:d2f5:388c:9a57]:8333 # AS19037 -[2804:14d:7e33:83b0:6e41:1ccc:cf20:aff9]:8333 # AS4230 +[2607:f2c0:e045:f2e0:fe4c:fbb:6c99:1220]:8333 # AS5645 +[2607:f2c0:f00e:300::54]:8333 # AS5645 +[2607:f2f8:ad40:ea11::1]:8333 # AS25795 +[2607:fdc0:5:9::2ca]:8333 # AS20326 +[2607:fea8:601e:7d01:be24:11ff:fe89:27f3]:8333 # AS812 +[2620:11c:5001:1118:d267:e5ff:fee9:e673]:8333 # AS13331 +[2620:11c:5001:2199:d267:e5ff:fee9:e673]:8333 # AS13331 +[2620:6:2003:105:67c:16ff:fe51:58bf]:8333 # AS395460 +[2620:6e:a000:1:42:42:42:42]:8333 # AS397444 +[2620:a6:2000:1:1:0:9:742a]:8333 # AS27566 +[2620:a6:2000:1:1:0:d:7f1d]:8333 # AS27566 +[2620:a6:2000:1:2:0:6:49c8]:8333 # AS27566 +[2620:a6:2000:1:2:0:b:388a]:8333 # AS27566 +[2620:ca:a000:beef::1]:8333 # AS401199 +[2620:ca:a000:beef::10]:8333 # AS401199 +[2620:ca:a000:beef::2]:8333 # AS401199 +[2620:ca:a000:beef::3]:8333 # AS401199 +[2620:ca:a000:beef::6]:8333 # AS401199 +[2800:150:11d:1093:c9e3:1ef4:bc4:250d]:8333 # AS22047 +[2800:40:17:24f:4d95:e130:7f97:90f2]:8333 # AS16814 +[2800:40:18:7d1:a236:bcff:fe58:b6ec]:8333 # AS16814 +[2800:40:74:4b8b:f673:db63:6f6f:2310]:8333 # AS16814 +[2803:5180:4100:4000::2]:8333 # AS263762 +[2803:9800:9447:84bb:b87f:1df2:ff01:1c28]:8333 # AS19037 +[2803:9800:a007:8391:1fd7:c263:a55b:b9fb]:8333 # AS19037 +[2804:14c:65d7:8ea5:6060:2102:6ba6:5614]:8333 # AS28573 +[2804:14d:7e33:83b0:6e41:1ccc:cf20:aff9]:8333 # AS28573 +[2804:229c:8200:18d6:14a:d8c8:b4dd:3f25]:8333 # AS264111 [2804:431:e038:cd01:aaa1:59ff:fe0d:44b8]:8333 # AS27699 -[2804:d57:450d:f00:a422:9828:b00e:91e9]:8333 # AS8167 -[2806:2f0:5020:d287:4dcd:6204:909b:4125]:8333 # AS17072 +[2804:d41:e028:5900:aea:4236:2d76:1eb9]:8333 # AS7738 +[2804:d45:cb22:ef00:f89c:d038:2a36:a3fa]:8333 # AS7738 +[2804:d57:4b3d:7d00:752d:1d78:6b32:f71c]:8333 # AS8167 +[2804:d57:5949:1800:2a0:98ff:fe79:339b]:8333 # AS8167 +[2804:fec:d2d8:6100:fa63:2ecd:48a0:2f34]:8333 # AS262493 +[2806:103e:1b:4835:a787:2ea5:9025:aaa7]:8333 # AS8151 +[2806:267:148a:1d10:dc4b:3694:423b:b6b4]:8333 # AS13999 +[2806:2f0:80e1:e17b:3529:8aa:90c:509a]:8333 # AS17072 +[2806:2f0:a481:c585:603:478e:57f9:409e]:8333 # AS17072 +[2a00:1169:114:dc00::]:8333 # AS29066 +[2a00:1190:c013::be:1337]:8333 # AS16302 +[2a00:11c0:60:294:c48f:beff:fe15:a97f]:8333 # AS197540 [2a00:1298:8001::6542]:8333 # AS5578 [2a00:12e0:101:99:20c:29ff:fe29:d03f]:8333 # AS6798 [2a00:1398:4:2a03:3eec:efff:fe05:d93e]:8333 # AS34878 [2a00:1398:4:2a03::bc03]:8333 # AS34878 +[2a00:13a0:3015:1:85:14:79:26]:8333 # AS31242 [2a00:1768:2001:27::ef6a]:8333 # AS43350 +[2a00:1a08:ffff:5::11]:8333 # AS25534 [2a00:1f40:5001:108:5d17:7703:b0f5:4133]:8333 # AS42864 +[2a00:1f40:5001:386:dead:beef:b1ac:c0fe]:8333 # AS42864 [2a00:23c5:fe80:7301:d6ae:52ff:fed5:56a5]:8333 # AS2856 [2a00:23c6:5c8a:5c00:c05a:4dff:fe65:9d69]:8333 # AS2856 -[2a00:6020:4503:3700:5054:ff:fe90:640e]:8333 # AS60294 -[2a00:6020:b489:2000:5054:ff:fefc:5ed8]:8333 # AS60294 -[2a00:8a60:e012:a00::21]:8333 # AS680 -[2a00:bbe0:0:221f::246]:8333 # AS47605 -[2a00:d520:9:9300:420b:544e:8019:6d3a]:8333 # AS15600 -[2a00:fd40:c:c::c]:8333 # AS3269 +[2a00:4d80::1]:8333 # AS43150 +[2a00:5980:93::135]:8333 # AS197869 +[2a00:6020:4914:5700:db31:ca50:797:c468]:8333 # AS60294 +[2a00:6020:509e:a400:211:32ff:fe5c:369c]:8333 # AS60294 +[2a00:6020:b406:e00:79e:9ad6:9181:ebb8]:8333 # AS60294 +[2a00:6020:b489:2000:42:c0ff:fea8:b209]:8333 # AS60294 +[2a00:7c80:0:4e::2]:8333 # AS49981 +[2a00:7c80:0:4e:b7c0::2001]:8333 # AS49981 +[2a00:8a60:e012:a00::9001]:8333 # AS47610 +[2a00:a040:199:84fa:1ac0:4dff:fe41:3e93]:8333 # AS12849 +[2a00:bba0:1204:3700:21e:6ff:fe4a:5378]:8333 # AS207375 +[2a00:bbe0:0:221f::246]:8333 # AS60414 +[2a00:d4e0:ff:fc02:9e6b:ff:fe17:6115]:8333 # AS15600 +[2a00:d880:5:c2::d329]:8333 # AS198203 +[2a00:ee2:4d00:600::1]:8333 # AS5603 +[2a00:ee2:4d00:6b0::1000:1]:8333 # AS5603 +[2a01:238:425f:4600:bbb8:16d6:e907:cb6f]:8333 # AS6724 +[2a01:239:265:ad00::1]:8333 # AS8560 +[2a01:261:218:3f00:8d0f:2105:c657:4ae7]:8333 # AS34779 +[2a01:4b00:807c:3100:a36:c9ff:fe7e:de5f]:8333 # AS56478 +[2a01:4b00:b906:f100:d812:4f64:a931:19b7]:8333 # AS56478 +[2a01:4b00:b906:f100:dea6:32ff:fed5:f142]:8333 # AS56478 +[2a01:4b00:bf1b:7200:d826:7d6f:b13:276c]:8333 # AS56478 +[2a01:4f8:171:16af::2]:8333 # AS24940 [2a01:4f8:171:1f16::2]:8333 # AS24940 -[2a01:4f8:200:7222::2]:8333 # AS24940 [2a01:4f8:202:4205::2]:8333 # AS24940 -[2a01:4f8:242:2016::2]:8333 # AS24940 -[2a01:4f8:261:420c::2]:8333 # AS24940 -[2a01:4f8:272:4cd9::2]:8333 # AS24940 -[2a01:4f9:1a:a966::2]:8333 # AS24940 -[2a01:4f9:1a:af0d::2]:8333 # AS24940 -[2a01:4f9:2b:29a::2]:8333 # AS24940 -[2a01:4f9:5a:44a5::2]:8333 # AS24940 -[2a01:7a7:2:2804:ae1f:6bff:fe9d:6c94]:8333 # AS20773 -[2a01:8740:1:753::e5cb]:8333 # AS57344 -[2a01:8740:1:ff2e::9428]:8333 # AS57344 -[2a01:8740:1:ffc5::8c6a]:8333 # AS57344 -[2a01:cb00:790:f500:110b:b446:2260:7d2c]:8333 # AS3215 -[2a01:cb10:336:cb00:61ac:d15d:4ac0:2cbd]:8333 # AS3215 -[2a01:cb10:336:cb00:d237:45ff:fec5:2cd0]:8333 # AS3215 -[2a01:cb15:804c:8000:21e:6ff:fe51:2c32]:8333 # AS3215 -[2a01:e0a:185:55f0:a0ba:9eaf:9853:92b7]:8333 # AS12322 -[2a01:e0a:301:7010:b87d:e14b:cea9:b998]:8333 # AS12322 +[2a01:4f8:242:4246::2]:8333 # AS24940 +[2a01:4f8:252:1ceb::2]:8333 # AS24940 +[2a01:4f8:271:5ca8::2]:8333 # AS24940 +[2a01:4f9:1a:aad4::2]:8333 # AS24940 +[2a01:4f9:4a:515b::2]:8333 # AS24940 +[2a01:4f9:5a:16cb:876a:bce7:b3c8:118a]:8333 # AS24940 +[2a01:4f9:5a:25c2::2]:8333 # AS24940 +[2a01:4ff:1f0:8517::1]:8333 # AS212317 +[2a01:4ff:1f0:91ad::1]:8333 # AS212317 +[2a01:4ff:1f0:ec0d::1]:8333 # AS212317 +[2a01:4ff:f0:cc2a::1]:8333 # AS213230 +[2a01:4ff:f0:e4e9::1]:8333 # AS213230 +[2a01:5a8:303:13ac::1]:8333 # AS8866 +[2a01:5a8:308:4333:4074:6aff:fe9c:f5d2]:8333 # AS8866 +[2a01:7a7:2:2804:ae1f:6bff:fe9d:6c94]:8333 # AS29066 +[2a01:7c8:aaac:89:5054:ff:feb7:f5cb]:8333 # AS20857 +[2a01:7c8:aac2:180:5054:ff:fe56:8d10]:8333 # AS20857 +[2a01:8740:1:753::e5cb]:8333 # AS203380 +[2a01:8740:1:ff2e::9428]:8333 # AS203380 +[2a01:8740:1:ffc5::8c6a]:8333 # AS203380 +[2a01:cb00:139e:a00:142d:fec1:d0df:da18]:8333 # AS3215 +[2a01:cb00:1428:ea00:8a4c:1b72:f959:ca4]:8333 # AS3215 +[2a01:cb10:249:7300:b:c:b:c]:8333 # AS3215 +[2a01:e0a:1c1:a3e0:443b:bcab:7778:b03b]:8333 # AS12322 +[2a01:e0a:252:6bd0::2]:8333 # AS12322 [2a01:e0a:3b3:1420:7ca0:3a9a:5cc3:b644]:8333 # AS12322 -[2a01:e0a:5:9390:bf35:4d41:8a2a:570]:8333 # AS12322 +[2a01:e0a:57b:a0:7039:12e3:6547:2849]:8333 # AS12322 +[2a01:e0a:83d:dd30:246a:4af7:53f4:8d65]:8333 # AS12322 [2a01:e0a:9e9:c240:8e3a:af64:4f0:8f79]:8333 # AS12322 -[2a01:e0a:b0f:37e0:a13f:e65:ac42:8e36]:8333 # AS12322 -[2a01:e0a:b5:7f50:c257:a55b:4846:97e1]:8333 # AS12322 -[2a01:e0a:bf6:8d70:20c:29ff:fe30:4fd2]:8333 # AS12322 -[2a01:e11:100c:70:39f3:e3c9:832f:37a]:8333 # AS12322 -[2a01:e34:ec1d:7100:8aae:ddff:fe02:4159]:8333 # AS12322 -[2a02:1210:7c92:5100:211:32ff:feae:152d]:8333 # AS3303 -[2a02:1210:86bf:f100:a9ac:d041:1f8e:6925]:8333 # AS3303 -[2a02:22a0:bbb3:dc10:50e1:57ff:fe70:9492]:8333 # AS1136 -[2a02:247a:215:3e00:1::1]:8333 # AS8560 -[2a02:2c60:f103:7c0:1a31:bfff:fecc:5d91]:8333 # AS9063 +[2a01:e0a:b7:7db0:24e:1ff:feaa:e183]:8333 # AS12322 +[2a01:e0a:db3:66a0:92e1:4c4:8ce9:2b5d]:8333 # AS12322 +[2a01:e0a:df:b9a0:b62e:99ff:fece:1395]:8333 # AS12322 +[2a01:e0a:e6e:6bb0:2e0:4cff:fe68:232]:8333 # AS12322 +[2a01:e11:100c:70:39f3:e3c9:832f:37a]:8333 # AS29447 +[2a02:1210:1c04:d900:86e5:2135:4f88:82e]:8333 # AS3303 +[2a02:1210:200a:3c00:b559:6c65:10cb:3765]:8333 # AS3303 +[2a02:1210:3c3a:5600:61e6:a811:ef0b:f9c2]:8333 # AS3303 +[2a02:1210:4857:ed00:4c86:3d1c:db1a:460d]:8333 # AS3303 +[2a02:1210:4aba:e800:21ec:346:a29f:90be]:8333 # AS3303 +[2a02:1210:60e0:800:8d6e:134d:a0ca:ef24]:8333 # AS3303 +[2a02:1210:7823:de00:211:32ff:feae:152d]:8333 # AS3303 +[2a02:1210:84ea:f600:503e:6f19:c2c1:9ca6]:8333 # AS3303 +[2a02:13b8:f000:101::a]:8333 # AS15614 +[2a02:168:2000:97::26]:8333 # AS13030 +[2a02:168:420b:7::7]:8333 # AS13030 +[2a02:168:420b:a::20]:8333 # AS13030 +[2a02:168:62a7::b1c]:8333 # AS13030 +[2a02:168:675e:0:e65f:1ff:fe09:3591]:8333 # AS13030 +[2a02:168:b5cf:4::]:8333 # AS13030 +[2a02:1748:f7df:95b1:96c6:91ff:fe1d:e0b6]:8333 # AS51184 +[2a02:21b4:2089:9100:106b:c6b:c328:be4e]:8333 # AS57370 +[2a02:21b4:c820:c300:3126:c960:f356:aab5]:8333 # AS57370 +[2a02:22a0:bbb3:dc10:50e1:57ff:fe70:9492]:8333 # AS28685 +[2a02:247a:215:3e00::1]:8333 # AS8560 +[2a02:247a:22d:c000:1::1]:8333 # AS8560 +[2a02:247a:243:7b00::1]:8333 # AS8560 +[2a02:2780:9000:70::7]:8333 # AS35434 +[2a02:2780:9000:70::f]:8333 # AS35434 +[2a02:29b8:dc01:3750::c4d]:8333 # AS51852 +[2a02:2f05:6307:100:fd:ac4b:7f1a:1d95]:8333 # AS8708 [2a02:3102:4d5c:f000:dea6:32ff:febb:b9cb]:8333 # AS6805 -[2a02:3102:bc00:10e9:ca5:9dff:fea9:1cbb]:8333 # AS6805 +[2a02:3102:c324:1049:ca5:9dff:fea9:1cbb]:8333 # AS6805 [2a02:390:9000:0:aaa1:59ff:fe43:b57b]:8333 # AS12496 +[2a02:6d40:3055:b201:dea6:32ff:fe44:4b25]:8333 # AS42652 +[2a02:6ea0:d14a::a921:e257]:8333 # AS60068 [2a02:768:f92b:db46:5e46:772b:71d:29b7]:8333 # AS44489 -[2a02:8070:f181:f600:bcb:2d1:d790:78ff]:8333 # AS51185 -[2a02:8071:6380:c500:7285:c2ff:feb5:a39c]:8333 # AS3209 -[2a02:8084:2021:73f3::66e6]:8333 # AS6830 +[2a02:7a01::91:228:45:130]:8333 # AS197895 +[2a02:7b40:50d1:e77e::1]:8333 # AS62282 +[2a02:7b40:5928:89::1]:8333 # AS62282 +[2a02:7b40:b0df:8f88::1]:8333 # AS62282 +[2a02:7b40:b945:3599::1]:8333 # AS62282 +[2a02:7b40:c3b5:f595::1]:8333 # AS62282 +[2a02:7b40:d418:69b4::1]:8333 # AS62282 +[2a02:7b40:d418:6dfe::1]:8333 # AS62282 +[2a02:8070:f181:f600:bcb:2d1:d790:78ff]:8333 # AS3209 +[2a02:8071:6380:c500:d250:99ff:fe14:afb2]:8333 # AS3209 +[2a02:8084:2021:7393::66e6]:8333 # AS6830 +[2a02:8108:28c0:5d60:da3a:ddff:fe45:4cb5]:8333 # AS3209 +[2a02:8108:8ac0:5db:d250:99ff:fe9e:792a]:8333 # AS3209 +[2a02:810b:181f:fa8e:1cc7:c528:4a59:6334]:8333 # AS3209 [2a02:8308:8188:5100:6d8b:4531:4331:eee2]:8333 # AS16019 [2a02:8388:e302:7980:6f85:a0b3:4b4d:8b0f]:8333 # AS8412 [2a02:8388:e5c3:4a80:201:2eff:fe82:b3cc]:8333 # AS8412 -[2a02:a31a:e03d:9400:3f18:2729:c86:d754]:8333 # AS6830 +[2a02:908:c200:6d00:caad:5e32:35e7:3157]:8333 # AS3209 +[2a02:a457:1a1b:ff04::1033]:8333 # AS1136 [2a02:a45a:94cd:f00d::1]:8333 # AS1136 [2a02:a465:80f4:1:f369:4ef5:aa12:7566]:8333 # AS1136 +[2a02:a466:4d4f:1:8471:fe5d:cff:d524]:8333 # AS1136 +[2a02:a468:61f8:1::2]:8333 # AS1136 +[2a02:a469:2d51:1:921b:eff:fe8c:7975]:8333 # AS1136 +[2a02:a469:3eda:1:7e83:34ff:feb6:13f3]:8333 # AS1136 [2a02:ab88:20b:ce00:223:24ff:fe56:6202]:8333 # AS21334 -[2a02:c206:2016:2394::1]:8333 # AS51167 -[2a02:c206:2162:5603::1]:8333 # AS51167 -[2a02:c206:2162:5605::1]:8333 # AS51167 -[2a02:c206:2162:5606::1]:8333 # AS51167 -[2a02:c206:2162:5856::1]:8333 # AS51167 -[2a02:c206:2162:7348::1]:8333 # AS51167 -[2a02:c206:2162:7352::1]:8333 # AS51167 -[2a02:c206:2162:8026::1]:8333 # AS51167 -[2a02:c207:2034:7358::1]:8333 # AS51167 -[2a02:c207:3006:3185::1]:8333 # AS51167 +[2a02:ab8:201:403::126]:8333 # AS48943 +[2a02:ab8:201:403:b87a:46a1:aece:21ed]:8333 # AS48943 +[2a02:af8:fab0:808:85:234:145:132]:8333 # AS29550 +[2a02:b48:207:2:8333::4]:8333 # AS39572 +[2a02:b48:207:2:8333::5]:8333 # AS39572 +[2a02:c206:2131:403::1]:8333 # AS51167 +[2a02:c206:2161:3107::1]:8333 # AS51167 +[2a02:c206:2170:3718::1]:8333 # AS51167 +[2a02:c206:2172:2852::1]:8333 # AS51167 +[2a02:c206:2179:6690::1]:8333 # AS51167 +[2a02:c206:2181:6405::1]:8333 # AS51167 +[2a02:c206:2188:9353::1]:8333 # AS51167 +[2a02:c206:3013:3626::1]:8333 # AS51167 +[2a02:c207:2043:5542::1]:8333 # AS51167 +[2a02:c207:3002:7468::1]:8333 # AS51167 +[2a02:cb43:4000::178]:8333 # AS20546 +[2a02:e5e:1:10::27]:8333 # AS25057 +[2a02:e98:20:1504::1]:8333 # AS24641 +[2a03:4000:28:68:7411:53ff:fe4c:21d]:8333 # AS197540 +[2a03:4000:2:1e3:c8b7:eeff:feb0:d26c]:8333 # AS197540 +[2a03:4000:5d:bd4:a8bf:78ff:fe98:7ea4]:8333 # AS197540 +[2a03:4000:5d:ea7:944c:6bff:fead:b1f1]:8333 # AS197540 +[2a03:4000:5f:cfc:14c3:eff:feb5:1c1a]:8333 # AS197540 +[2a03:4000:63:dc7:d418:2dff:fef3:94d9]:8333 # AS197540 +[2a03:4000:9:7d9:c88f:1dff:fe4e:44d]:8333 # AS197540 +[2a03:6000:870:0:46:23:87:218]:8333 # AS60131 +[2a03:b0c0:1:e0::368:d001]:8333 # AS14061 +[2a03:b0c0:1:e0::6aa:7001]:8333 # AS14061 [2a03:cfc0:8000:2a::9532:6507]:8333 # AS201814 -[2a03:cfc0:8000:2a::9532:6510]:8333 # AS201814 -[2a03:cfc0:8000:2a::9532:6511]:8333 # AS201814 +[2a03:cfc0:8000:2a::9532:650f]:8333 # AS201814 +[2a03:cfc0:8000:2a::9532:6514]:8333 # AS201814 [2a03:cfc0:8000:2a::9532:6516]:8333 # AS201814 -[2a03:cfc0:8000:2a::9532:651d]:8333 # AS201814 +[2a03:cfc0:8000:2a::9532:651b]:8333 # AS201814 +[2a03:cfc0:8000:2a::9532:651c]:8333 # AS201814 [2a03:cfc0:8000:2a::9532:6520]:8333 # AS201814 [2a03:cfc0:8000:2a::9532:6522]:8333 # AS201814 [2a03:cfc0:8000:2a::9532:6523]:8333 # AS201814 -[2a03:cfc0:8000:2a::9532:659a]:8333 # AS201814 -[2a03:cfc0:8000:2a::9532:659d]:8333 # AS201814 +[2a03:cfc0:8000:2a::9532:659c]:8333 # AS201814 [2a03:ec0:0:928::701:701]:8333 # AS199669 -[2a04:ee41:86:50b6:fa75:a4ff:fe3c:243f]:8333 # AS15796 -[2a05:d012:42a:5703:4dc5:8116:787c:e016]:8333 # AS16509 -[2a05:d014:a55:4001:f6ab:dd5e:4039:b46c]:8333 # AS16509 -[2a05:d018:a75:6c00:c05b:4d0a:3658:1030]:8333 # AS16509 -[2a07:9a07:3::2:1]:8333 # AS202605 -[2a07:d884::130e]:8333 # AS6762 -[2a0a:ef40:e44:9b01:2746:ca1e:6788:351c]:8333 # AS1273 +[2a04:3543:1000:2310:e878:79ff:fe3c:1729]:8333 # AS202053 +[2a04:52c0:102:2219::1]:8333 # AS60404 +[2a04:52c0:102:49af::1]:8333 # AS60404 +[2a04:52c0:103:c455::1]:8333 # AS60404 +[2a04:52c0:104:160c::1]:8333 # AS60404 +[2a05:3580:d101:3700::]:8333 # AS35807 +[2a05:4cc0:0:332::2]:8333 # AS8772 +[2a05:6d40:b94e:d100:230:48ff:fedf:1432]:8333 # AS202128 +[2a05:d01e:1b1:6c03:5369:fd23:e62f:a257]:8333 # AS16509 +[2a05:f480:2c00:100c:5400:4ff:fed7:dead]:8333 # AS20473 +[2a05:f480:3000:2b4e:5400:4ff:fed7:4206]:8333 # AS20473 +[2a06:dd00:10:0:225:90ff:fe33:56e8]:8333 # AS56694 +[2a06:dd01::36:0:0:1]:8333 # AS42474 +[2a06:e881:3408:2::2]:8333 # AS205165 +[2a07:7200:ffff:0:3016:d5ff:fe5e:1114]:8333 # AS34197 +[2a07:7200:ffff:0:60d1:eff:fe09:3886]:8333 # AS34197 +[2a07:7200:ffff:0:b0a5:23ff:fe34:d292]:8333 # AS34197 +[2a07:7200:ffff:0:c43e:80ff:fe3c:e0cd]:8333 # AS34197 +[2a07:7200:ffff:0:f4d3:aff:febe:ad99]:8333 # AS34197 +[2a07:b242:1000:1300:f250:8f0a:cdba:4d76]:8333 # AS202618 +[2a07:d884::127e]:8333 # AS23959 +[2a09:2681:1001::23]:8333 # AS61282 +[2a0a:31c0:100:0:888f:90ff:fe2c:761b]:8333 # AS62098 +[2a0a:4580:101d::1]:8333 # AS29670 +[2a0a:4cc0:100:37b:c44a:2fff:fe10:2d3c]:8333 # AS197540 +[2a0a:4cc0:1:340:1460:fdff:feb2:2994]:8333 # AS197540 +[2a0b:4880::266e:96ff:fedb:7cdc]:8333 # AS48614 +[2a0b:f300:2:6::2]:8333 # AS62240 [2a0b:f4c0:c1:920e:b25a:daff:fe87:77b4]:8333 # AS205100 -[2a10:c941:100:24::2:1001]:8333 # AS141011 -[2a12:8e40:5668:f001::1]:8333 # AS34465 -[2a12:a302:1:a180::b5ca]:8333 # AS23959 -[2c0f:f4a8:b:b108:807d:b2d6:9146:38be]:8333 # AS37254 -[2c0f:f4a8:b:b108:c458:5c61:dcca:cb10]:8333 # AS37254 -iy7go4454pb4p2zmnkwrgsi6v6oqv53zxnmalz6rnfjemxftapfa.b32.i2p:0 -j225nrmndwviihpe7ib6mm5h723cg62wrb7vnwofopv472ue3zwa.b32.i2p:0 -j2m526lqsujvt6b6xl4ipzbjkvkuecrye3vkggwo6jadvzqu7f7q.b32.i2p:0 -j2pyenyhoppsjexenznxvgqrcs4buv4nssctowgpg6czdoo3nyiq.b32.i2p:0 -j3usxovx7ukl645u77jud2mpmrk7ryh5yaxno6rceu77hqlxkuta.b32.i2p:0 -j42dsnjlg4vv33tshgs5jyham6plf3suj2sn2k6ew4tmcz3fpaqq.b32.i2p:0 -j4tjrfxnwcmbhkixmqlnotginhfxgfdvjahr6yn7j7rkbdqngh4a.b32.i2p:0 -jb3iui7grnljdjmsz7qbustrl5vn3ip3upnkzbaegaiklric7cha.b32.i2p:0 -jbmqtghha7hscwbwpi7ps2dnghq2bvxjnfeb5glngnvgjmeackaq.b32.i2p:0 -jd43pc2l73ek6hk2tp6hiyada7ed7vshqo2fvxbga2daylcghfyq.b32.i2p:0 -jd63whebd5yuls7r34mi3lnnuuhqxxr4lns672tzliru4vk7hwrq.b32.i2p:0 -je6ju6ihybxm5wkw5daeqjet74lscvi4ls5wn5wf7kiaczfggafq.b32.i2p:0 -jeidstlwdlt63lju7cnj2mh4fofysjnc2wcvilphynprd7jw64ma.b32.i2p:0 -jeox5nruuoopedsfpuoi6kwewmhbbsnhf7kib2q6oafvchxvmnnq.b32.i2p:0 -jex3ykw2nmw7owhgbtio5flv7us624bxwp46nr7rhmteujrmtvvq.b32.i2p:0 -jfdh65i4nhpg4obnoe4aqi3vzvbi6fyzjj2ee7s3qm2gbcnllkvq.b32.i2p:0 -jh2qxkjqngj2m5tn2ecaidfqac4awgnmkgsajntoqs5qqyjtp5yq.b32.i2p:0 -jh7ev4a5zfzmeyekinhtbqfi6c7xhvc4msdpyi67j3sxl6r44ukq.b32.i2p:0 -jibaw7ynbnxueqsy7k7jyvoj6ldzbuckppfx5wozt7mftihy5vcq.b32.i2p:0 -jicc5kwy4tv4j2nn6gfbis7e6dxy2kdvet3zpxdbyp74h5gpnxuq.b32.i2p:0 -jimdydczt6e2lceezopnl4fgz7q2jeqqhlqaxrgen33ouxk57xiq.b32.i2p:0 -jjangl6h4py2pd2gwamhqlsymyuocmpioneinzf5bb5qvvdjzzqa.b32.i2p:0 -jk56z3febpco6rbkpzzv3jszf4px5uztmoxzkpss7mxnzqlpsdla.b32.i2p:0 -jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0 -jkvey2vfdto2ucudi4jlgsbpmlls3uwmlkjonfhk5yminkwzwi2q.b32.i2p:0 -jl4vr5kac7njyltivn7ut5afyq5ipzc5woxl4523emodxixci3zq.b32.i2p:0 -jmebfluhrl6ad5pt4ipevf3g3a4trcu7axalpubpkir6zlwovm5q.b32.i2p:0 -jndr5i4qhxs6aa2bqvufrgttq6enavyghi54dqfuku2qnstdqa5a.b32.i2p:0 -jopiw2tup5h5xh2hwef4oflgskawbpfmswub2iosmqocejijd4fa.b32.i2p:0 -jrert3o2rhbkpquybwg7tq4bdvlxeh6lnlcr5ddexkuguvi2l2pq.b32.i2p:0 -jrobuecgmuuqmpdsbxwbqeldt2735cgcemngoasnbbkdz2ufdlmq.b32.i2p:0 -jrvg22xvbmjyrkqg7mr622zhnda3ijtua65cqngwrven7sf5zd7q.b32.i2p:0 -jsg4dsxvgjcqz3c2qgtwi4ip3l4n4hlxodbvgukwaipycwo26zua.b32.i2p:0 -jt35uwbl5wx7ponyxomksrjjs7zy5yymvtud3nmogt7ci7xxlm2q.b32.i2p:0 -jvaoh33cpczp626ldwr4azh4hb5cjmxlbz3dq3cxisdlzn7z25eq.b32.i2p:0 -jvlj7qyxcmolf76wneyvmdxrpiezsxkiimapwxbdbiw2phvlyjba.b32.i2p:0 -jwqlvqmfvodnrslde2idqt25qxiyvgqdlr2q4uod5s6lkmlempya.b32.i2p:0 -jxjc7oe24vxdepkfvl365qfwrxcad2f3j43fnfuchtvqqkqd2rzq.b32.i2p:0 -k4mch53m72zv7jdda3poa2zn7bi3jacqwfb45peealxbhysdozcq.b32.i2p:0 -k4pjt6m25dcxno3udek6rasooz5ztqnywa3f2owpvcjzvisg7nga.b32.i2p:0 -k5ars7hsrfubadroe5h7oypjnqwi6v2vxxy6rmns7zubf66aivbq.b32.i2p:0 -k6eeshsk4vf34b5gfnraz4p5qb6scv4kw6eiltebel5exw6keppq.b32.i2p:0 -k6gt64xby5igmln5hfcuzspt2tndimzrdvj65yo76h22g5yhlvja.b32.i2p:0 -k7kcnrqe3ybqu2w3fali7zext6na7o5o65rx6f5oqza2lonsry6a.b32.i2p:0 -kbawcieyelwwitrjow537zpmdkncwiq42rhjgayw5o7u562mk23a.b32.i2p:0 -kcqkothplemakipfpeajxmu4xsszpaxpprgtuv5tgfdaqejg2sqq.b32.i2p:0 -kdrcbr6wg2bj6oipsbeqy6bp3v7dqpth6cheviysmvo4bdta7fda.b32.i2p:0 -kehosmgk76fxnjywqjj6nqs4ohg4hsutljdzjo4sswhxlj5l5tca.b32.i2p:0 -khxruoaom7juockko2tbxqo3bnrjmoqjhdoady3yyr4qacz4somq.b32.i2p:0 -kjaa3zlp4sipfxikketgvlx4oxq5ok57ifxenbiewmsrew6lcw7q.b32.i2p:0 -kjvrzgckasb57yqhluvjblx2ngxstumfg6uufz5mc7zyetkjlr7a.b32.i2p:0 -kkihsh2faw2gxil6it4glol4u37ccruuzsusyikquzmkffj3wn6q.b32.i2p:0 -km3b5j6cqrcqewdpuveibptw5gguwktwan36jlow4xykpg2dgr6a.b32.i2p:0 -kppcor54kkge6cgq47nzevlfrhbxingcjfmk2emkrdaejpixkqdq.b32.i2p:0 -kskidltmbigp2etp4pdl67ke2qzjjw66wqairzr4wn2apq4o7bka.b32.i2p:0 -ksxxinje357zctkobwnxsy44ddivq7yp2n3n5gopk4okir2vghaa.b32.i2p:0 -ktua3j43ijxhhhfeljsp32kdiuic5nlnfnkx3ealy7ojva4vwkoq.b32.i2p:0 -kuzu73gzvlnog4cdtdk7edbusxr4pigknvwg2bjo6l46ugsgmrtq.b32.i2p:0 -kw3v6gq5semgt4gg6itum3qtaylanyof7wn6bnbngdeby4xixuoa.b32.i2p:0 -l364nudwoj63fe5nsjmniiun63e3ycdqrjyknbfixxtre5spx7ga.b32.i2p:0 -l3ach5wbdx3n5nq53sv6tagijrbse3nwa2gkqz5oj7aifyaizpcq.b32.i2p:0 -l5fita4r7niir3hxmu7mzcwrigxinkrn4oqeembdkgao7k2yztha.b32.i2p:0 -l5obkk7zzop3nztnt6ijugz4okqsyhhb5o6gkbqottgqzzzcgvla.b32.i2p:0 -lai3534z6zs2tukzixdagrciezum2bkyuask2srxjrn67yu4c57a.b32.i2p:0 -lbif3mgg2b2ir5dkz7u6iatdrui2h2a64vlmffcfgqnpjuvwzaxa.b32.i2p:0 -leu37bptuuu5377mi7cb5t2vsu4hesblyxl5zptnnk4vodhovwea.b32.i2p:0 -lfuvzzzceuik5u5pnd2i67amegel5ua2rrnncxkyyc7bhteq73aa.b32.i2p:0 -lgpojpoix7zd6dhpo5hdrnwm4ueyjvi7tbot4qsqybk3upuocnpa.b32.i2p:0 -lh7qjombcmiekvv6niz5eflr55cnd3oxx7nuus6vmehqfodr67za.b32.i2p:0 -lhupu3owhuc7qwvyfazgkbcmr7sjp5qqxps732vy52v67fsn5guq.b32.i2p:0 -li4vuovafxjrf54kvfg3mjrg2mebs6edpl5yrr2dohddvgmxjyvq.b32.i2p:0 -liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0 -lmlf3yjyg4djrb7wtzmrb4fbkorqba7k4lvk7ax4omay4mbytupa.b32.i2p:0 -lpal67whroip3c2yj4fxbayj46d3tr5osyqog6el5n6ctktdnakq.b32.i2p:0 -lpektonr2uyiohuzi35shtj3oaa77rklmqsivuydxkcxkea2dwuq.b32.i2p:0 -lpffyejskwwap2go7ommmryex2autlkmcnnpk2tm6aitxcalwrha.b32.i2p:0 -lpqkgbek3ci3w4qobpeqepjor3bukz555rzlmghck4o7wwb7ajza.b32.i2p:0 -lprgmkc45te7skx7rffpz72ca5c3zdg3tabiksdboao5w4wceu5a.b32.i2p:0 -lqn32kgic4cincyqlybpwbywcrowcxmscfcm4mqt4fgp24qs3y3q.b32.i2p:0 -lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0 -ls52j74gwtsrqhlgqcai2cjl2rcivfib7jzovc4454h6tq3i6k7q.b32.i2p:0 -ls5otp5mybmxqsaeaid7wlori2ukieehr644adjfwdxux7jxlvga.b32.i2p:0 -lttdnbluvybzbjq52t5vbdkk3pvzc6zyi2oji7yjdpcgtgz732bq.b32.i2p:0 -lunkwblewltvq4spt7j5u2nfpqyndvgepl7edkiru322mmtpy2lq.b32.i2p:0 -lvdbqavgdom5h5denwkmdwslfzxckf6eddwflelbog7tgo2m7usa.b32.i2p:0 -lwjrapkfexjyjqf2rrdr4ghhxmlr3jdygsonetgtheglvmru5x6q.b32.i2p:0 -lyg26sjkcx5ied5a4a7jdxmfeplfcnux3fux5rsxzkm5mgbbsllq.b32.i2p:0 -lyqmygrc6gujxa4xlnwqku3vtfkbrszdiirsagn6xd2yw4kvodrq.b32.i2p:0 -lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0 -m2k7ajij2wvgfpsbg32zuorbsjt72iye3ozz6dbyxtj57fx7xsqq.b32.i2p:0 -m3hlmj2gz2co5gu4ss3wj4b7ebeg2xbkrr65ogxvhn76uxna5qma.b32.i2p:0 -m4o2kndr75clxemwbq5m6vnok7eiqshf42wjjvag7dtwxtafxhra.b32.i2p:0 -m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0 -me6x2p4m6jw3cxi2xl4a37u4orzmv3xdopr5t2vgwjmauiuqrmzq.b32.i2p:0 -mf6tmlegp7uga66cdael5376uaz4qd3wacuh44yvepa3kbu4fk3a.b32.i2p:0 -mhgxec57s6h7eixgemsghlcuhmgh7m7p7phqd5kzmm4wovrp2pqq.b32.i2p:0 -mjpulaafdyuanouslfpjcsvumi4edtckfu3ffn3ipabkxj4sn35q.b32.i2p:0 -mlakhs4ixcqwvk4vo4ce3loa54wmdlfingk73jookrkbra6ppq4q.b32.i2p:0 -mnkqn3r4jmg6vrmlprabenndyft2z2jw6g4nsnolt434coiklmyq.b32.i2p:0 -mnrbc3qi4zuk2tzghmy55kplawncih6jkmt75qczfu27enu3gcea.b32.i2p:0 -mnrrefebq3yxr2avprp3ay7w42sx27ijv6stjljzpwohnfnkg26a.b32.i2p:0 -mo27t6wym666b3wfauhndqocbetdsssxksep6x4dcpuh5dxe76oa.b32.i2p:0 -mo6mp2tymma5l2swob6kqzzb25ccmgccfj5pic6omjkktv4wve2q.b32.i2p:0 -mpi7bivbr2pywsgasslw5we766m757os2667h3hqnhcftaszdv3a.b32.i2p:0 -mpqb3jdmdibarrflyiik5wj3ekitxpe2oqieztlax3uomxspgsvq.b32.i2p:0 -mqocuhx3qwcwfuuin42yuhtqgm76drlmfvzikf7urot75qw3ykpa.b32.i2p:0 -mrbhw6ow77bjqmb67rurbkcl4xs2ocj4pti6hnz4wcsg6bduwtya.b32.i2p:0 -mrypjr2fagjhg6z4ixr73f5npkeyoxsjamcdv5uc6oj5oi2ylsvq.b32.i2p:0 -msjl4a7mdp7x2bcllmbxurhfmtxvolykonz45psmh7j6pptfyy5a.b32.i2p:0 -mtlznxqya5nbuyorybzul4cpdlrnvlrhalx2eogwjce5j32js5wa.b32.i2p:0 -mv7b44duaxqpzbdztnrdvnj6ypsp7yhs4z3dc2q64jov6pritmja.b32.i2p:0 -mvs5a3s6rgfbvvgq44wzyd57vf5pr3jcthc5qdo75xgj4slsm7tq.b32.i2p:0 -mwcqoe2lu7u6ogwo77kr5sr4wx6pxnotkdeck3yyjfh4uklytj2a.b32.i2p:0 -mwevh5r5dkzddlo2ol6bojpdds3kno4xqoy6p6ulid3paamgrtla.b32.i2p:0 -mwyjzdrgtypbwjyulw4ifetejz6xusqstvzylztsphpg2r2zf7ua.b32.i2p:0 -my66tuvzfyy6kkbdeqvgfpk3xuoxerucxt73tw6wxv3ian2p2snq.b32.i2p:0 -n3f4ngbs2igvp3j27vsi7thguqxoyvbfenaqhgypuqdz5iovek2a.b32.i2p:0 -n3fa2yuf3i3opdktiwyxzhbpudcut73valxdrlre2xs2ooepddaa.b32.i2p:0 -n47e4gkf5xujcamnsarfuy7435hfsgs4zhndcxaw2evafn6r2rma.b32.i2p:0 -n4n7bivjb2mffgll2ulpwyb4m2oomv5roxtdj6bmlb4cgpf3wdja.b32.i2p:0 -n4zwusew5coibur4p2g436ktc3cyogz3sklztu6ruulag3je6ita.b32.i2p:0 -n7ykk3cxcqzcoeipo7ghzb62ko4d6bxzfgenzxistvg6fuclebva.b32.i2p:0 -nazasriqoa6qoxdlgzjwsggubxl6i4nge5q7om7nijaqi24ulgua.b32.i2p:0 -ncdjjthck6v6phz4laddyc7a7czoujys55melfcoptvl2h4izqlq.b32.i2p:0 -ndtoi53fz7e6ml6v6jn33675nwciw7mu5msn7afzbhebprusqg7a.b32.i2p:0 -ndunnsjyp6l4w3jebow4zgsfrdsy2lrapjgslb3tv7dg6oypfbwq.b32.i2p:0 -ndx23xqvt4qezezih4wlj7mqtwc4nzbvmgseq6fc6e2ddywrmkwq.b32.i2p:0 -nejmippeopyo75wd3gjrhca3fr5mo2g37owzwdezxmg7uhx6ygxa.b32.i2p:0 -nfsi3fenzrzoccj7bpzuvjbxnij7dmzuprg7ia4geuortoquja7q.b32.i2p:0 -ngn5elnvbm234yyun5kbjyr76oy5nhrvyckn33cqcbx25hw4lfoq.b32.i2p:0 -nhpbv2ravt6t5fhxyvuhrxyma37wph6dzuzpddlw3uoivzl6tx4a.b32.i2p:0 -ni4ns3ou7v6zh5qrawvkwnmshnrzcyc5zojkw647rrniplmurrba.b32.i2p:0 -nigrfbou3zt6wxegn5im4cyminjcjmbsqror7ntcr5i7yv6chwvq.b32.i2p:0 -nij7pzb6mhrra5glb3dyghjt55sngwrikzdlagmpsf7jn2onvoaa.b32.i2p:0 -nisd4was4gm3pkvuwjh3sbaoo35jtxop6y2d7ug4iol4cffkrk5q.b32.i2p:0 -niyz7v5fdhqqtlr4y3tcgdoeu3myntub4trzvgixlgjbmowccgja.b32.i2p:0 -nloq52novup3cawccvaakmbudooatwkw7dqltnr6q3j4qy7r6oia.b32.i2p:0 -nn7p4y7pun3m3txaqbkeptkxykzwrf75ru2zimadnewj7g3r4una.b32.i2p:0 -noj7le7kkj54umo6mdftagvvk327cuir7q75bnvuphrxa7kjujna.b32.i2p:0 -npcmehkhh4z2wtk3f5426izrytvqvyf6aa7hyx6hf6jdbxveqima.b32.i2p:0 -nrrg4p7tztllzthlkqzomqi3dejfcak7t63n7zzuomt5atzz5m4a.b32.i2p:0 -nt3ysas4wpjgkft5pohrfstm2vgj7t2vx34u32voy7rqon7dlbga.b32.i2p:0 -nu2ao72zway2ponkhrf322wyfrrn4mdmyp7n5q5xzmjhcge5odma.b32.i2p:0 -nufliiw3uav3tzdalit224yhbfpcjtgfrm5ic7ob6l3mmsay6cpa.b32.i2p:0 -numilh7hhhf6inzkzway3hzif4kiroqstxqbz7hzvoy2ctgpaqda.b32.i2p:0 -nuwphtuudfrswids22qjq63zgxh5wu7erafl36jyniuxhz75ikyq.b32.i2p:0 -nvmuuajhaw74g565l3a7dpezs4rkzm22ub5jhh6mdvzu43j4a6dq.b32.i2p:0 -nz4lq7pmswngaevv2uqyainqzutfxlkavxgde2w2slo2p6e2kcfq.b32.i2p:0 -o5ijpzor3en5xnndm3ntti7o4fxvv24t3veh4g7mahk7ogesb67a.b32.i2p:0 -o6b747qkpgu6gvsem7leylvmxsaaqby67pu55fmqn52dgazuvbxa.b32.i2p:0 -o6t4fr5ayfadzieutstgwcllvwxeuzjlxmzsmpj3hpkvefhzfaea.b32.i2p:0 -o6vbupdnpd5bwvcx7ivaecgyo7x5vdu5em4va6cmx5iwcf5tyaca.b32.i2p:0 -oaeqbkgpek4qnm3nly76x2tfrad2tun2xefliez7a3uxddeq4i4a.b32.i2p:0 -obf5kfk5n4nnsw7ez6ls6chqu4lz4wlck7utwvmjnlin4nzfnspq.b32.i2p:0 -oeydvkjoeqy3473wxkkbmoc6zz5m6zcmf6ov2hfkci54efsityua.b32.i2p:0 -of2gy2vblht57tn6yfczslnmp2xybdiazzta43y24w76tl6tu2xa.b32.i2p:0 -oggn6qbpmbag224gumagzgno53mgozb65tpzt5lezjbfbbiqky4q.b32.i2p:0 -ognn4mwwtmtjbrnq2kur7spcfohivxlrvz3sfamt3t46pk2e2ibq.b32.i2p:0 -ogqdcq2igslh3n5jn3utz2vpevttul366bt2246vilfnowuyvova.b32.i2p:0 -okjamsyd4wutvhfhsffejwk6ioru4mmvwagfssoy5hcocg2gj76a.b32.i2p:0 -om32whhwvcsbrf4g6uh5hupsl67oapccourkxyr7uf5zwaqxtxbq.b32.i2p:0 -ommky7qetuh45h4lk3raili27fnbhsgxv3zucinoaymnymo5735q.b32.i2p:0 -omngcjfwtiyqwbfqqggzbkttqgm3blywu43kpto2py2e4gp7fhra.b32.i2p:0 -opnpvz7mzfw6nypgmnn5zgtlzx7xuc4w7vat5bsr4mdtp77kz7eq.b32.i2p:0 -oqrl573nw6my2o5mup6uq6pm5immw3gnviahig5cceges4wfnyhq.b32.i2p:0 -orvshryqq24l24e4dvockx2ekj4hu42otqxsvyvy7tm7hhdjsz7a.b32.i2p:0 -oukeldqgovavh3npgb2by7w6hug575uae24z6uqfdl6flh7ma6rq.b32.i2p:0 -ovnk3wfbrkvvute6vkn5glhdtlxr6nyvebiflvr5l6ws6sorpa2q.b32.i2p:0 -owexluejb3eszx4p3b6zuxyggsxxtkxfgxoylkagfecs3bgfnpja.b32.i2p:0 -oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0 -oznpphdisfvlcjgkvny6ma62wy637nh4vtpxww47ifpmlqkjv3ba.b32.i2p:0 -p3au2w5jnkqugxnkukj4rusvynvz3oxawdf4ajzeyxvfvyzhmetq.b32.i2p:0 -p4tsqwvdpaitvlgaujfr2m2qbr36qiwusas5zkiut7w2wjcp3sqa.b32.i2p:0 -p6o3tzllswm2j4wah35niry4tcdu6lq5b67ehevcx45sae7pb6da.b32.i2p:0 -p7ifeij3vhds3diihx5qimucyzgck5omfkqxc4pkbbjtfu4hp6wq.b32.i2p:0 -pbag76x5yyo5d3wypvtohxmgbtdrjjb35ljnq4w5fpoguyt5mj6q.b32.i2p:0 -pbftrtdthbj5qcecraden3hdvwomqrgseec6ib5h24n2zcivdqaa.b32.i2p:0 -pc4d5v74tr4vz54pbr57ejga765ep6vwk5kox55gfobi5572apta.b32.i2p:0 -pcc6cnry4maul7zlbd32khalaavkcbw5hdjuk4zjwposaorjicca.b32.i2p:0 -pcdlqw2awppohbiued4rffgs6n3lv3thhon3r67jmx2652qx2khq.b32.i2p:0 -peteksofgwgndsdh6ovh2ydkrgpyqgttit4ususs4bzksvdqkbea.b32.i2p:0 -phendyytrqdr2vfsw3kil6yui5vb2p4v5xuddezg57wsdw5uyquq.b32.i2p:0 -plhoz53xhplmyuejnsg5bkfe24ow3pbldysoovuupu6qwb3nttca.b32.i2p:0 -pm4nukrzndd2lvd3shivpjrcbjlontmxhag2xzdf572snwbr3p6a.b32.i2p:0 -pn5cx32ljrvzj6x7hpgyff3rlftextqpp4zn3nkfufrrpnpuimzq.b32.i2p:0 -pnhspu3rloczdbzsysa2iftsgoiy3zgcd22jodmk7zdjanhiemla.b32.i2p:0 -ppe2jfsb2xrmgwugbq7agy44ucb6yq4qbufaf2sh76b4kwpa4jcq.b32.i2p:0 -ppez53yrs6lanyvyxuxblqxiuvhnqvvtafmwaid2kgp2dx2v5iaq.b32.i2p:0 -pqnqwxl7jsrok7vgpgcvlxwlkg6yckx33n3g4xf5lvuntwn63b6a.b32.i2p:0 -pri376r6uuwgnbnevki7c363h4ryfwjza7pcbfswqqxk6hnrkhja.b32.i2p:0 -pscw5yzaj5js2fn7gzrzoj6teonlsohlbnvdco65ubdefpnpwhpa.b32.i2p:0 -pt3mqmvkv7aleja7vattlysu6x7gjnbwqvwtu4skzabvkjztfi2q.b32.i2p:0 -pu6e2b5bz75qnmp2rox252aksllnitv2grnn7qfyzjkfio7w5h6a.b32.i2p:0 -punslpht6pysnlteht24rgvrkmzdd437lnpflojwakl5dy6mbema.b32.i2p:0 -pv6g7uin653rerdiivdgtoirjvokjowi4b3fwatszdlteyos3i2a.b32.i2p:0 -pvqyvn2lpvoeyhgcgunoqtetkrkp76iegyoii2af4crnlto6gb2q.b32.i2p:0 -pw42656k2vbwxmvrc2qbsz3jslvcxahln7rehsbia5jdio2knh3q.b32.i2p:0 -pxbyhv62tcdqqpl6pbp3og7ajzzcnbximv5kyt3hid3djd3uwkdq.b32.i2p:0 -pyf2csixjugwp6ad3bkry2ulkzj7inc747dsmpk7iebuidk4l3ra.b32.i2p:0 -pyole4gslrmenfcmd4ilqyzvsuyrjyffjbw7angentqjkkljitqq.b32.i2p:0 -q3ueujd332k5qjxdqkjtjlgkm3ktvdy7ats4c2ogcvokog4wm3vq.b32.i2p:0 -q4o7bf37e6afx7evwdyovsqptjwo6td3c6qtjh4rtdngp3trwi3a.b32.i2p:0 -q55g5g6s47hi7pcuomug3vrcd67vji7us2gqmfe7qn2nkq5vz52a.b32.i2p:0 -q6lzsezu4idxpdwro4x6svwz7j6h6gso6enidcxv7jhc2gbepuzq.b32.i2p:0 -q6o3eqnyg44uzjzqeudsankgdouylshkhdhl7b4bqxkbmdnm4iaq.b32.i2p:0 -q76g4lkosb2sxenh47eutqgwwzjyph52rirc635wkwnxsejrzdda.b32.i2p:0 -q7ntdwy6xueyvghbjamfrh62aqtuu3ikwg622em44pa3czomrdjq.b32.i2p:0 -qa77lz7dl64qwtj4fxxlz6otkuvv42dciggnmx62eobs2xqi3vlq.b32.i2p:0 -qaqvxmyvq2m4wombmtaz3our3qmp7eet3qle5flnrs3a5wgfhxba.b32.i2p:0 -qawed5ou5vb42ugi42goxr2s6cqzpyh3s5atkhvfvyhyc6anxyaa.b32.i2p:0 -qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0 -qelsaseevnmz2unpovh4nbpjpshjg45iudiaf5zbngealwwuxe2a.b32.i2p:0 -qfbughfr5hhgoomasyviwk3zin24uerpl6urz5smzxc2div5ixxa.b32.i2p:0 -qfl3i45ipgugo7ueswy3ynnbaet77xawiplvmm3kp4fj72qvzc6a.b32.i2p:0 -qhuk5zq5v7h5p7o62gsxgtqqo7va4i77o5vei6wttxqcgaw47h7a.b32.i2p:0 -qivuqkrr3pv3rul4wgx4o4zon5wegidt5auylv3bhebfuj6oqauq.b32.i2p:0 -qjdftbhcaghdslzxjqx3nmem4z5p5jt7e7ou5bdz5llnqlxshe5a.b32.i2p:0 -qk3iq3wr6emttdilvdqbv6vnqjshuzz6mylwyfo3z6vpjywvnfca.b32.i2p:0 -qkohzoxigef43ro7mf2bd76eyneuuj2vfyremufvufssksbvj3jq.b32.i2p:0 -qksthizqtfdjjxcrahqxkl3bev75k24blagrkoszxen45zelijpa.b32.i2p:0 -qlhklv3q3rrszbrkxw755lpdburxwcj5dkxwicas46flztlkdcja.b32.i2p:0 -qmtg5ukzxemsktsxw2brwmohehyehwlleky3kuzeqzy4ledcou3a.b32.i2p:0 -qndgqhj3cpbxrktu6r7ysaooccqzvselvn2tphu3plx2z5ouocgq.b32.i2p:0 -qnqojlthym7z4gwizcblhpd2thy7v4a6ifme57bzyl3nxzkj6ica.b32.i2p:0 -qorzdjceszf432obxa73tnwhqb7ltxrxlfkkqmw2flmfjhoyv36a.b32.i2p:0 -qp5ppgozzbkuingg22zgamf4ozpe2n5hjlu4i25r6pjqw2ngrhoq.b32.i2p:0 -qpddavnflr5tdmeypeu5lrjjwsgtdhz7hw5emxiyjkcp7m7xysca.b32.i2p:0 -qpo3u565rmgeioruszadbc4vmpgjyoh7qorv4lyefl7geewyyz7a.b32.i2p:0 -qqiakw24obfwz375gfb6muzaz7tr6ani3od6leoox7jwzrizyxkq.b32.i2p:0 -qqmxvujwi4ktgj2cuqmw4kiujkf7ukrkoe5ryy4bjb7tyleplsja.b32.i2p:0 -qrpz67rcwrbpcockid5ml24dtdhhhekty3xd66ekkyatpfjd2wka.b32.i2p:0 -quzkrgzb5pmn4465647ke5lsfbseqnorr6ljvfsxcagj7rzl7hcq.b32.i2p:0 -qv5e4jlcmmkdlmh5spkvv2wgj343vm4yoty2hofuzi4lornn3hzq.b32.i2p:0 -qwhvlprhk3ntswr5xntnc2hhgmvd3bbgzgkbombiibhrsj7k6gyq.b32.i2p:0 -qykavpjbecssape77mrxjxwxces2gbjd6gzewd6zys32uhmnnw3a.b32.i2p:0 -qyqwn5xs24h65rldrle5msyarmqof3lb33uz7sutauwdg5qiuhoq.b32.i2p:0 -r2p5kqr7xjo4ncz7l6ekdx2ge6su2j22j2tdsoxu4jw3u67z7poa.b32.i2p:0 -r4ukdj7c2k557k7qd6siauhhqucshwy2rrkm66twzyh4jiucimaq.b32.i2p:0 -r5d5jgscvs6ix5v646ohwa64vutu7umfeknrc2hrezdjtlr4lm6a.b32.i2p:0 -r6d4moarp22wnnsnmsxqt3s32gzyscaccackcazvimrep7sa26ma.b32.i2p:0 -r6hd3knqi2p6kaw7hybrcf2q5lcarulcczs3sgcuz4yc2saj3gya.b32.i2p:0 -r7bug6wbhevqqlbavouj3ggpa7e57sbd3oivkzqeyagrtxshmjpa.b32.i2p:0 -ra7ztq7oq7jcozpui7c4zv76gh7rjwhq5fkpxp7dvw7ritick66q.b32.i2p:0 -rb7tyjd6gi7evmt5mzvtboramqip43sh72zjxnwhj5k72zfi3g6a.b32.i2p:0 -rb7x26lmepfbcd7wtxu42pf4tdxbe5p5zsf3cwuukd4fs4zhxtba.b32.i2p:0 -rd2cw3iukuth2lwe44q7fipawrne2io6y3fyyv5xew6vd3hos2qa.b32.i2p:0 -refo4v727jmff6ylrpbkvd5emlfr2hamaeh7zho6oval5dmnwlta.b32.i2p:0 -refrtydbdslzcgcsmmph3435qigyajh4q2nvl756f5yojouln4yq.b32.i2p:0 -rfgsjhyvqbunef5b5r2emjuoxx2i7rcsl7gathy2n4gwjyyat6bq.b32.i2p:0 -rg677vpfzyhsckzzcvoyvqdbwtdkqig7lxv4unmxcz63vtr6tgza.b32.i2p:0 -rgbq36syjadm2ex2gftc6xztivckrqzcjszla3jacwfo5hqutzqa.b32.i2p:0 -rizuiypjfhukt3bqnetppoauovuaqq5e6jzgd7tgy24zrwa2ydxq.b32.i2p:0 -rkhb3463btvfozwta37itlkt37iyncpkzak2xhoe4kg7tqafqria.b32.i2p:0 -rl4b3r5h5xodo7kiw4nykd4rhoc4j37kxizzyb6ukgcomyc2qrya.b32.i2p:0 -rnsjgirap5lfhxpb2xczuawgoztb4ptgdwt5rcb2bz72vhtai2jq.b32.i2p:0 -rrm2pems425buhonptp7lbtbprmwwjhbftey4ujvk25nclx7rerq.b32.i2p:0 -rvjzxak3jvwwti7klfb64wrsmlfcs6ceiqhzbbmjynokn5tz3egq.b32.i2p:0 -rwgf2wj2x66xtnjx3dggxhkuy6gvihvur42tbkoej6bd7iukoqiq.b32.i2p:0 -rxatc4b7obgosvznpqrmyrl6ty2yixhi7rpbh45sopqwzglyimga.b32.i2p:0 -ry3iuaabf5ek73otfvchwrqryez3nsgq57bpmzkyzumqhfbhgtaq.b32.i2p:0 -rypsyqod2yq3zagcvvc2643vydtv4zm2ew5r3w5kjzyq2snvzv2a.b32.i2p:0 -s35hlnmumkgdsvj2gepnwro4wo2h7ts7ddjhhihqggywn7qcym2a.b32.i2p:0 -s3rbe5n7lyy6smerpkgr4ictzbvkciu7gxyj6zqw3xyw62rmivha.b32.i2p:0 -s43w4tsmzmddvu2cxugh2lx4o5mup3rkvjhm455u2qqpg4bqlhyq.b32.i2p:0 -s4qlly4iwzevejk4ex5zfqhb4t666o73mvdmy4gpu47tpb775nja.b32.i2p:0 -s5ls42vzfaqzgrjr6cvgkmgifei2rtvj7uzaljkpsmt62jwtmvxq.b32.i2p:0 -s6umfzwe27x7az2yjsgqftjzawoj5lrcrgxldkfwfq2qwobml2ma.b32.i2p:0 -s6vsdby2liaahn2fh7qvrehqfus7gaz3p3u3rpjtfjhm4ahvz46q.b32.i2p:0 -sa3k2xipbuwm62bb5n2mwaqyyjcvxzb53kmzinoojgnjpnqurzeq.b32.i2p:0 -sadnlzguaa4k6kvpiky27izp36er3i5h74l452povbnajqullpca.b32.i2p:0 -saj5uchj7dzmxjv3kdzalgtbqzw6wu4wzxxdiobc23m452ehk3zq.b32.i2p:0 -sbalp2doxyedtr52kj57va2rmbi5npspv4drk4vxnujag72gtpiq.b32.i2p:0 -sdxfzbgwxpf6hbik7k4bqm63wm4xld7qgo3hjlhknnehzxyyeu5a.b32.i2p:0 -sh5hww42vwlsl57cdropaeqmmwozinnr2tg6wq4prg5wrkusvxja.b32.i2p:0 -shpd3cifcjoebw6pskj4pfmrm7lwecrygjnje55heorhsxm2lnrq.b32.i2p:0 -si5x3fon3ew644friidc5o3syrf5v6kk4pxxjvhibev3odxk7nyq.b32.i2p:0 -sikkmrxv6wat265rpay2tk7jywyvlzkekpolmwyp2el5g7iihsvq.b32.i2p:0 -sjpqyf3rq7ojcalldlybvyyh5lqiq5j3ade5w6txe3473ybhk3sa.b32.i2p:0 -sk7aivked563g6g2ri2saggni7jqzxmucuqa6xkudcgjvpbjsyda.b32.i2p:0 -slbbsiq2pmouqht3hznafnowq7sxzlidmwghfch7iiq64rzdhwra.b32.i2p:0 -sle3cbbdom6rknc3drqtawctpy635ica5d5gerjjdahfymkok4ma.b32.i2p:0 -slnmute5o6h23ldim34wro4zh4qa2pchnskmdpek2nzc7u5oz7jq.b32.i2p:0 -snfinsblh4j4wsv2n5kmkfxbvqzcei2ryfyu4heqy6u73mosep6q.b32.i2p:0 -snsw3ewf7wjtwspiuj33h3vtxnybllurzcwm7u62iutf5phoitkq.b32.i2p:0 -sooo7ajo74ajo6m2yomcc6jcofdgkdoyjcbrpl3nyvvusr6fw7ta.b32.i2p:0 -sorobw22rerrhpx5t67joyqai3ou6xsvqxb7wdomtnwnqztm4sga.b32.i2p:0 -sotpvcqqzzmty6llimwlvknqsdcypn4wsnwk677kepzmy76w2gqa.b32.i2p:0 -spbb34lslk2tldwzr4ydi2culk7sxgl3imb2gg746xbxqqcj7vzq.b32.i2p:0 -spuaa2y6qsaywypklz7itcb5klesogef2x66m4flws2r574qjc5a.b32.i2p:0 -sqjjqyrhh45jpgfp66idiirgh5ck7f4s76ee2l5bli4obsotu7zq.b32.i2p:0 -sqjorsqambyienumg5qpw3foftkp44vpsd4lwklgbl4lag4mm6gq.b32.i2p:0 -sqr66feh2g3f6bknt2tnltmnhqdkzoq3jhdaatfusshrv6v2zhma.b32.i2p:0 -stltasmf4b54srrjb3mf7hjtjvmvvms26btxakccdtllgrm2qzgq.b32.i2p:0 -su7d4biurihkyr3qeea7makkxzikxr5zi4znvryh3bjespppfhxq.b32.i2p:0 -swmtaospvaup7me3dvzlw5xoeohhj4zn5q6agivif7kxtseweriq.b32.i2p:0 -syhxehvl6rublw6k5ysmzcsqrzdsnd7eqrbwalfkvhgfccpu2osq.b32.i2p:0 -sykjw3jnb7n6bo574wnpiaxhp2nm4gc6hc4jh4v6trsbpboysooa.b32.i2p:0 -syqxyl67b4hdo5u3jtkkzsabccvtjaerpushov7nrc2f42x67fja.b32.i2p:0 -t2e45js4dn4cfsyyevm26z5ltvmu6lftxziji4fm3v4v2t3ykaoa.b32.i2p:0 -t32qcc2tbjgqxrydr2txgm4ahhhae3zkkojmguehw5gsbtrdvxsa.b32.i2p:0 -t43qqzux7ik7kki2rxtillcgbxrznuhjac7wtqh52sqovk5ay3xq.b32.i2p:0 -t4notlid4bejwz2tzucpvednkeuskenpnu5sqcbdhh3lqouigqxa.b32.i2p:0 -t5cd7q36no6doxduuvk5psdx47zl7ousnckjgw7c6zr3o3ke7ffa.b32.i2p:0 -t7gbmefspnynaezmvx445fjapp24pjjf7wx3evpwlmolzyu3wi5q.b32.i2p:0 -tanmhvkoyd35kf6a2nhj5rmbwpt3shc6thypsle45my565womjya.b32.i2p:0 -tbqehmm3nuuf2spwsjobrc4hg6uxji4mdelivhywz4b7f5lv6rka.b32.i2p:0 -tbrjczwl76v7ob6hon36z6f35otpv5g467q33pgzyyakp525wwfq.b32.i2p:0 -tcx3ftsdl36ukysuuewydapdzuu4alewyg22squei2wda4a74tba.b32.i2p:0 -tetoqjagsf7fpejajiwm4rosqscy5huqbz5hcqgfuha5tdfnlrnq.b32.i2p:0 -tf4tozh5unsgyzpdsmrdcpbgekw2agu7tp5jvyclzcs5kjudwwpa.b32.i2p:0 -tfuvti7yonn5pjptzzvpshh23x4rqjvm2usolrbnlu42laj4mhyq.b32.i2p:0 -tg6goh3flzmcer5voft2nf3tudm7ikyez334zry66vqxmc4ieixa.b32.i2p:0 -tgt7rdhywtlwob47flp6ccq7prrbh4ipnwm3xszuykq7be2pksyq.b32.i2p:0 -th3dj5sqw75lga3tnffbsywajxafv7cvlb7sed6w7q3w3sxuqo6a.b32.i2p:0 -tj2upmck47iktfh4vncmyajnkbatqglqzy4coqef7wioor4hbsjq.b32.i2p:0 -tk63xbzug7def6esivofwq2h2c53ar3ot7hsezdq3amxqqaoyr5a.b32.i2p:0 -tkzuysa4lkad53cywbt6sgpcndvvvdkjeatpkwyfweorx7rfe3ba.b32.i2p:0 -tl3xkknuukvyinyhvt7saz3tvz24ptgyqtzy3igygyfapcf2o3lq.b32.i2p:0 -tl66bkfoqu6eameaqtlwrvfttyc6xj3s57za3hd7omnfnjg3i44a.b32.i2p:0 -tlfttkbshrcixu6i6syntl5xjsoh6mtgfpix54knahyeuhlju4ga.b32.i2p:0 -tmmjmcrwegjke5fzv2hha2wkis7l6xdaa7fkq24ge5rbvqpwxzpa.b32.i2p:0 -tobdew6554c76jhrulcd2ssgvef7dryini2xjxem2zushe37ycua.b32.i2p:0 -trucvlawpufrszky4zzhhxtddnhio4mnqawzc47n7kik6i444m2q.b32.i2p:0 -tsfr6zvcgsmw2ekaxqqtkdrnbib5uio7lgmrtmscrvwe2d46g7jq.b32.i2p:0 -tsrlbxayhihugr723z6rkyafglnhcyzi2zhojzsyfdjsqkkd53bq.b32.i2p:0 -tv3x4kddbu753tnlghgh3txogp26tlydt47rl5scx7eoxgnocf4a.b32.i2p:0 -tvbutrv73xhwqbtosmbp3cesdyc5bbtslay4gjsf7rzdx4ztgzaq.b32.i2p:0 -tvotv5p3emxxnti2bnvucbfy4to7gxptwvh4qznuhy62hghnju4a.b32.i2p:0 -txpr56jvbf3lmqgaozqdqzgckfpugzyd4cwplkjootvf3hk42ibq.b32.i2p:0 -tyfkhz6ggpi2rykez3v3j5f3evnjxfoau7ve7m2heaukrcqiui4a.b32.i2p:0 -tyvsuqy36cx2yvf7jhnkd5ojc52g6vxl2rw5qshqwpk63ptovdda.b32.i2p:0 -tz5txdipkxcnydzcsuqw47qxdvpob644u3cttlbrbfg3zp75vl7q.b32.i2p:0 -tzudbbctweb7rpnf2vswuw26j63ysqztsbt7lfpfj6xautueiklq.b32.i2p:0 -u2tnrysboqqwjn73awg4hfxtfjgbqab6vrdgyu43s672jdcanhca.b32.i2p:0 -u5ixxcd6slvzxouj532njusx7ec4wemrfwmg6gwltlnkruubi63q.b32.i2p:0 -u635477uxqs7z4uvwx224u6ojn3c3ewcb66f3j7qlbzqyrrevxja.b32.i2p:0 -u6wrw47yfjdzk6a7nc6c6scvfokwuqmvuhxehqvymrv7owiajxia.b32.i2p:0 -u7uklnwthbrynr3z2gc3yxfmi5yoemsugjbb4nm44x26f25vxp5q.b32.i2p:0 -u7ygn3heosxu6l2die34y7wteexfp6h2w5j3nhr424yoblysigyq.b32.i2p:0 -uags6hm646f2qsyqfhzjt2xlnjqbiopiodghywosdgz7bwtbggta.b32.i2p:0 -uc52rzz4xu5ikx6hl6r6sqxfmiyyxsffpcu5frrtepczidwjwuha.b32.i2p:0 -udfxh2r5yfu5z7ynzacur7p3g7ug35kfa33ghes2bazpdivxlhsq.b32.i2p:0 -udkwqdo5odg5npn52rueipghn5omhvojthzdmvcvuomgzglum7fa.b32.i2p:0 -udzbx5jyvrp4g3iujlca7jnlaaaa5m3e4jv4sbr7tvp6k6cdjc5q.b32.i2p:0 -ufgoaa6g746zzpphuvxuomuizkyfpz45chqta7skrywqq6cjbqna.b32.i2p:0 -ufittrlr4eautphuqzuotc7b3xx27n4xgy5afm4foc6nsv56q7ka.b32.i2p:0 -ugw5zbhs2pvsgxieklmc6z4z6d5cvyux4pctpf2udhjgxvajot2a.b32.i2p:0 -ujg6b4cyxhi5pf4puwvwupur3iddm23uibapigpwl4bstvlt4cva.b32.i2p:0 -undzufsjeb4qlf7y5llh56tji6zlhtshlsyht4yjdsa2k4ayx7vq.b32.i2p:0 -uobwophnzqq4yhpp54aisud5ojgrxq6pasmq4aq6qw7dhgjcoqpa.b32.i2p:0 -uodycjdscpurlego2nrs7ptoze26p6236t2r2tax5ubdgi6duqaa.b32.i2p:0 -uohuxnjd27cftarbf6kh4czmotwvstpon2sgs2vpffqkgmg7guxa.b32.i2p:0 -up2kudwqomqrwvfognnhz2mjwqvkgpknfyscp4ue5ioev3q4jd5q.b32.i2p:0 -upme7c64dwjgbt7w72yf5ydl3dyp25dtenrkq6z3aw6hbircqzsa.b32.i2p:0 -uppxodf6bz3qibvpzzvtedl5lk3h7fslrwmed2cmqvdpgtvqkv2q.b32.i2p:0 -urqlr3cei7pp2cruga4txxmmvel3bh7nsbqzqzpe7omvmbm4v75a.b32.i2p:0 -usgqijrwhtwgoekjcr26yqcgpncwpsescrr3eek35e3rhkrtptoa.b32.i2p:0 -uu47uxdqqtv2pqorbaxnhhfmcsxmknvpreambqqkosr45b44h5ia.b32.i2p:0 -uv44mjoqrj3m3gzz5wxlnszt5pvgk3iqlc3pmqfe6un6gxays2cq.b32.i2p:0 -uyshm6nokdjyq3l43224at2rigpa4zmiyybuufyq22t4l65ialmq.b32.i2p:0 -uysvdsh2bzicmdqqdl7ezuftxcywzapohbzl5ap5hyiinki354mq.b32.i2p:0 -uyy4dbfyx2i2x3goobc6uxj4nb7ktzsu72zlksypjfisgka3xnta.b32.i2p:0 -uzgfmsjcbjxitt6bed3p3gpdzviyop2rz3cxqyu64ec3z2r5imqa.b32.i2p:0 -vbzp4sjkgqwymn2z4ikbae7rv3clbo7vv4mwv4ft7tu7ubrmbeha.b32.i2p:0 -vcksnyuyw3i6hfviob5yzoynq7okxi677bw7224273fjhsk2kgra.b32.i2p:0 -vdpfoahxse7cjciw5l7ffbwzc6e4xdlf5ulvrk34mzm2gy4mhlwq.b32.i2p:0 -vdv2aitgqica4taqcmjexw5xfbrfbhvf5kuxwvfjf3yiki5a5cjq.b32.i2p:0 -vet6qwwa74jrqrjzcm7ylfprzwpnt3hlzjvkbnaoiv4o2zzkr3sq.b32.i2p:0 -veucihmd74nnumiunvruyjs6kpjs5sqw5dprldlzcf7i3h4igkda.b32.i2p:0 -vewdrismzwnlxlvni7slpq722wlwfami2elghudm2ofcjhpjcs6a.b32.i2p:0 -vf3l3f5unlwrfmr3fiphpomgslxgm6m4chg72itf45yfu3brmy2q.b32.i2p:0 -vfpzasrsrqh3llkudmas5fymwn2ohswqi3vakclgm6fn4nb6s5xq.b32.i2p:0 -vgkou4ysuxvhlxrwf5n2ihn4ffyvvedluun47l6dobi5ycziy3nq.b32.i2p:0 -vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0 -vj54d2pkdeqvcuj5ykeggr6jnhhnmq5q6qe7nttvb6yjetweadma.b32.i2p:0 -vlwovj6fxzvtsypnmslocootmphezr5txanyfz2gjhn5lanrn2fa.b32.i2p:0 -vmatpbu2vf5p76k2emzg2tjyqi6p6yj3cl4z32ncdhz37ubprkha.b32.i2p:0 -vmbyttxf6sw6ivdamftxung44mktqb4vphmm4lqzdqqpcmksterq.b32.i2p:0 -vmoogdd5lztt5wpzkwhd67uwnvpupye7ycsbz55jl25sueowcxxq.b32.i2p:0 -vn5rsr26rp7yxrqliq7vo4zb6aoichaybd3urvc5eedaspxjp3la.b32.i2p:0 -vnxjmzogakc2a4xn5w4qormiqt5khnjptnoaro74ehinrv4q3yga.b32.i2p:0 -voi5u3azhajnt7476tcikl5mactxcvtsbnrzixwkj62qhpaw5ujq.b32.i2p:0 -vpevx6tl6ma6mnlj42d4fke57en4v5r76yx6rcmhtvw47guo34uq.b32.i2p:0 -vpmkctqhkdqgkekt72srqm4sqaliug37uq2wp2ywady3p235cpaq.b32.i2p:0 -vptzpxba7oys3w2htjgh4uxogaedursdh2yz5k6e7yh4b3pokuna.b32.i2p:0 -vs67sj5crkcjo7m74tdunzefj6ahgrgohs6egj5jxmneszwaoo7a.b32.i2p:0 -vuqk76jvxfk55bkovqcmmkvycmndee7j3tuv7ezdb2slrfpjyvoa.b32.i2p:0 -vxokhkidetjp4tjrj7idojx45hguhnl2azvqnbulougvdkstf3ma.b32.i2p:0 -vxs2es6f7uw2uuneslb7ipvmg6kqh6ytpjezoj2ptwx7od4jqmxa.b32.i2p:0 -vziy2cbrbvliqpi27feak2hiewovxtlkqppsagtaxeib6nkonknq.b32.i2p:0 -vzqowkd4aoyekapcskylli77aj3e5fomixsjyiawnldzj6c5nxtq.b32.i2p:0 -w2a73mo4grdgwvkzdsh6nyutagd4bmywywacxviodw7xnof72aoa.b32.i2p:0 -w2mgaza75amrvfocl7wt6v7eimprlasuj3bi4xezdr2wyqhkxzwq.b32.i2p:0 -w2zi3xos4jaz3ft5yca2x5zf34esctpmzqlqpdrqntjmi2o3gfba.b32.i2p:0 -w3hyqnlueb4yv5lkzj3wlnrjp7fzpxnig6x6m3w5du2ptfjcm2jq.b32.i2p:0 -w4arykcvc7eckzuqr7kvs2njsjpknzb6vvsodpyzp6tvu27bzoka.b32.i2p:0 -w4k4gm3chiyskfzshilxjchpgtpx2xmc6euvkyzkyjvzvdbqroma.b32.i2p:0 -w55r4ykzu6qt6uhp33exqbqmlt357cts2u2zoi7hkuphqmv5iupa.b32.i2p:0 -w6jl2gubyscdpubizes5bp6s42cito4k27xwcjwh76rvuik2prha.b32.i2p:0 -wacfewi6ehmfxvftxqmracfh7se2t7ozl62u4hsuyd4c5xfzuajq.b32.i2p:0 -weidpvshind3dnblwtb4zpssazeenkf7a63favavkc4crhqdk76a.b32.i2p:0 -wgrbhqemtf7qu4c6acjicb7uyee6rlinafyysvxc2yocq4t2ilca.b32.i2p:0 -wjfukwyohljaxgv4woewdtpoxi3q6hnwcnefpgrtif2kqfrxslnq.b32.i2p:0 -wlepjf4lxs4e553rtpoys6kqp2ozcv4pqjwzoybawcl3zhrdvz2a.b32.i2p:0 -wmly6cz5j54w2g2gibnhlpvuhh3bky26cq3a5jy6dp2hg3hc34oq.b32.i2p:0 -wnp26nyphqfmq3udocgcwenpsgfwk4ssw53st4wvwt6mwf7wm35q.b32.i2p:0 -woanasilvwu3yfurvhvqj3lxd25bzj4fxwy3ef3qjbso3cozvyca.b32.i2p:0 -wpnewole7fofvwvrvkkgf45sgcverlodocu7fstm2axp5jfykraq.b32.i2p:0 -wrqu543ssub7kiwzfug4o7m6lc5ibmaamdc3o4uo6a7ntxiqzd4q.b32.i2p:0 -wsbf5tpo7ecsafusflyym72k6tbyclgvqav56qafvyc4j3spzdoq.b32.i2p:0 -wtfebbwmsxoywu6nw5cowlxqhtokxrxftve2zee6flvrpqg4j6ma.b32.i2p:0 -wtoh5v7xm3wx4rqutbyvqaixybwlprx5ua2yiv2gac3prria5emq.b32.i2p:0 -wuikfwkext6lbl6urhoysr2abcyff5lkm2ojr6mfenqq25nzlluq.b32.i2p:0 -wumjwpr45uhvtggq6jkzfda47e4iqk2onizw6vn5po3bd3uqcduq.b32.i2p:0 -wv335vkr73gsaza4t6foqypnovccubvwfsarkmw3xtc3t3sncmya.b32.i2p:0 -wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0 -wwbojywnrcf2mci7f3zgbomrukcm4d3nv6pttb3dohjpge2sz27a.b32.i2p:0 -wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0 -wxfs2ccar4szd66dlmlijh3i3r4muehqjxjmabwbb46cq3gpbsoa.b32.i2p:0 -wy2udklgydh7iknnffbzvldoiwsct6dy3o7fjcsjcdjoq4b65vha.b32.i2p:0 -wzui6sc7667w7aabs6iebiex47o7cysxpryfdaltaklw2z2xgtuq.b32.i2p:0 -wzvki5234ffqhri26fqoxosqq3xengl23eoitkvip4mp7aipo3lq.b32.i2p:0 -x4cetuarbwiqphebitvgv4x4kzh6yhyyvu5c4yjlm4jsyl4bvs5q.b32.i2p:0 -x5qtgyzzgkovoko62l6n54p55xma5pbstbp6t6xc6hbugxz5ck2a.b32.i2p:0 -xasewpiqpzhyggxwsajmnkrppi2ozmapqv6673zuuymoueq67tla.b32.i2p:0 -xbetybs3nyeykskasolpatj4qrfnigz7a2bx7wcsyrniqd3usnaq.b32.i2p:0 -xd2byhr22rqkawocapbxedovmifyk77qrh6br4ctx7ny26hpmusq.b32.i2p:0 -xdoonpwnxhr7sjoyca3lkqsapmefd2puyar22ztocod4drjju6fq.b32.i2p:0 -xdq2g4tkaukzcu6mnvdukchinma7koi6c3noflpjabrzjrgeumfa.b32.i2p:0 -xegcohfrnnnuz3hdmb7r4e6pzxbmtg466n6mty2oz3tcoqutxj7q.b32.i2p:0 -xfyzfugo3qtfpq3s5zccbbqrxfkgy3ttlqhz6t6ovmtgrsuyce7q.b32.i2p:0 -xgbz5vpek6vaeej2zejxrjloqg2sqb67gim72qqpodqfq62rflvq.b32.i2p:0 -xgqzxudkvgbqwosaha7zb26jgza5wb7m66727rk4v2zj72xgg2ia.b32.i2p:0 -xgsk2huqghiftyznr6llr6ztepo523hiwqscxjpawcbme7xtjrta.b32.i2p:0 -xjebyiaydsbb76gqzetsmccgh67oeaxt3c4mkwmt7gjlfym266ea.b32.i2p:0 -xlfxusgnzpmatutaredcvx27zoiecno4tpxm52jicdvn4sr5dyya.b32.i2p:0 -xm55wnfhgmsy4wz24swjs2ziguheut6y72kht4ytwyfdmjsxslnq.b32.i2p:0 -xnb3pxtmai6ofbarycclwwueaarn4r3zt3zgkeepo4pgmswqvfcq.b32.i2p:0 -xnvsgbonlja7cmeokr2msvdelqlasbkwgqndqg7eakw43t3m465q.b32.i2p:0 -xpqubs4ftu7ym4xwrirlz2e36gvyjkil3chvq74bj4lf7djcrw4q.b32.i2p:0 -xrrx2rcpj3zefshtt7kamz3uflnwebpv2gkgd6vlrdazxgln57gq.b32.i2p:0 -xrwuqylcgkr2ovsf4pziosd27ywd7pfaohnreoyzm72qlnvoktrq.b32.i2p:0 -xtxh4wtmbjls76wxnehe57etubuqvsdiunwgve6kwjt4acwswnjq.b32.i2p:0 -xud4fgmeq4hl4cgsbjn3ubz2iyjguogskn7wreesvpsm3ib27kpa.b32.i2p:0 -xuivvnpcj2rhsxmkyyjzmyq6a7gwgusnqwdklgimamvkzu7rnnmq.b32.i2p:0 -xvpzaqftlfx2etqys733mndm7jr3l2j3if3wskfljzaow5s4rrfq.b32.i2p:0 -xvtvmaele7ns725mjaowsajpx4bgfecburyh6pqmdnn37cq7cs2q.b32.i2p:0 -xw6ble42juwkfrjetb3hmk2ep6jnyufhutoenyrou6ieoqiomw4q.b32.i2p:0 -xwlkpubkvsdsyaeylqfmxfk43juk6sz3hxnmwe4zencjq77aznea.b32.i2p:0 -xydzqrwggskdbmeqrhgt6alroglzbkcarzdlhabmvrszm5u6cfuq.b32.i2p:0 -xyhlemqmoeusqbbzr4oqph6kgmvm3a3lrbuanxkmyetwohxoynna.b32.i2p:0 -y365lf3vlh6vg4rs6trnjc4ia2xqplahk26y3tyqjly2q2vpfnqa.b32.i2p:0 -y3equ2tc6zsxqtndugsfzottuenfgxnl7eqgadmnzjkoigxvseka.b32.i2p:0 -y3occl5rqc2mz64esu5mqzoyfzlbxop7tttf2b3gyxjust57txfq.b32.i2p:0 -y45xhqkb43ncokfwhsmr4z6fwykuit6o3p2kbso3emv7stpiwwoq.b32.i2p:0 -y4njm6ftdn562q5thzd3fvb2f5mbi6bglmyupukcmcpt2tuo6slq.b32.i2p:0 -y5wr2bw3rt4rvw7hqqj7qtlf7vdds6zk6cs3mu3myyduasieqoka.b32.i2p:0 -ybjgylnhvk3fzyacxvyh6dwvrh7lk273qh5qws7uquvrhhwr6rka.b32.i2p:0 -yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0 -yemrkyqmjzwwn2yast2ga6dcnsovnxwip2rjpid56grdg7itugpa.b32.i2p:0 -yfplj67xwcblbiu4ozddmzlmjl4ifa7bhkzzu6fu6jkoyqui6v6q.b32.i2p:0 -ygtc5m4mh3qhi7tct44gxqbenhkasp2y4ydjn5qua4l5vh35osdq.b32.i2p:0 -yj3v3ocgldnackxptsjmwasa4xzxj3it6rtuhmlpxvwlq5kmyytq.b32.i2p:0 -yk2srkdlbm7kebv53dx45ss7q2fjcy56m3gywqvw65eya7co7hgq.b32.i2p:0 -ykppjmwunzqzuuqc6qqsijomfzdgieeq2mkidapc4awrww2ninbq.b32.i2p:0 -ykv62rivlxurq2wkecagzs76tulfor765c237bsjn7jt4436kn2q.b32.i2p:0 -yllvqk2utimxjtoyzk7l24s4n5sqp5dbn5vwsbt3g3dd6h4dxseq.b32.i2p:0 -ylpyfcs24ij67dkl7ighyou4z2gpfhjlt2iellj2ad4ddrxci63a.b32.i2p:0 -ymo2cnldmstzqlsdhx7kurii7aaffrhpgafxlli3s47pzbfe5evq.b32.i2p:0 -yny6zqtb7qve7wwfctsozhzhbq4hyitlqco4uhc5q3rvjex77oaq.b32.i2p:0 -ynzhhxlieigtmj6l7f2dq54ypnsaf723au7o3uhnismlgnkmcqjq.b32.i2p:0 -yof4yvv4agwhfmicj5u2drem47nvfkihnp6bil7ocg65gydyzzcq.b32.i2p:0 -yojuyryq6vfoy2mftrdmybmq2hjefuzrwmpqqfvk2kd5hptgr3qa.b32.i2p:0 -ypbq5aleoqqoxto4tkxlmlxh2hrstjxzpgonj3lk7dzweahs3hhq.b32.i2p:0 -yql2k4zjl64dtybuculjgg4v4u6sje4smnyay3vslv7irrigzxka.b32.i2p:0 -ys36rtuedg44sahelbysqi2mbc2l3rcfdy33zdvhvfkx5uocacba.b32.i2p:0 -ys7np3pmfhiyq3z2rcoeylb7agfbyfuhhp7ky2uzvvuzswad6cia.b32.i2p:0 -yuqb55drzrhxfnvobycxqau47kibaaf4voamk3kxl77xbb42xkqa.b32.i2p:0 -ywfauauaekbrxgwaahcjzifemzdq26xsshw54sg4bpr5z74scwiq.b32.i2p:0 -ywpsgu6nlnf2l4sy44tit2av7hfzwwttbjvwbtsbtqur3awiax2a.b32.i2p:0 -z34pw5tlowwi3gpj3ycb2dptgyuq65bpj7w36xahslgikggo5eaa.b32.i2p:0 -z3j2xshl4tpbxaybcprhzq7cuz6urboqoxvvpnfriv4n2lq72jsq.b32.i2p:0 -z3pgyfiwfzcd2g7v4rs6el5tvc55y7a3tai4gcbpso6flaejckea.b32.i2p:0 -z6mlyrxcjddpcaoumxnw5peulnkvj56hgwqmnc5adoutp7piujaa.b32.i2p:0 -z6xsstyq4zynzvagwv3wr7htz4vxttrotzb5izefotlwqm7kjtua.b32.i2p:0 -z7cjxpy4taui2ka3ekfqtoumsb7pg2sok3wfey3m2roeuppcrzhq.b32.i2p:0 -z7cjzfmv6wadjguzaavu7pfsqhujbczspbf5sxxrqndeovu3lt3a.b32.i2p:0 -z7gkesbkbl27lpcpbnhgfofjz5fhnvljzfvyydu7ky3odzdqs4lq.b32.i2p:0 -zafd45c2hzd4w2t24qtjqqbqm3z4hayb6vadj6sd5oukjyij2ara.b32.i2p:0 -zbkqcqtiiw4nwsds5pjel6alr5i4hgiyqf5giwurdygfysacru2a.b32.i2p:0 -zbz722dh7rvu6ugdydmlmtgfyc7rnpeslae525c7mhr7rgsekjba.b32.i2p:0 -zcwgqw7hlw7437a7au6n6obljdb4arnshoibdqo6voree4xiznoq.b32.i2p:0 -zd4ns4zcyvgpwkioftiiftgj74n6mf4m4ieq6aedqaznmdi6rhdq.b32.i2p:0 -zgwseerxwqnid3zhculzuqbkhghthsbvsbnqowredostfqlvawsq.b32.i2p:0 -ziehuxdpyg5dvvnzedmcqxszdcflsrx6fqmgzb7odefqwqaxrs7q.b32.i2p:0 -zk2r7kzzigzu5kz67xnrbe56u5walngylcsk756bkmt66cmeeydq.b32.i2p:0 -zkbjgfp4ouockpsmpbdyli4ilo7f3lbfjsboay3nf47ymir2ldrq.b32.i2p:0 -zki6halesukhfel76pziutgica4zrp5qtbmlmgyqf6dnnomk7hja.b32.i2p:0 -zkij473aummp6rvwvi7wbr5iio6xu2uh4rophbhyot37uxhrygiq.b32.i2p:0 -zpvqqdrcnagad5ayutf7hkp6prtvrbmknhqdul3qweft7oa5ikzq.b32.i2p:0 -zqft7c6riv7aux62qwe5xfqki3dcb4urvbfy6m4wz7f46j2us3la.b32.i2p:0 -zqhoqgf3enj2pv74sjov6dthpr6jqafw5qqzzsvnfdqzycychxpq.b32.i2p:0 -zrrki54mn56fytizkfmhx7eubea37padxa3zliwq6gtknrsxv2aa.b32.i2p:0 -zsfpcnbk4g2bwxl7yy5ebrcvlxd5gpcxatewdrgpige7oqykunwq.b32.i2p:0 -zszq7enaxbz5p3f3idhfkkd2u2ygpeqwj3o6hkofffcmllnymwqa.b32.i2p:0 -ztr3c7qz6v4hrnegmkzjsr52wyi4u6ery4m74sk3m77oup2ws4ka.b32.i2p:0 -ztyxbjae7ucfyupxpy75jwpzdktg4gbvhl43nh2crwqrx2uhveda.b32.i2p:0 -zuamj63ad73jmnw7xnxrmjsbjg7vg23j46w3mpc2udpcgjfkcqcq.b32.i2p:0 -zvchlrjuzqdlx37fhibhnym4y6p56vtlymujjuzhh2cp34yqfrtq.b32.i2p:0 -zxsd3fqczh6ddgejc24nnmb3ww7nalieq3a7cs2mqiy6tmff3wia.b32.i2p:0 -zy2ywvyqds5bgdoo4tgbu3bwjp3ygyn3zfuby44jemc6xa6fbwta.b32.i2p:0 -zzre44vh766jgfordw2ehu2r6p44j23uyovgvm7iwuhp3g5iz4ca.b32.i2p:0 -ycdw2e4ufgfwhcqna4g3m2qsvaly23ozaexawcj3x4gtgcehgwujjgid.onion:8333 -ycfvedulkprd5bmivqejur5aptcs47daqtcvzotnnhfvwu3o6gcp5cyd.onion:8333 -yck6l5ffw6oszgtoc7et4fytvp3sqdf5awyky4tlpgem2n4y6icxqoqd.onion:8333 -ycnepnzktkhfysqijlgbjk5awivls3eiqb5kjudotjvnvlbe6ah2k5yd.onion:8333 -ycwrrabomoixkxggkxldyxkqoc7qqy2t5wxcsxjgodlvuydwch6dqoyd.onion:8333 -ycwwrwkqibvkftpc5kyqs6nf7hrzetrmqgwo4yae7bq5otvubkfsread.onion:8333 -ycxjdh4jr4vun447cdszcoge26pbdnqblfi2osmk5e4uqmrigw7y4byd.onion:8333 -yd2ami3rem3i24q2b76l4ujyq343ycrowrthwqycvpcsofgpwlxyryqd.onion:8333 -yd4nyusqking6tkcwmmopznlxhyfhk3gsw265alz7vpo6toqg3kwn6yd.onion:8333 -yd6b3wtmu6bz5km7hw645omyv65one627xech7f3vnlwkblsvqdtmiyd.onion:8333 -ydforbx54mnz7g5u2mu2ulkomvakdbwxoad6araknijb2i47gkfeh7qd.onion:8333 -ydiqekqpcf536w5uwsdclw5pt4n2fkz52fo4vwdducc5t5l4ghqaxnad.onion:8333 -ydl5kqr2auvie5mtjkm37hzkqh43pobibty4msfzkbu4junpg5gak6yd.onion:8333 -ydojumivjpins2lwgql5xaywbngrmw56nvmtalvfiy7sr42ksvr6apyd.onion:8333 -ydvbxdzs6w5wefifiqsqntpbd7tliofenqih5hlnz34546fvy4ab7iid.onion:8333 -yeat6ea4esvd4nimhg2rcb3ghpusoqzjb44alb3hhdj4d2nimn2vpoad.onion:8333 -yeficzguf443sojjdcmh7lzk7l6y43a6v2jbyk3x2w4n7xokjs4crnqd.onion:8333 -yefjaylovpdhbb5b5bhjx37digt5u62lmzyc54ygtabwdphm3zwd77id.onion:8333 -yeghpcuryadlbxzk6o3ujebmfuumkpoi32dr2ctfmql6vqn5wjioehqd.onion:8333 -yenw26f3i6kf5u2nad6xligxk5iyizjvl7msx3pzjcatiesogdef4zqd.onion:8333 -yeoadueo3ukf6s3fetywtbvgmpvrtkja5rlp7wcp4aich6tfhh35giyd.onion:8333 -yeqjrnnuf4fbgzik74qfhrohcymj7ccbze6ndky4pe673chfsjconfqd.onion:8333 -yernmfgru46g43vsijjv44n7m35tpoznnkd2p2wl3uqzkietukxqxoqd.onion:8333 -yettfzp2vanmkehwxeaugotqcsg3wsomcargvetk4nhwnebrpq7ah2qd.onion:8333 +[2a0c:b641:6f0:193::]:8333 # AS203394 +[2a0e:8f02:21d1:144::101]:8333 # AS203528 +[2a0e:cb00:700b:0:cb0f:cba:41b2:28b3]:8333 # AS60377 +[2a0e:e701:103e::4]:8333 # AS2027 +[2a0f:b780:300:1::2]:8333 # AS49095 +[2a0f:df00:0:2010::162]:8333 # AS41281 +[2a0f:e586:f:f::13]:8333 # AS207656 +[2a10:3781:2c19::1]:8333 # AS206238 +[2a10:3781:3a73:25::25]:8333 # AS206238 +[2a10:3781:3a73:25:a177:ad25:b14a:176a]:8333 # AS206238 +[2a10:3781:3fff::1]:8333 # AS206238 +[2a10:3781:84b:1:8002:99d3:191f:c738]:8333 # AS206238 +[2a10:c941:100:24::2:1001]:8333 # AS35277 +[2a11:d540:531:b00b::5]:8333 # AS207586 +[2a12:8e40:5668:e40b::1]:8333 # AS45021 +[2a12:8e40:5668:e40c::1]:8333 # AS45021 +[2a12:8e40:5668:e410::1]:8333 # AS45021 +[2a12:8e40:5668:e412::1]:8333 # AS45021 +[2a12:8e40:5668:e416::1]:8333 # AS45021 +[2a12:8e40:5668:e417::1]:8333 # AS45021 +[2a12:8e40:5668:e41d::1]:8333 # AS45021 +[2a12:8e40:5668:e41e::1]:8333 # AS45021 +[2a12:8e40:5668:e422::1]:8333 # AS45021 +[2a12:8e40:5668:e424::1]:8333 # AS45021 +[2c0f:fb18:402:5::3]:8333 # AS37199 +22pz2giqglrjahnebbeedjyfhmy26wifq7d6wnioioqv3kbctddraead.onion:8333 +244f4ods2jyhxjbzmjoo74hvdgzxkkf4xysnwlin4b66zactsve44mad.onion:8333 +25l62iysmquzrl2xgocvipsb2qhwxizahgfo55ssj2ducahghmc4rlyd.onion:8333 +25nwqmtbqicqrprsfv75tghg432c4viqlps7ov52pb2uj2u2w4ek2dqd.onion:8333 +25zmfaqaki3f34pwra24yl6eqgsrhmcxwa2vjbfxzddgalegee6e6sid.onion:8333 +26jfbxrdnsbxlai7qonraijp3sa2sybizmx75ry6dyr3s3dampmwufyd.onion:8333 +27nda43gq3qie4mw2gscszxw45cktlkzb2dsehanwqrv3il45bc5xmid.onion:8333 +2b5myuudry2fc5abwur67yxenqkjbp3gwy4xkxly6elurxwpq6my6pyd.onion:8333 +2bu7aca5dslx53okedetkovivsfzgjku5krxnxv6jcwpovrqceyktgid.onion:8333 +2frnyqoym5gqwo7px6blri2p6cqxpqwjz6fxtruwbo6hcfbuh7r6qxad.onion:8333 +2g7f4dst4ga2mwtavj3uhixhwtktas53rutzhf3dl4lkeb3x6i7ollqd.onion:8333 +2hyo2nphjdhk7srnkj722pnynbtd4qcu2kaqqsqfqn4du3qi45ydkgid.onion:8333 +2hyxmlakirtpgbxmyoylskwm3q3p45rseqz4bezpwocx5zk2rzgdsoyd.onion:8333 +2jnduapgnsztxqlw7an263mjjrd2hh2okgpg6s4pxltkwsawyfrabvid.onion:8333 +2nbfeuyzysqhw2aawievujdc7s3pvri3gygufownc73pbbq7pwoa3aad.onion:8333 +2ockgj6yxkytfiup3rlutk7j62ttnvndivrsqq423gi72bg5puqyacad.onion:8333 +2oyz7zkpukhlodz4hcdsfkb7f3tdopyk2h65nwtaiviuwcv4lku53myd.onion:8333 +2qmfh2ay6zvpvvsc2fgvcarwi6ny7voht36uwqzh2s2lckktxde663id.onion:8333 +2rpqi26jltpqxghloljkfvpywqyiztklvqe2j6g535ct4qc5cfi6wcid.onion:8333 +2rpxcrfxrtdcs7f7kdba6j7r3ej6k2xiwcrbbncvuyo3dms3iqscadad.onion:8333 +3bzy4vmqovhimund35clac4tx3isy4fzpnqq7chzioktr5in4a246lad.onion:8333 +3d37tkrobqlm74estbowv34vegntpby4o35f4cp4adopksrhvqpbgaid.onion:8333 +3dxq5z3rmhzhr5jaaiwzn34dlxjashwdfyezp3pxi2bokf6ljlrysuid.onion:8333 +3f44ddpy2c6wytq37d73ro7j3hl24njgmkhknxyekd3nfi6fi62adhad.onion:8333 +3f6x3accjzo72tcxf3fwzotwt2wi4f6jqimuodd5td3tkla7tvs25lyd.onion:8333 +3k5pwv5mqjo4cgekyy2ncv6ioyduqudk6gjo6rq3ozdqatgdma5n2ead.onion:8333 +3lurimig54ozppuvqbh5lorxcm4z65l6ybyrst3ksdjfioyic6nms6ad.onion:8333 +3m4o7fccoizgqe3iybwetbqtm3vsb7dpoodgd5gtanyxz7g3usg7lgyd.onion:8333 +3qggxbp2bggve2x2evcs6nynoaxryuew5mcr4llsknczewi3occ7bqad.onion:8333 +3sap4vo5v42zf6uvbeoxgj2tmqwfxnsm6lltrcexhed7zbi67rvkbwid.onion:8333 +3tofha4w7b7y5amgwhj3hssjr7z3rzrptlpm6wgzgkrruqw4jy2msqqd.onion:8333 +3tpbeteemou53yfzifzbbmhgq7avlrumtacstk62hlukw4vgt7ip54ad.onion:8333 +3wldmps5hoxc76qff2of3adp6fqda3vobcenodoqwwn2grlgsnurn5qd.onion:8333 +42qfhqoyebkpddesxi7zbm3ujcfzmattclannvkdp6g57gkbg5l6nuqd.onion:8333 +42ukdi6zsgq5hcf5d4b6xxdj77ffismhz2sm7gevibcnwhzfgunluayd.onion:8333 +47u4lbj7qmyllkxj3jbzfjoag4z5yiuoypsyp4354aprosmunkaszvyd.onion:8333 +4l2kbv6dyaghiqrzcuylzuhwjcag3vbujr4cre2f2f3a5gbf7s2t3bid.onion:8333 +4ns7eu3lxa3b5zqvajvzrigo24ltbjmeiqm2parheihatd4n6mqkbuid.onion:8333 +4pm2bfb3aekl3lkpf4rhjjbdnfcn2xcnqkk4de3pz6ekvhf5ym35gjid.onion:8333 +4q6xkttr2vvycn6e4uw55feflsq3oyrmazn7tfz45yxni73yhjj42jid.onion:8333 +4rf36sj773fhwxbq2smywp4xkpdxviy6azro4epcl5vtjf7fsjn5c6ad.onion:8333 +4v5mywuxbpdqyfwwo4bvygbqyvne27ekguavq266ap6o75jbcjlme4id.onion:8333 +4vp2psi73qfspc6neodpxoxe4hexphfzq5llosrah5gk4njwhn7hzlqd.onion:8333 +52mfjouhwxf3puu2af4dsoksjfhnvuf4mgpkcblw6gdmsjgrbprxyzad.onion:8333 +53bpgsfyljzx5uztq5zu2ybm2oqjiba2ecmmcwjqz54fslxr2j67txad.onion:8333 +56ff7zlhr3slha3d2f62iexx7gn3jxrjvkb3e7nx7u2jtnuc2s7xxgid.onion:8333 +5bxpoorrgyhsc5746rg4advtjmxkpfwo4vhokze7xv7vcaa3anetujid.onion:8333 +5gikcukg56x7tygwtjpexvd7ca3mihjptzfrcxbrlh32veywo4lr6tqd.onion:8333 +5kggaeljugzw53t7mirx2hqmscuc5fab23pfg57mivrbww3pe5corlid.onion:8333 +5ngcxrrpkcciev6uagutm6zjoi7d6l3nlhiktii3z3mhzpcb5qkiisad.onion:8333 +5pia4po7brgcabehjypingeufxwayoj4min6jga5qyzacn5lp4c2cwyd.onion:8333 +5pmr2qluaafemlifmsrd3dtxhgtzkhc2u7kpszqvl5h3lwb54jmnloyd.onion:8333 +5sl6ffjj3mecnskhs6ltphzq7z4vxdhfsm6f7xv4fmyqjtqlbzz6evad.onion:8333 +5tm6ubis2atpjieggptfit5zk4dnmoewcclj3gbjfcpnosywve7isbad.onion:8333 +5vikh7wzmyktdbj4otnizwsoetpq7t3swag526lvvyzw5wjmoijx2uad.onion:8333 +5vllnjopzyhmlfpsakb6vzqr4fpgbqeilcurxmi5ktamtvkhqduc57id.onion:8333 +5vpbnwmkqjmeos4qfta5o76nsui4iissafgzl3qdktmsznzbe33i7wyd.onion:8333 +5wcgiu7egpkqpn66vy6dz435r7ovqsp2y7efpjy6nabb5bhtnigvj6yd.onion:8333 +5yenarpzihhwz75lbcrt22wj2qtql44k5pzb2tyev6fxlbpzmp64ytad.onion:8333 +5zi4cuchmzuwnkg6li7ith3persinyvomcuch5fmxyuzt6enf2c7maqd.onion:8333 +62tw7sc55265w2sqhhkbncoumgxbixxtkakiuog7zcqyug7iebbxzzid.onion:8333 +63cquq2e3gpcgfti5pettx4sbg5tg6xsjl7neskl2w6wnqgik6k4koid.onion:8333 +65jiaxxehmakn64nsyeax2xk3dqkegohu33fi77gjhukzw7dm5urwkid.onion:8333 +6bzt2mdeo6afhflfxmilnhokkvw6edxue4lgcdvjib6fn5dmy7hx4tid.onion:8333 +6hobuesgn3fk4b6xkkgjj4yabn4rdkqxhor2yg5sdflprmtjjuo6n6yd.onion:8333 +6irbiwo6m3vyooxia6gsyxvx5cxufdpvnb3pv5wwy4eoloo5dmah3ead.onion:8333 +6jya753mqzrkmgkop2nyx65cxqfoup22mdapj5tkk6gqwh7m6zej5byd.onion:8333 +6m5667klqvbya6uqnmcqspo7aeoreozcipzzb5f222vlrjhhodronyyd.onion:8333 +6ovl23cbwhc2dpm5rg4rs2xrqg7r6v2d4btsvs6teh3j3fwi5y7drvad.onion:8333 +6q2qwfnphyov635sq4j6hiiy55wi4ode5jbcd6wociu4t5cn7mm52jyd.onion:8333 +6qk6btc23vtuldtnnmkvrqvmzcjpoullfwdmnnctvlvekxhkdjlsobyd.onion:8333 +6voevyc6f7ng2axpgzw3irmu677os3b6l65ljhuozf7hfkar2fpbxxyd.onion:8333 +6wyq2i4gsjvidvz7umsdnwrgxvksjs7wqvvuf4zdjxsjfjwg7wil5zid.onion:8333 +6znucpvx7k6zasghyu2dqfp5thsrr7a56cdhb3yqoagre3uv52od6gid.onion:8333 +74oj4sd4e5zf7mub55pem4kjcqo6udugo533mlnahxmx6kliwmhurkad.onion:8333 +76yijbvce4sblwgr32q2se2hakcbxesccnzjmlpoptm2d2txmsepd2qd.onion:8333 +77xulqs6goaawmm625koq2jm3uhnd5dccr5cthgins3jpuywncq3unid.onion:8333 +7baui46dvqf374kpi7aaffa7xnh36xndc5mjmqf4kzbxcuuxa5ojlaqd.onion:8333 +7bjwdnx5umef3bchtn4coz4qawx2st4752ckrmwqr27ueg45w6mouaid.onion:8333 +7d7kfcywf53obtguqshs344lgthjac26hndditvodqlh5rocy3cjplad.onion:8333 +7dje2pijmwanoj5thrg7xmc6hfsld2tgrrknsuem3dfx2l6o4f2cdoyd.onion:8333 +7e3rx4potc2rt345yeathbegxnd5pknju7iw2lwi2cz3ap5onnk3ktid.onion:8333 +7g6vpzfqmzbx6cbqu27euah2ync2d35wfega5uco7xq7ywrkdsjtlxad.onion:8333 +7hefggwwkbpyxsq42idogvxpfbdayayf4vgiteog5ekthegmy3dl6fqd.onion:8333 +7mlt6sj3gcjoo5jpf2ctc5ozvljizu6vw2cs2dw3oyzomeaoiw3uqcyd.onion:8333 +7nnpzpyfbqqzpmmfen6w6y7gr22dey25zvrav3icfmlyb2nfwxticlad.onion:8333 +7pyrpvqdhmayxggpcyqn5l3m5vqkw3qubnmgwlpya2mdo6x7pih7r7id.onion:8333 +7qwkvlpilk5fel2biif4nstoubxdedxirvqujcyptxgy6bf6dzsj5kyd.onion:8333 +7r362setmugzrgptpjz2cgzm7qv4nhx3r6dhbabki7xsv4qqwumzz4id.onion:8333 +7r52rv5epyoq4ni4qhqxspnfyajxhfl6rynw6c4a2p27r4vnq64nizid.onion:8333 +7rpz563sgtfza2qmaj7ltamswufnmdxv72vcqloxfksmfr7fudjsuyqd.onion:8333 +7sm42kkqswwp6axdpz53ssefbmgrag7exwiis2ifdg7wfio6bxnu7cad.onion:8333 +7twzyh323ott7mpbo6y5qkyk3eugwitnsgwkxegqfg45u3crxoa6e7ad.onion:8333 +7wakp4xjxksgreekwjeonul2gj4omcn67g2qkiazfq44hgqit4z7rryd.onion:8333 +7zgfoegeed6jotgmuf2wkotbb2drdkuk223v3moomc4akiuy3yincsyd.onion:8333 +7zlknyoxay3rbdb4bj2zdsnagldpzjlzzlrmwihpb6yutklzqkhpwmid.onion:8333 +a4dkz55hsbef26ja7bz2tfsvlgjigg55ocnhycxq34efwpuzgtgfwwid.onion:8333 +aec4fcjyfr5g4eqsejmvc7t3eit6nbnv4voxnykmw2orn2smhixfrfid.onion:8333 +af3uv4mrxrqenu6a3kbfeovapp6k4v2p2ymxv44jw3i7szagcmxf3bad.onion:8333 +afn2rl2wdprisevyhxea5nrbflt3vwdh5crg4hqb2c4iukaxdw34j2yd.onion:8333 +afseqft4jxpkyeiz4c6v57nxwttwte7r4xas4lnkuxckfn4ohpycb4ad.onion:8333 +ahwkawuxyowyesovtvriaghqdvud7ksy3kt6rjhkcadsff5rllpnjtad.onion:8333 +ajws3x7xec4kdoprrljsdsnv2grzqng7yb2p2mp4gm735hly2rdfatqd.onion:8333 +ak226w3yvth4s4fs4ia4rcdkhkzoyrkjk25kk34qgxeoglvuho7dj6id.onion:8333 +alhwf5hus5gfkeq6nsqxhrxlq3nxherufycamaf7xnjwpnexuf2mziid.onion:8333 +alsnycayqigth3b5vrjtftlowxdnkne4qmnqawjw3qmhdoig4spqlayd.onion:8333 +atygn6lucla7t6coygbfd62n533kashhwavubkiwz5qgjmt5nkk2vkid.onion:8333 +awznblcc4yvfocchm73gwgtig7ohxxszmwx5ft5rpbeno2i6fwllukqd.onion:8333 +azf3zr4ldr74nemt5z342melrvrffm5qw4qx4p47zfokwqupw3gxl6yd.onion:8333 +azvij5u6agee2dl2k7eh2eliqu3f3d5gldzxodoo7qtjfiky6ewufmyd.onion:8333 +b3jgrfpicqpymo62sdgfmvgk65gw47rhr2iywrusj2rfs3piwwhsboad.onion:8333 +b6fljee4jrarq23x4ppnwulldtsysqviknpgtdu5aizpkxomkgvtsxyd.onion:8333 +bacwevhzgtzgxvdkkwyvkaxsxwhkhqwa6hb3cvuizjsihwklqhslmiyd.onion:8333 +badjfbjiddjpnru7nemmscmtshyicdwmmj4tce23v3iihjh5tsu6zqid.onion:8333 +bap5i44uxcoomakmwcjls4spwh3uipliitfs6mfkrczdnsyc27gwf4ad.onion:8333 +bb4n3x3uacfdd4o7n6xlgomnott533kjjdrjnpo6ptbigpe5h26fm5id.onion:8333 +bbf7tqqbgnk5kat6ltxjlaxeruqeyyovbxsc3baucjar7aerlq6pv6qd.onion:8333 +bdrm5qxuox7ksubnmweootuxhb4v3qpvp7fkkwadavzqvgyputydfaad.onion:8333 +bgimz47rqq6nr7yzjaucrx4llfbtrytooxkpy57okjhubz6kcxlh6cad.onion:8333 +bipshow4n2uhgfb7my5ddmeqn3ysxgtsfwlzp2yhqg6ex7z7guzkkwqd.onion:8333 +blfpqvmciektsqzy46bse4mzyxpsb3dz4z7wpoufjr4d3tvzigtlbmid.onion:8333 +botxev6ve7ushdwdkbgsizb5k5ugozfst4x5ptsat3munr5eyqxx3jqd.onion:8333 +brlajuce7fehga3y2fq75rwm63ecvnyh3evsydyah62d5x7mzzmwbayd.onion:8333 +bszynsgeze7m5lknibgenz5rl4zcfel7lojxe6j4y6aecfttftowp7id.onion:8333 +bu2bpe3ucyws6fbzekadnbfdxjq4z3tqxsgpnvm36nf5tes3u37gyjyd.onion:8333 +bu3xgmjbtkfkk5jqy3ckdivwfgufefpc43yczszpriggnksbeapx3tid.onion:8333 +bx6z6hkku5ksqq66fuqrghbaz4bkw2qu4uiv4qxajfmqnrfejtmm44yd.onion:8333 +bzb74unsgxuv3wrkjzee4nxe7knmf44a3tbwsf5ljvfci7hjidmlflid.onion:8333 +bznwam37uhpeuodct2ppxkoe4h6xs37vjb64cpb22aiafh75vabqujqd.onion:8333 +c64xcctcx7aelj5yy2sxa7jinpi7wzhzzvdydr5aqllzu2fzgufkuzad.onion:8333 +c6fok2ng5z3jvk3bbujnprs2cl2htlfpht5hdethnkkfyfhg6wiz6fqd.onion:8333 +c6k3i4245y6honrsxfcm2l5gcnn5rlcatxzyyubf3kubhzdvgxop3rqd.onion:8333 +cbgpdxoree2eg43xmd4szoaawstbxqvo5kb23ky5bez2pq75k7vpi3id.onion:8333 +cbnuxupqql42wefzspje5wqkaauk2mk6ptqb6khle443attsannqvzyd.onion:8333 +ccwhslmsgslatdy37tsqn75ojxtweg3a66phlxm4o7s3g6byj4x4ghyd.onion:8333 +ccwupmup76qqjmtzuiv3hpi3u7akqte3d6wzuvee5spe4lcdzeldzuyd.onion:8333 +cfgoe62d76nn46h2dp7ut4oigb35kkphi5ghzn7hmsxly5qfijlpzwad.onion:8333 +crbqu3nsuag7y3fty2s2o6khgxl4k5wfbn6mguy2kvdbybvtbqzgkoyd.onion:8333 +crqe5di5puk2ehjiw2ruuqaqmefc6hwryo5cpicyydkxekdbzno4rtyd.onion:8333 +ct2is77gyqeckpqu3khdvzvq5bm3cowixixdlgadafkvdzeviwyrw2ad.onion:8333 +ctto73iocvgjkru6iw62a6hre4lubq2kluupye2dnp4raxr2urgu6oyd.onion:8333 +cy4utydmbvspzfbz2vdlzuuxkyyzhjuumra7klk6ojiptv7y6cup75yd.onion:8333 +d2mlhomjbqjxv6mn6xx3xir5x55jrmx37pz2swm5m3arctpt7n24kaid.onion:8333 +d4acgxoszymwjrjjcyclht2zzq47pomhavsafxiervejqyzipd5uxbid.onion:8333 +d4clcpzl66owm7t3pm7czb7zzgsqefpdh5plrnfypba7f2mikfv4u2yd.onion:8333 +d4jnim6os7bshrjgpfecsg4i2g3vt4azycssuqahiupsd7hwtjpfjsqd.onion:8333 +d5sd6yiuwt5rts6xghywihgxpbfih7rcrv2ubt5gh6nf67dfxq5g23yd.onion:8333 +d7nslqez2k4rhvxbg2kxedlzyoyt2g3nvelcniyg7xuc2fidtgstdwid.onion:8333 +damegzcogdp5lvypiy5p5fo6lfom5s4fvuwa2wjlm2cmsnhhpcadtyqd.onion:8333 +db5atsyx3n63dyc5upujumsp2b5jihafxpw4tp4k4pnlmbahilicaeyd.onion:8333 +dgezrh3kfcngsvufx5lrp6nodcshy2fs3w4ltalwt2etr4qvvylvrkyd.onion:8333 +dhipk4h5xsan2jjjfci2pljnyy3ip34tmuzyt2rh7zlmezzdcqesxnyd.onion:8333 +dje3novlozm5ceky6npbt7qjnf4emui6f4ygwfhhy57ddkasvy73bqid.onion:8333 +dni2rjvqe53gpmdr3ykhnsuiscjy655j6ir55uegdgiogkwz7cdgqcad.onion:8333 +dnyvygq2dmvevz6ajcf3asd3d5cqmpevo44qyt3km57nysyt75rpwlyd.onion:8333 +dqaeyhf5v4472dygabraclznfhtyytwy4hdvrjqarwij7qu375sidoad.onion:8333 +dujcffazdttews7bernuv7weox3asklnwuzqsdoyzqxy3logfupzwayd.onion:8333 +dv4dtz5zu3te3g2ccrz3nrgcfzozqesgmgtb5aozhkgonqwg3dicgtid.onion:8333 +dvzwybrkcynzfjg4jpckt5kungd4nsqbwylshblesuwzflvocm4rgbyd.onion:8333 +dxkkytqbvl4hhwh5i6u77rx2rkicau6dyygt6xewgy3apbolw6w4mlqd.onion:8333 +dzhhqpetvyq5g6xhgy7gkuwey23dso6sc7jb5irlcfs7cbfaec3gqlid.onion:8333 +e26a4bpxijuh4nmeqm5g6d2ir6h2cwyw7i7nroxy7s4yo2eog4vvd3id.onion:8333 +e4hdaommmm4y6q62g5jvh6mtcot3vhqj42wmopm32bu3etrdo5vbsoad.onion:8333 +e5mzbzdvpngxjkbfq76hdpfti3wirwqezugqaksprdctb3p3unw36oqd.onion:8333 +eaqxyujymqzwamyf5qtbbnvstu4sg3bv5umpkzxjbsaxamzfu6xbi5ad.onion:8333 +ecx4pf7gwdpllaf3sz6nseb42ojgp3cto5xo5j6vn7afu4spccub5mad.onion:8333 +ed4imq444il5pp5gks3yimgh3j7v3vh7qydzyzksvv222ebudoyvfsqd.onion:8333 +eheqmoscz2jqa63b47255pkknl655xkjbgwhpeuiryfrj6hkf4vureqd.onion:8333 +eiywuxh2hwhk2qalfvqtfvj4ljuez3o2d4deqmowabci4o3evmgjpjyd.onion:8333 +ejgeelmm62ygi6ruynkzt5trh7ys2csgvkxzct4qptlwqcdnpqiu7yyd.onion:8333 +ejrykyejku5dlmuz6on2pi7ysjg6c5puuownbytwmq7mvw6xyqbze6ad.onion:8333 +enc4qxoyoap5ndr7duevmjhv2zcpor3c347523yafo6ct4tzj457baad.onion:8333 +et2jf6nekem3x53tyzcheqo7ar73wg4by3ucvzyjfliul7357cei5uad.onion:8333 +eta57alktm4zhvh3avor2j5hbhdaelb3r7jy2hipraffsyp6bzo6ahyd.onion:8333 +etcabymwunkkvnx4fwghc47qf2qf4ix3jtzfhp4gohyhcdibg6sbeuyd.onion:8333 +etj2w3zby7hfaldy34dsuttvjtimywhvqjitk3w75ufprsqe47vr6vyd.onion:8333 +fbuvbm4kekb3wze6xocibjkxnkyj257ot6d52342bzvvs4uzk2ykljid.onion:8333 +fig7txolf3throetkrs2zbhev46rq2qd75zr7pdnmewgngmcseu4udad.onion:8333 +flgedyhmormdyrxqtayz65kpmgw4bmgpr6steg4r7hjixnjowdanf3id.onion:8333 +fliooz7kq6lj6es45jg32n66jq6myliqbnzg2iyusun5dt5tyxg7tmid.onion:8333 +fwykc7ow6i4o2m7vygmgfdkevyqvw2gspdf6lxrfhdemalb34dbkjtid.onion:8333 +g3rzugt4b4rv2yq266jeaykvbv76nnqi6735nghovcsnvyqwmfoqsdqd.onion:8333 +g4ojra3inm4l25p7zl263vz2lz2qufwtjwlehwzffi3vfruef2kfg2qd.onion:8333 +g5bsayc3x23fkkssptmllu2qn4kg7jkpcl4fx5edjbecojymiukikead.onion:8333 +g5r2uda6whsgs65yf7v7yoqmqokbkqiwvgwjigej64yskk3skleticad.onion:8333 +g5uuvidgkvdf2cmoekggzbifzbojh7dn75e75y7v2ig5jflkykm7niyd.onion:8333 +g7wnozndrisbuu664xzbwwzuui7b5xkuzfew3xmfmld5yw6ypswtpgqd.onion:8333 +gf6vyqezos2s52kxwz3itpma5wnb63ol7qg3kuwxg537sejtu5jnmnid.onion:8333 +gfoqfn4vlnzk4ocrwegqrgmzmfriwrzgnx7jdpinqkybidtyt7kehqid.onion:8333 +gkgud3alqw7vqywtawsssovmvkhslqr4xenrmrg6om6iljub5o2fh6ad.onion:8333 +gkvgggf5guqcygywlenme5ml7dgtkpjmbtemsblwdex6jv5kvpct6dad.onion:8333 +glp5z36juz4zfh7touj5tbchprcfbdptdhci7shyyimd6bbjlcijjeqd.onion:8333 +gotjkzjvun4p3etaf33p26vlwtmlceytyynsbgiknb4tra3snl2wigid.onion:8333 +gptcyzjkqzt56r4a43ergixiljheby53t5xtb7dcqx6hfkpt5f62stqd.onion:8333 +gpzwpzigfrhkyhc3l5sllo24duxa6ousnk5or44jsrtdj24dstol6syd.onion:8333 +gqcqsp6ktamk2wad7sy2quysxivgu3gjxitx7krpwgsh37csllx4xoid.onion:8333 +grkruzba44rm5m4gkyejjn35wxblxos4ba2vsi7ddzjub43ydnrjhqqd.onion:8333 +gx3hsyxf2jznihgprtkagqjnpwcp4hl4k5kde55go2vtfczh2t2zcmid.onion:8333 +gzte3h7x5qjzdbyibrprffzf2mzmhmkhzymq7zs4ksgwstdxtdpzeuqd.onion:8333 +h7kfqg6lf7v5dywswdzka2eepdyiqira6mamj6l7razuxejlspopleqd.onion:8333 +h7rors5zihhghcytr6lh7wgmioaht2bubslski4o3nas4lnqwq4i5byd.onion:8333 +hagkd2gq3v6a42lralbpmhpcjjlgfq6ledege3abfpwvj5ln7ydyciqd.onion:8333 +hakum7yuy4qpjzu7czyl5j2nnli5mw3fx2fxjcwfjs3gr5vkglrgs4qd.onion:8333 +hckgp7as2kephoosoqe42v2ibt5o3kgjeyrgcbipilxnuhqrhxmlg2id.onion:8333 +hg6syx4oyvrcraxytqymj2blngpwji5rhfbjnglo7tvzfpmc5sobdjid.onion:8333 +hh5d6gja23hlwmtrpmwbd7zn266zro43hzxjpwa23p4xnq64wibazsad.onion:8333 +hibgbt66hb4tvmhkmyzwlxirdmpkg2aa46xznnswwsuy3w4foitwedqd.onion:8333 +hl2fornwqseckgkkqpx2r2r22nstdg45amytkfkffcgnlgyayyodtyid.onion:8333 +hl5z56lx7zyq5zwqy7htw6w7skbb3lgrj3dglj46dynsygncs73meuad.onion:8333 +hlinnnjusoqzc5taurrf7oe2k3m33re66clnbpmme5ild3cebctbukad.onion:8333 +hlsihfuyafpoxchsrhlh4wdkda77iv4wmpnz2sgofonswq4kn6ns4pid.onion:8333 +hmnvzj67qtygqbe4uultm6gzhpwg7bd5auww4piraenmbqp54plzyqad.onion:8333 +hpieksjfcnba4js2rcuf3dl3igt2njsm54ztf4iux7jhrr4zmgqltdqd.onion:8333 +hqvdx6ny4p6lruba7wlaaycndmenzygc3nnjwjd7lhfnnkuznriyb5ad.onion:8333 +hrmvwr7x5vdhpfeuo46a2ry3grmt2mul7a7rhjpaaq6einsmrunuvpyd.onion:8333 +hsjtdnlt676ufkgas6ozkrwcjrag26awhkm7xejov4nu776lk2lb3oid.onion:8333 +hvl5d5gesz7vq6uyktalim3ypwqfdytrhg2nlqx34yq2u65hgvb4iiid.onion:8333 +hvp5reyglzzbyzfetg2wibpz3sk3dgpii44bpqgzulk3i753kqj2veid.onion:8333 +hymhpwqwoi4atw2pj2kqlkzpzyy4pegj7e5titydrlenpg7sh3oi34qd.onion:8333 +hyygg2luyb554u5dstu3yxj3akkooayzdu2iwx36y2d3wiyrawffznid.onion:8333 +hzhmvmupvgcawbcs5yqeejti2il5x66rwtlf6aplrwhx2begwfhpesid.onion:8333 +i2e44r55u4obbtvjq7p5edhrnhwvo6xxudhq4qkx6dxupcdkvon56xad.onion:8333 +i44vl2trbapr54ocbr5zaqhctuabklnugsoofmxpw2to4gr5e2tr6qid.onion:8333 +i5auigbdj6fwx4c7r6wxa4iuwkjozapzety2ndm7yn7qdxq6frmgkwyd.onion:8333 +i7wicebmued4xlwqejvoexi5uhw3ttzxkjwyqldonk2bccpd3p46q7id.onion:8333 +i7z3b4cwoswz7sknczkdnwmhbkn7yk5uvxjwtrtezner5t4mbi2rs7qd.onion:8333 +ibeldkbgecvvapqmltodznun3hocnt2u6lpocmtwfklp76xp6edwb7qd.onion:8333 +icyzujf4jopznrgpsagmfucv47wwb45tsruwdjuepp7hha2hy2hy24id.onion:8333 +id4pu6h47tfnmpmhurq5womypqmxw5ri4jxbp2pqt56zq4litdbxxjqd.onion:8333 +id7ca4f4yb5yrf5itoqczqp2bsyinqjkwuo5mvzx6245ef3nmj2wodid.onion:8333 +iehll6sixysyqtfripbtc6ob5zaa2rqlnlthuxkygmamo2hj3fm3rlqd.onion:8333 +ifdlnn2cxerjvc4egepebsv5gnkgqtovwutfja37osq2g24gows65uyd.onion:8333 +igns5t6crnyqxlos7lnvhcpltiocus4ox4lbw475ugl7yctzj3yz54yd.onion:8333 +iioiaikirvhrwoixgql4tbnkamb47yamsrzih7npit7bumnc7be2j7id.onion:8333 +ijj7n53gnbmieojkeq6ptz2ffxtauguqqsluuy2rrjoi2najk3yjlqid.onion:8333 +iltm5bpnfaoqgwbzfyzo22vqhgpfqjtkd7xw6cpzjtrmanaetgxgwlqd.onion:8333 +itt3znksrv5dbodyvshvmltsnw4ihzdlfcepgbcr3pzrjxm6dpzvvpyd.onion:8333 +iuvdsszxh6ec52vfz4w2wsaswy2nhvptvoqp42ti4kuv22mryhza36id.onion:8333 +j2xonbopjepbjnuhq7su4hpwbcykx7sqrml5n2n7lvqahyx7s4bhkhad.onion:8333 +j3t6pxfjlbklt6vvsrxapk2ctwxsqwkxhvon7i4c4y2m3u4ibzh7wqyd.onion:8333 +j3tdqjirxly4fdw2nuearkjinmmwq6wup3uq2xnkixy4xvspz7jhqdyd.onion:8333 +j67ve57vc5dn5xcorufb5kg7yxyzub27sgzasn2vwhpysvrcfkfehvyd.onion:8333 +j6h4k4lymw3zmtin5n7vm2vp6bnjr42vlk2kgv7dbuoagpzih3dlppid.onion:8333 +jagbaxijmydmaxjv2tq23ybmtqdqiydm2qabkdnuscohsm5moowja7id.onion:8333 +jclj32gvup4rk3kq7gh5yhdyze7b2isfegxafbtxg4k2czs2kzvo4mqd.onion:8333 +jeqj462sr274gnhng7d5jpveuuj5b7gcp6hsm7skum3gio5abhcv45id.onion:8333 +jguxnkcfn4r4pgyoj7cvisyfwqaqpkd7o2wdqztsfl6sh4bcc63ngqyd.onion:8333 +jhztcjkmp23adfz4dimyuyzjkkfbno3nfgeq4ndp44amcnfxrc7vgoyd.onion:8333 +jj6fehlqile22m4flh4ujcn2f475ckm5zsfnu6f4qyfbgr75pquf2ryd.onion:8333 +jli6qkv745s4wxfob6ruxua262mghtj7cu7qghdfo6wygryk6qi425ad.onion:8333 +jlkvkyalczcidry6eq4jxywv6sz3cb46a6ynqvl4fia6ah5vtzhtocad.onion:8333 +jmahatsxjgfg3iz7hkel5lkf73k2switbletcahhajzhrtndj2w7a7qd.onion:8333 +jnetopradsod3332aswwycxwtwdk24bo5gqv34dk3hzx3crfclougfqd.onion:8333 +jow6ete5u5cs2z3ntgbgygqssirexaoet5c4hsu3t42n3uvtcct4q3yd.onion:8333 +jtdbt54n6tccbwpbvqay3n3pfnrmu4kagqztghfal626wimuu6ynfpqd.onion:8333 +jxkgl7uxgyk7fy7bd6hjlkycc6dbtqiypvatm4r3y4eldj7asqhcgpqd.onion:8333 +jxlhkqbtkumhra652u2b65nbminvpqvzj57z7ihwnd7xbqr7oocbjzad.onion:8333 +k4tlmd5ifhbxw7j3g2eeqqmfudae3j2iwj7ytxgv4aq56zmiwxnp4tid.onion:8333 +k5ukx467c6kgf7svvohlecnde7veu7z3tpk7ow46ryo2f25xgdzczqqd.onion:8333 +k6bsyqwkmd5umwsa4okocd5qqkdine76ennwd66jlzip64hfindn6ead.onion:8333 +kamatyg2sqhbcgxnlbih3vg2prwtk4yqhnbefkl6cdmrhhbug3hhu4qd.onion:8333 +kcy4qzf3zznqsejy4w7tfhx6vdryk4u3wcodb377hjxzcolbfnycq3ad.onion:8333 +kjnokdj37cimgseydldmehyquvgo5d6uqce7plauwtdpwzpmfkgrizyd.onion:8333 +ko7igyyk4dr6ofshs75mbhiwgim6eppyspda755y6exlqdkymnw2qsyd.onion:8333 +kovsmudoognktyjhucswkm2poshl7vsilpsbptxugz72a27hokopu2ad.onion:8333 +kqsnps2opo3eajaucdys7ofss63p3oirdesiqvaqdiqmzj6ctfitwayd.onion:8333 +kr5gulo3vhxqk22pctlbpcukl2bplmuegl5dwigc6oti2zqapmu2ddyd.onion:8333 +kymtxayvuvaddtahyx3kpxntaki3gmlmlexukgxw7ib2qtwuqbat66qd.onion:8333 +l2uhir4t3mq6cj2ldyxziydskyh7k2nx5oxhq223bryenvygs6iwlgqd.onion:8333 +l4djzf7rkj2nkkfget3p2r2sh466uddwqpb7knndb7bqlawf3bovjhyd.onion:8333 +lacfexi6mowtpmfrnddvthsczivqa4nyvv6ng23htkn4sfxfqsbp5vqd.onion:8333 +lb45zexgtnb72v752s5l2t56eiq4duhqvrzk6irsvpp4h6xxgoc5e7qd.onion:8333 +le4k76j3ysbyy3ithq3oyhhaesch7mbwfqqfcze6z7txjdymznpo7gad.onion:8333 +lgilelzyhm5em7gnmqm46b6u3g2iam2dxbc3ywktlbq6gpibphy7ayqd.onion:8333 +lh3myis4neyqoz6er6av4cwffoy5hdgirmvnz4ywy5mvi2gggv2tl4qd.onion:8333 +lizmefe3njrrelmdzynyhhtye2jiffh42x277xysq7zqbevcfkyphcad.onion:8333 +lj2ur7xjnwl4qeijrcj2644khjlzczc6wipfcshevuynvlbgfcullzyd.onion:8333 +lkhigyl7ky7zvgj3aiitbnlsqxt2zhk4nygs3mi2fokrbp2saw2jghqd.onion:8333 +llxd4aegg4bf42kbrdsgt43azlazu2k4ssgzgwtgdajv3pwxtdtyg4ad.onion:8333 +lrjqlddfglvcw4ahzcosg7mqtzy6bahymqxc6k33qqzk65z4jy2uhuqd.onion:8333 +lrysypmxkxxhgay74gkgucnfg7ppupfxgio4v3dpzbhoeyyzygwbztqd.onion:8333 +lvwcux6i5qekbpz6njlt7ghk6v5dvl3f3arc4tprbkuxmtk4jo34mvad.onion:8333 +lw3fr3synjzzqptoonwftim7wpbhpie2yf7pyj67vdnouz2ovbdyl7id.onion:8333 +lws7kt2jgjy3kurxxzqxww6r7mrc4grjmkekhgcpfw4tbgcn4kts2zyd.onion:8333 +lxrasz7dvra6e7tnulyw5wvh6h6oien4arihaohjeak4bslx5oihorad.onion:8333 +lykf5rgcaocbyfmxhhcq2aqi7e2jv5rixmmxisyrfubb7phaujimhgyd.onion:8333 +lypt4weazmqrm7y44ohdc3ey23n3xeei6yerofknbg7e2flfkakabzad.onion:8333 +m2lpxaib55uttwv57g4mjfjrr7dqt7cdw4aq7s4pg3zxyywuorr74zad.onion:8333 +m3haeigwafocrug6fi3dczpaxmowwg3dspdbnt5fla4qa3hvsnhifmad.onion:8333 +m7zjjsdog4qeo75x5j2sqi7eet3kepiqr7uciiknwnxetpzksojpeqyd.onion:8333 +mdum4stqqbjs4ups45rqghxpxee2qwhkqb4kizyyzpa2jqryxtmj4eid.onion:8333 +mfla23r3bodslvrduvethu4ituej5k56vldpp7m5pu5bfykvq2oquvad.onion:8333 +mh6okc4axtxpna2vsv6madexepg2rhyeiqnqrfw2pktgyjbmnn76ivyd.onion:8333 +mhqf4lnddyujweijl2hlvyqfeehn2whtnlaxdj7m4rkjxffvzzis4oid.onion:8333 +mkchot4yopdk3buttae2chruenu23xg5srd3r7gb52gkg4eznpavv5yd.onion:8333 +mortxv4zzlyupri7vhvmi2cd4uyhletlj2uth4sy4rxtm26m47dyzxqd.onion:8333 +mpbsa7gm3tpp5nasl453ggh4l5tsc5y5ky3ppmlgf2cgbtzs3dbceuid.onion:8333 +mrvayqa6w654g2p6kgsr5lrshn4bahmac2o26s6yetvmxqwllo7fwfad.onion:8333 +mthicrguvyzgyfxfn6tmdswnmldpvxwcib25xg3ghdna5qttod5huuid.onion:8333 +mvjotqstesnrivtjtmtpl2qurvkyf3gsfgftmjm2upkyodxkwhmrnpad.onion:8333 +mweq6yuerljpnvwlkvnh7duofgd4q7yjtbls7g3muz747pdnddt4cnad.onion:8333 +mxv3rijxa4g2mgafhwyax7lcfyrhhila5g4rnm46cwemileo7okfnpyd.onion:8333 +n2buii4clktnynlfp3ccmuxsgwvngugzhpgbggjmrxv7yqi7gejhgaid.onion:8333 +n3jzmnv7pss45lrbrc57tsy3gznnr6asyosdkdlprilc6queug6e4bid.onion:8333 +n5zxq26im25j4qgymyohaa5i5tcpihxfpfwkwfook5tivipoa24yy5ad.onion:8333 +n6465c2af6s2fzz25ljpv7xjvbj2gthqail7ns6wd6v6tgkkofgedmad.onion:8333 +n65mfok2vfir64opzuxqqpmxnhubcvpyite4kxhf3grs76hzbjyaxjqd.onion:8333 +n6wythsibolbz6hdv3kdxbo3bdhf5wtefgd4tksb224zk577mxytnaid.onion:8333 +ncolh5aclnjsjtthsmn7qscvwx2mf6jq2z75cx4snbeqt7mpbjzmcoad.onion:8333 +ndme2euw6yve7bj5ya3awkhvaznb3gauaidw5ov6qmf4kqghsa2wvmqd.onion:8333 +ngupd4e7h6eldd6tn3a7yvarujoomtvj27dcfwgz6umcta52bygjguqd.onion:8333 +nhondlor7mswosksexpy22qvrmd2gmskxohdzt3szv73zvkmlw53nzid.onion:8333 +nhqdw4pprxgvxxqxtid3frx5t73tcmmdk5sax7a43c5vd6nqw6fxpxad.onion:8333 +ni4u52jpbfjs7vkwndlornh3u5ezfl7e6i4vjccpoczmx4wqxee4wxad.onion:8333 +ni7gpz5a3nkn6gxo4xgcsset6ws37ju75e2z5c6azmavcvs5wxrbzyad.onion:8333 +nir3jv7w3hleurdz7yfwr3f4bmyw7ce7u3rnlf6z7tbxoi76jwnelnad.onion:8333 +njeci67qcye45cl5pp4wptml7gk7wlqqjnez6ob7ps74wkpfdjhsmuid.onion:8333 +nklnhb6lpiwtpxjxkdfthnckpcashewdubutl563mvph2xjdbaxkctqd.onion:8333 +nlsk62k2xyvermr7b7f7cwtxdrgk4npnewmr3omk7uaggoshcdz5tyyd.onion:8333 +noeuviuxcwwlkplsncm3pfu5qtx7b3kncfxe5tfq4v7iv362skor6oid.onion:8333 +nq2fwdqt3qf3fkfhlnrlnscmrucnirsunsezr3kfsc7jrj4nbzsephid.onion:8333 +ns5p2fa3afrainrynk4dzjfbsvknw6jao5sgsvvv2esaw5b43cieenid.onion:8333 +nwmjxig6azspof2ahmvaekxeb6kywdbvf3d5rxldyormrmvh2rfz4pid.onion:8333 +nzrp7w2xr7chajnwiv72oea6kd4pvle5mbqqhnvhkh4egnpytynosjqd.onion:8333 +o7rmuyo6u6gnvnqy5lmxvvqmb3d7i7txrdrt2ns4vjrostcvbdrwpvad.onion:8333 +oe2ipczaggoszamekva5an5idscmbwflde6yqymyyvexxyrwzxylceyd.onion:8333 +offbdtz3vbdyvjfddp47o4vkocl5bjcc7lhoxast74raakgd37j2gtid.onion:8333 +ogiz2gvxv3gjr3tn2os2y3pscvq37fbgkrfjg4c5q7x6mmeg52duoaad.onion:8333 +ognns2u5bdmwu66oktrluycronq4jsqxqs7dqnzzjoskobfpgz6nqcad.onion:8333 +ohcp4dgbobbe3y327wxys6gdolluhezxvbojhw5ixhbuun2rmzofxfyd.onion:8333 +ohf5ytsaptvjfmrgtgesypb3osa6z27mj55rnlxsmrisxrbnx6v3czqd.onion:8333 +ok2owqkjhsslywvo7pytpcjf6443tdvgs5sh5vzvpqoakfmo44a5bpad.onion:8333 +olp6o4vhznaftlmnlhibjxpoyaopdurzsiqvchh55kh3ceqiaiwm2yyd.onion:8333 +onlybestsir3tjebxjh2h52q2q4xgt2rpx3z56adzjzyo6rk6jo3rtid.onion:8333 +osfazvr657jukhdyj7rostfg57lzy6c7gvaxbh7ul3jakppktisckbyd.onion:8333 +otlq5dpuoexvu2ufu23z2rnx3vbetoi3kytxlatmh7loukwolrhn25id.onion:8333 +owvvw6jozvhzsgg5bwcukzvnpfsowaw4pmz3btzetqtwtdt5nbiqunyd.onion:8333 +ox36ix2aclqlilqnr5j6xj3erdenrby754a2r44vw5xlibqlwbemacad.onion:8333 +oxfqjol6335es6zabisfhjljaykd7si3sni4nkjwong5duzw7tw6jjqd.onion:8333 +ozynvhwue5n7kqkivx7y6o2jqe6atusrutpu5c4u2duydzywewjgheyd.onion:8333 +p3chmg2yfray3kuhdoe7nh4zkxmq2opp3zu7rznb7v3gyqaryrxfgmid.onion:8333 +p3x6cqcik3hwdhevmqnwruhsidgdsqvxwbcmylaoup472rpcorptv6id.onion:8333 +p6cdmihgjpyu5ds5sbpfwjscf2w5ltyqgtwobeud74e4rxamtdlhoyad.onion:8333 +pcxlvkgabsowmrx54b5bgqglershgfchr6xavrhbfngridplzhf2pwqd.onion:8333 +pev4gqbesjnma22gnhgcp64hjdentn7cf2zuwmclfe4w5vdhujb5dkad.onion:8333 +pfqr7kal3efztxigrbrdb5qvhozpzxqqawt5dymbloicbre2mp7fvuyd.onion:8333 +pk5wtrhot5qa4fjcsd433u6j6vm7nws2kif6xwby7antjhz3jh3ab5ad.onion:8333 +pnimgn35ybiyje377slm5wi7a4mekzrfjioqboolj7fhoa6bitpl7yid.onion:8333 +ppujyg4f66wpy2rwtdiu3dosq563mv5hcimmaoaeyn5riau4kq45akyd.onion:8333 +ppvvdgnhirjtdrleg3nytysjd75gjsksd3s4bpqwv74qrobzl5arxiid.onion:8333 +prwpkeljx7embshafpgq4qrfkanvlqfgwzwmhzfsdrv3xvsw3b463qyd.onion:8333 +pw2oq7uvf3xg2cg4444ouq6aqrkmf2taqw5oiznghebiquhxvywsnkid.onion:8333 +pyuqmbjilfbju55vbaqxhcggvs2rmwsgg5im2gcbwsmnbvkride5iuyd.onion:8333 +pzltogfefm4zdsj7mtxdq5cp7rw4o7nizyoteta5zdbj7oy72rk4hnqd.onion:8333 +q4waeljubnwct7u4olw4wr7ptuduuprzw4dtvxaioxyhjhudpp5h5dad.onion:8333 +q5iracp7tn57fkhhcewahux4vofnzkqmfjldtoasq6h45vxv526evrqd.onion:8333 +qannow2dbksedv7wgi4j5gpgpf2qfgajjzlenmc7vmrfy7xku25pz6qd.onion:8333 +qdi5bvzkmysxe2a7u3nwytwqqrboujxg7dsmukukff2mjhcqsjm6qvad.onion:8333 +qhar6p3u6oyepbngfbxcsxdyzk7nmmxw7xnyk4sjiutjmnx7zvnsd7qd.onion:8333 +qi37t7cbq2bkfofqvmimodblq2qmo4jmn7nuiv5eyhtxrbj23l3feuqd.onion:8333 +qilhe2eagh2wj4itojf4x7muoakf3tb7n4rvb5tx5cihqhr6hkgx2vyd.onion:8333 +qnmxlslrhoqosnuf2v45rsifgwnsdj4e7zwkvloi6tubvkndg7akadad.onion:8333 +qox2gvzjm2bhzzl736kvhkqo5dnrzadruyfzalczh2x4g3fu52o5ksyd.onion:8333 +qumhzryq2oghxbrusaltdo466x7spsq6hgdevmdzqihqopceqksdqjqd.onion:8333 +qvfefulvat26zdnkot5xykjdm7nsoubmlrg3xrtwzqms5ns3ug2ovbyd.onion:8333 +qvfhewhezgbiepbc7bu7olsmoboint3pkry67wumhshyqosnpbthyjid.onion:8333 +qxgwkwwmul3lxfdgetsvvleeiz2bdhiq5h4523rq7xf6c2cfxxczodyd.onion:8333 +qz26vwgeqexbzepivswq7bycpujdnhtd43prsm427rfu6e3avwgxcnqd.onion:8333 +r2vq7zrtapss4dx2fbx7fm3xyg7gwdgq6mr32fcf6uovi3ft6fdigwqd.onion:8333 +r4nmrs2ewv2bfs6z4z7a6ypcey6ndmyweuw5puktnlpcesl3e25pauqd.onion:8333 +r7zbw2sx5sd3gkkop2po2fd53y6xsz7lncpwzcgyv66gtsrq7yaj4cqd.onion:8333 +rc352vcqyom5dp2k6jqqwfwbe6e27jwazk3itojqxrzuccrjcqr4azqd.onion:8333 +rc37l6as2mzvu6rssgpusy23uhtdzerd5cd3noaevtiktv5ndhjzazyd.onion:8333 +rcav4e6uz77o3o6q6rxexsiqnlvv7tfzsc3so2wcw4wqrsipo76c5myd.onion:8333 +rduriat5h4skczq7yeuy7cv2ecqrysz3bblfuo5z7u4p37ga7vabszad.onion:8333 +rekpfdhbguudic6ws5scnpieixjz6yi2heg7jeh3lj3yk2cxm27hplid.onion:8333 +rep3zta43guqsxuaem54jkjy6yrgsipxix3qhhvnt2kiek7fohjalpid.onion:8333 +rf6v6ew7gj3btll2hhbrfvzfbqk3arve5iwd3yjmcymmxyweiz6dlhad.onion:8333 +rgfftmtoaiyrub35duua4yovzjkfumuwukfgtagyk73yoqselezaioid.onion:8333 +rjsvlw34hal764kqvs2me6adx5ucwf4e5u77ilq5azql2vbetcieypid.onion:8333 +rn7qxkbh4puk66rnbxhhx3f6ntfc6vjzl5anknzichwpgq3ulz6knfqd.onion:8333 +ro2liqfgbjpybc65auyprcmhwffi6wi7kcmdicdzv3y6ueurky47sbad.onion:8333 +rq4mvn4xvntnmw7somr2biuswtik35vxogneb2rwq6spou5fy3n4oyqd.onion:8333 +rq5alkdxudjedsloei5u5x374eastaqoxwd4p5sdj3ewse54rgkkuzid.onion:8333 +rrxjpptqxvyxeq6q7ei7e6q6p4bqh75vtholcte3s45lg2hrwoqujaqd.onion:8333 +rvpwevsgpdipz2ewgmujeflni3hl7fbxl4lkltjcxjszfrczdxy65tyd.onion:8333 +rxejubww67egcw6speu4jvn3uh4h5dcrokd3bedoxa2qb4w2w27gn4ad.onion:8333 +s2h2gdkz5mk4qrfcgiecocbkkoapshuzsf5mxn5cl67ptzgtrqv4vzyd.onion:8333 +s3kcvocfgvhflaz4ook3zxyhqlt3kcz5zwnesxu3qu22xmkmxkairrad.onion:8333 +s4sazpnes67rqgxklf5l6qrgzizayuymqd2cehr5z3dnwqj2tonkn3qd.onion:8333 +s4t6eoru6b4xs7uyj4p7bhqob373a2suht7ggbeacevilwj752lqhoqd.onion:8333 +s7uoggkmsvuhff4k2r5jntcci5jwrwnjggb2k2zwg3s4em7xh5itncid.onion:8333 +sajwhnvra2pyb3s63pinuglaliun76wcxxhzfua5j57iyn3x7wc336qd.onion:8333 +sayaua65hiacjjwvxxkjwnpd6ecjwow2tv6k7iup3v3sreqa5cq2wxyd.onion:8333 +sm4me5bhu2wy6bu4w53e2wffkialasbh6fnjivf32bqjhjnjlb6ys7qd.onion:8333 +spzwladgktg6tqb4muptylfudoqaxszgz4holksftryymnmtoq652rad.onion:8333 +srmcvqymewfeynldgohku4pr6wrxotudfy34lfrjsooet2tvsrudfvad.onion:8333 +st6ctsi5uzvobfqq7raqc2wbzk7tpnegsvledwopmbegyfxhpk2feeyd.onion:8333 +suwdv5bah5udmttir35xmyws26aghffy6od4ejosxfh5l7ggqeb7evad.onion:8333 +svo4wrmgp6mwc64jlcz3moaxhhczwbd4yuwmrik4ssbasbslp65ma3yd.onion:8333 +sywwdc7yn42qohpqukbhdnxn2ptmv6434lu5fxieuoqq37cvq7tmyyqd.onion:8333 +szd2nyb5v3wwshb6jqdkafz4kuouvudq3zn3m3vc367radxdi6dhnbid.onion:8333 +t35zxzi6bmtq22mwdmygyjophnvt7wevvrxcmnc2p6g4ojpwhtop5yqd.onion:8333 +tcorvsyyhizume456jxit4mwxq2tgqkk222snmrz4piezalej5vojhad.onion:8333 +tet4eei5uiltcdd3t6gwieu5hrfmf22jek5xpnzrusekjhjztar7p4qd.onion:8333 +tggbmakxzrd7jmoft5knvkgrq5vgqg5iar4dfhbqj43ehvimxbvdmrqd.onion:8333 +thtzju4iz5vytcj5k32gixt3zagqsauyk3gvqcwxymcbf2uh2dnovjid.onion:8333 +thxoas6jir5jmkroiziwmiecvrktuadr6l3e5kiphx7e6awh5ijn7iid.onion:8333 +tiglomyomrtwigmox4lazdv5bfqcucsq2xjimitls7vv2c7ldofbttad.onion:8333 +tkxx2fvz4dwim3ksq64jbc4ezotdn7tmahpcgguvdnprdxjgm27haqqd.onion:8333 +tpjlymsdalyawl6qyw4ktcaj46mnb5slzgilo6moiwhk6yhssjuvzeid.onion:8333 +txaahqhk65mnxzdnboq6hw7b7gqnjvt4aspqo2iku53lk57vkd7giuid.onion:8333 +tzxfkfejmzl634qqybcp6cfkw74hzry6fb372bsy6lc37semeqgknsqd.onion:8333 +u243bnf3p54ule4un5kdszc3n5dcvpj4oofdgbu5zqkwqrckejsf5mad.onion:8333 +u2njpxmuzsteyympxqz5zpm7a2r3cbnwpc7unfgk5q2y3ltwy4kdrpid.onion:8333 +u3edrtzedv5tmzizamlj6n4kmpfrn4ekvxfjpzauxoy4jps3orzftiyd.onion:8333 +u3qhxwdbmjks2hbfouqcvoewbfadjotcgfnl656ahb33imy4ana4zgqd.onion:8333 +u4cdrgrbmdnxzwcrfcejbcpkoc3ugueoul52bircs6hfejlgfpksi7id.onion:8333 +uctbvktn6rprd5ra3bzlmx2nlgor3mnel2ju66iejykftlroflysdnad.onion:8333 +uegjypkyta55u2h5psaqlucpo3sm3hrumsyg4y7q24kxw3lxtkkwnvid.onion:8333 +ugkq3kl6unjm5vf7t3l4cenjs73ciasqqurdqmyc4zi5jtb57x2g2iad.onion:8333 +ui4i2ltehfchk3fkn6fssar4qo33v7qye3teozkmyghjvgqbwb2fwfqd.onion:8333 +un7aswzx4gjeym2jg4n65hp3nmgfvh54phkip7qjpudeajmdkdhqlpqd.onion:8333 +usk6s3ykfzq2mow7cmx65zyaqfckdjczkk6amm3oeqcsrily6vwsppad.onion:8333 +uslkjewqh5yaqptrf3ldmgijwunx2xzypaatyysokfsbhfknqor3load.onion:8333 +ust72z3wsgefcjkfybb2bbhyup2zcdidzdxzs4amtly7ubv2ljglkrad.onion:8333 +uzxiqhes6ksfbml5x744tv5bpktjehoed67l3fbeeof3xqyxq4pvx5yd.onion:8333 +v327cnzsw7fheim63ge2o54votgzaryprve4usxzqavozecwcunyhuad.onion:8333 +vabgp4i7lum6kckx6tnbb5gbnc2svd3ffeob3dcorvroqcxme3ppsuid.onion:8333 +vakmqacvrkv3vfooq6s7se3q6rtytuv5pk7oho56r6b4qhl4mqfp52yd.onion:8333 +vcoc7ldllc6ygydkiae6mopxfhunedgcpjbhs63mkm6v7trivd4ivxad.onion:8333 +vczxwtjlkilethuw7yrqfncd5lkfz6jfseklxcq3b4yyeg6xlvlpv3ad.onion:8333 +vegl6cmizlodquwawwn2gjtfxloap2hnqhc4ypw4mqzt7qlhklocfdyd.onion:8333 +vfabvpb5s3cbr7lfcnim5c6jpvls53p5f4vnzelbu75xgumg5quwd4yd.onion:8333 +vfr3vp3ifrsya5uzfwr6kopolohglhr4aso5htmo7js5eyno3fr5eqid.onion:8333 +vgsa2r2loouede4gr7dvfdlsq52rvbpddiltz6r5rwpjqwpdmzmtzmqd.onion:8333 +vm6siv5jl5whb22qqrxe65cnut3utcmgao7tajknfdmt4qbksduyz7id.onion:8333 +vmobjbqi4cos26uh4pntgielxzsm6sw34zhqlivjaegznplqjls3olqd.onion:8333 +vmyzflrxe53lrzjfi6cnsf57i4dovnitypjhyovkh5t6t7ln3l6dbgad.onion:8333 +vo673kizhvk62wxdsiu6cf5rgmapktxx2l7ztxvzfsndu6spb5ujkcyd.onion:8333 +vokml5p54goq73fudpo2rzrq2fgxeknoaj64b64lqc4hvqohelsjavqd.onion:8333 +vqx2th7tt6ngg3nucixdzlvw45b7na4j5srkwcqlgo4vixv5ki5rzmad.onion:8333 +vthdpsloo4bvdqlgymhz7rqfofw63jv2ieueqaw6inxrt5och7djl5yd.onion:8333 +vujnfef63nhvm3fdyf2fwkrgwdbgx4mov5lfpsswnpimbhyv2qy2g3ad.onion:8333 +vvjpadfmgwock3qhk6mdyzricilgsbgazkgvwt75nfyhxil5wogwnbyd.onion:8333 +vxysqr5f3wmcnnlkct3j7lppjinyy7vminf7qe2ttwpsfxrxtjbtc4qd.onion:8333 +vzleatncxglazfyw6f6keqi3276f2hewgisopidxh2mx3uxu4iflw2id.onion:8333 +w2qvjxn2eljr5g2s6n4pnyq27jwyydtesfdj2zl6ksz3caqoqmi4zjid.onion:8333 +w3bk6j5k53fmx4yf47ii6lja6vstgk265ixuyrglhpil54circo6oryd.onion:8333 +w4pcxveq6mssnk7egg6durw7ndznt7cd7pfn5q3f6usq5qgmx4tnr7ad.onion:8333 +w7uxnbpo7n5ekrljtn7ayhrmrbjqedf7zixpyljsrw2bh67fvbf4rdad.onion:8333 +wajgqp2kx32h2web3qdbsa4ruin4z3plxcg7xdtfe75uosgmw3pfvfid.onion:8333 +wbp2wqy3q4uzzpis26f7hveaokvbf5jnk3z42sjbv6uauwq6oy3fh3qd.onion:8333 +wdsyieovtttjog2hddbc4noq3xdiytis7nhul5ks2rie4plefe3x4fid.onion:8333 +wfufce72bnkhae75iyndpbihzr76xc6nlehhzihrnmqdqy2xmru4fpyd.onion:8333 +wh3cdsnjylvrrhbnis73fyrsy53fyfkajhbf7dlobjccjp5j5ev6ykqd.onion:8333 +wh5iploisetyxiqzutfd5ka2xfpnfsszthwecwommysip3jcba37vfyd.onion:8333 +wnhrfj3jvpfowqa4yf4m35haci2jxgxq2tugjrih7t2k7izj3672jwqd.onion:8333 +wockkiso5afh47gppalqlyrqddpjafgtq5sysupkdiwwsqn6hgqytlyd.onion:8333 +wrhikxkpwssh2jn3cmicrgzpiwagvx3wfvrbrojara3neblwa2hklvqd.onion:8333 +ws52h2nbknubs5hwrlkad7trtrpu3a5kqqjtiig7eulwkg7775vytryd.onion:8333 +wtdzgw46xbydiu7c4x5ojyvc4z6upmytuaghey7k6nhpaantmmwcynad.onion:8333 +wxnqkadi7mrhabjt722ltvj3o5zumdljeawekf7gk5slcqc2fdbazbid.onion:8333 +x2my6gggeyq2kddxr2bad32x6luabusxwdbac5juqp4zwzjqxyosg5yd.onion:8333 +x2n7skbsacubrzsnvdj5zstr6sjsgzvn66pd2tkmzbdzz7z5phm5hxid.onion:8333 +x3scsk6x5fos6hnoil52m3weehh3feefqwjv7tqrfjerosoqdvdkfiid.onion:8333 +x4mwiwksj5pel672lgdmsxctltnealbzda34cd2ur6xnmh4o3hgmt5id.onion:8333 +xbqby56ecqhzqw5e25aqj6jd7b3t7bkxo7khvh37jggjehspyh7btnid.onion:8333 +xbxhtvgzy4ikywim7zleucubsnl7efqowdoqukfjg4mkzs4sr6vphoqd.onion:8333 +ximsnnqifspqkrvkdebsrxmggzlu64hsxjp3qw55uosflvbgp5kz2qyd.onion:8333 +xl3sljm3pnulbj7nrzppkc4fnwtxetmpy24rzluqxr4uyp3auntlupid.onion:8333 +xmr5epdwuvylwsevzq32owihkxkwaiyghrb4mjusfob7daamjmyiload.onion:8333 +xn4crbhjyycbj2pa3quv6333i2xpmscbzshmssbhuchc74d6uphblxad.onion:8333 +xpdst6l2cblapbr4ubi2vbvn2hbrr5m4sjl5d7irpzb5ylzo22kkbayd.onion:8333 +xrd4o7bs7272pbhqttqzzudfpdzjvzopcbtdkxexejeubhtigitftvid.onion:8333 +xt5pt2gn2qnprz5vvdbet4p4wgf3ejbq77guay5fzjlxgn7dmnzqooid.onion:8333 +xti4kdl4ojss45oio5harzghee7zr2whzo5gn47f74rgh4h3vlq244yd.onion:8333 +xz463kgdshepjf7gtnsxibjaomtbuksh2wc447xgawmrl4bbfbzg4dyd.onion:8333 +ybji2ssvc4je4cqzbad2pczrhancohnyy66ogsbpg3d6bspvh6au7iqd.onion:8333 yfgo33tiu6w3nrvnfyw2nmpcwtfozinctn57566y5l4hfcttuvgff7id.onion:8333 -yfmujam6pa75vm7p5q7gvgkocqzcwm7lgbnodwtmzfw7usy5dvlgqyqd.onion:8333 -yfpqwz4qogg2r5sdweggggz76pmhxtegnisz55urw3egvcq2e3amvkid.onion:8333 -yfpucmv4zspytubs5epnze4xc4joqny52s7ifjk3vu644axwkfyfurad.onion:8333 -yfq3sexjxzuww7tnwc7jj2ethiu5f5r65ewpy66os3ozhoeje7na4hyd.onion:8333 yftuiua74fspnqanvait246qn6vmab4aoympjd3omppu46jkq777axid.onion:8333 -yfxz53gdbxu5hapg3e5kaa5pyxpbrpiql6j7sfe4i7fqj4blpqpufzyd.onion:8333 -yg5xbesziuiaigwyxjrn5c5hvj6fxef45edl7pir7risnr6un6esjtid.onion:8333 -yg75fc53cicbsarrpfv2s4crpkx6vdjub4va7cvbducwzhsf6qehx5id.onion:8333 -ygczn2llqhks3ohxvfck4ks45ekg4xr3loriyynnejw2jfmi7hjsfead.onion:8333 -ygdfwrg33s3qwiarwxbejalkirmqui3wjz7wfccprjry6bm5la65vhad.onion:8333 -ygh4hx4ugapidwxodkjr6vgl6vkaqvievk2eiie7v3ewuvjvg2mzp5id.onion:8333 -yglvvnb3dk2vh2wwgpcnvm6t4lgbdhnvpy4jfj3ee4ugb4xzvjrrcfqd.onion:8333 -ygospbn7dc5a6haqur4eoe2oj6jttjohs43rhl5m22ltruh4fz5isxyd.onion:8333 -ygowwz67kvvri2lcwknsc5xjdz7ffat5tqkm7fmxrrzfgvqnxoxkvgid.onion:8333 -ygwuwz5autfc4tqluyuoebghc7f6lgjykm6oprynh3h2vfp4xmhiapqd.onion:8333 -yh4edjvpbo55vsankh7e33u77ep7eah5h5gvfgu7t7mbb7kkmjvgirqd.onion:8333 -yh4uoyfzey53dnoj6zm3frihhgwpqfqkw36sjmqsvfnl3rqohs52wqid.onion:8333 -yh5us7dk25ttxkt6miers3bazlm3jiums5nwz6mzd4i6kn5oizjccuqd.onion:8333 -yhddybpp6lgu34i7uurdqg5jznfdajwr7co3twiqf7pgnj4yjgzbnpqd.onion:8333 -yhiswltkrs3upvkrygsuiou5i2njnyxk3gwtsmcr5yn4lfinzifbpkid.onion:8333 -yhjkylctf577degc7ufffvg3gsdxgnx64pdhzfujxjgfhbulmtc7yaad.onion:8333 -yhnzb5pmcbeiqs6bxm3xvzdy2dgblteiswvvtg6vhkum5gjjw7abjzqd.onion:8333 -yhqytulgwdtvozjhuyod2cufnkbh75mgyw43k6w63ah2fzulskfssyid.onion:8333 -yhtxfuf5zxqoqkuodfpmzsnnmtm354y5rtexqplt5l3fkzzksjkkzvyd.onion:8333 -yhvyxjfauptpsjrxrf3oxtv5zlju2gdpitwsabcmj5gdpjr6i4z4ulyd.onion:8333 -yhxcgpy2bwwhhpmgellyghjpkw7cfrjlq6trq2yl3632rxerwbmkvfyd.onion:8333 -yi2k4otmwujg7bi5iw7ewqntnxb26jyplx5xyk7bjvvaut2y2mhcgqid.onion:8333 -yi32omh7hh54oeot4i2ze2tif4l4cwdhzxxn4bzmtqrotfxrepttfead.onion:8333 -yi4gxqy63csutkea3zss2oryz4get22hcfginwcejy65g35ec5t4uzad.onion:8333 -yi4nvghovjd5bzcbhitvezh4uwg32n6r23et633odlacu4eamfym5mad.onion:8333 -yi5x6isngj7pivr5wt6i3drntlqsvbzijpdy254lbjdnihxmfy2cdgad.onion:8333 -yi6umkklbb6vr4j75buoss7kqkgcsdsx5fvgi57h7j5bzuleoe3ae4qd.onion:8333 -yibgffpo7dimyvjlbzfr3dnmnl2r5hbrpxbtcpksthsko6udsrk5uzqd.onion:8333 -yiiyiuwns45zhmkwi3wjumqhnyfkwkahbggd6hrxtnrxfqwn2vdx7pid.onion:8333 -yijdxmlgnfcwrb5zxvchjhgtc5357mecuopminujkono7bwjgqu4acyd.onion:8333 -yise75jksg27th74bxo3a6rcr3huvromhmuhnmy3n3ngcgfpagq445id.onion:8333 -yised7sf3xzsnlggeuioas2of4crrllkpz2gfbdy7c5cysa5sxi23lad.onion:8333 -yisvuvmqtn7wht6dndrqzsdl7vuspxwrmfwwu5o7wldnzn4mbzeb4yad.onion:8333 -yitceyo3wv2mk56omv6mon3n7dcfr7jiggdmzlmtikpoam2otiey64yd.onion:8333 -yiuesqqc73nn7kxadavmlwc7ymciszzk7bxs3bd4fwucaocme6qb7lyd.onion:8333 -yiz7d2lkgk2mftp6i5e2tqhotqkqjgxbdmzbnflwvsioyfydqrvll6qd.onion:8333 yj3gs4nvumsfztawn7ku4cmner2zlmcn5kke33g4j2vywxsrqmbd7kyd.onion:8333 -yj3q4iustxfcq4bisbuw3jvqc7ph2ggld56mvyxqvgw2tmsinbwlnzyd.onion:8333 -yj666fxjddvz4xzkhtzhh53wvkiobvildczzxb3mixjipqqiqaz3bzid.onion:8333 -yjdhdurh6vqxuykgmuskpabjzjni3ehxxh3zq5redu5hqdmhdw5b5jyd.onion:8333 -yjkojvjsg6yhfj2ln2bpcrh2e6fr42ul3yzsebbz2kkytg7pf2zzjzid.onion:8333 -yjudzsswyvfqyeth2eghfvegxg6z6ubnx72kmqjljhdewrckw56lggyd.onion:8333 -yk2foofoifxgbrp5a45okwbelrsvycgqgw24xv56hmuqxlpmw6msndad.onion:8333 -yk4sercvyzvqxgbgn7srm6eeivlzoa3t4sz363aygcyciubcieihhxqd.onion:8333 ykh3t44zjojpj76ouqeo662ljhyc2t6e3mike76iqpelcdztgaxuw5id.onion:8333 -ykkhln6x6hcmhyrx5rxaf3c5auh5k4plrpaisits63r33ecwkmtexhqd.onion:8333 -ykqehwl47hwypuhhuuxkpoexocldvllixqhplpsy6ym65vbjfa3yfbid.onion:8333 -yku2clwr3x3ndzfjdk3o4spoztoqy6ndatken5wopgapg7qkvypuqoid.onion:8333 -ykwrwuffwvaxlwivt3hlhyz2yo5xde7dw4x67ygc4xh2t6m4i5cftkid.onion:8333 -yl2preaby2yqyhmviyq46roapupmnijt2g3mzmvwtxptvybz7rbs32ad.onion:8333 -yl2stshaozpyqtut7m6ln47z2qhledknuwhij6kvxsuaai4nwy6fp7qd.onion:8333 -yl37nyh3vujz2fyrz3eoqoteixyiz3dj5rfnnmrglcgcswzbeqbjhiid.onion:8333 -yl3bo5zwwsg5dbhrrcjkvoyvwwxp3kbdgprhe6md52ob2lra7ynrbwid.onion:8333 -ylaoywooejvpfosewxmyxjhc2ahfepjbvuyjc4p7bymwirexlkdituid.onion:8333 ylaprgwti4dsumx5xvlhul3esf3yi3ebyyubb2dwfgwe3zysv3e6nyad.onion:8333 -ylblnrd2jnfjtustl6yt6pix4mgqr5qqoevunmwk32e6fxq6uj3dchqd.onion:8333 -yldtx7o5y5jf2utrrtqf5yf56akol55wars2uwxuvjoubustrtmuqxid.onion:8333 -ylh3vliup6k27pt2thw4xgfguiziaosb5y3ovee4w6dzwcb6hc6czwqd.onion:8333 -ylsvnjqrcgatkzj5gfkwt6cz236z76yvgpeulggzml3xb7tnbsttjnad.onion:8333 -yluwecwlibf5dw2sup64dq4gs4cfdhtkfhoy5cszrvu75wljeqanr7ad.onion:8333 -ylyuglp5b2p65gmiofhe2irpxswlhecdecg7d27qhcwehegr2efmesyd.onion:8333 -ymgyodvztfs4nnijjnwiv6eadetxjm765iv3ryuyhsq4upnjwncpvsqd.onion:8333 -ymiw3d4klephwuwbkgdpllrs6hssb4svcg2um7sdm3hsnnksbnvj2vqd.onion:8333 -ymnypd7xmz2fka2r4yxvq2ibf7rvdyl6eemppo74rfehu2d2oqkclcqd.onion:8333 -ympp5jlakwfhj2bozw6w33qailkrqbroizxm3pdfxvjdbrkwtyx5iiqd.onion:8333 -ymrunm2vhoarw7rpo6jdmq4mev5hz63umljki65q2v327vmnw6wjyvad.onion:8333 ymt2hdfgdxo2awvj2k4y5tbpvapj75j7v34tvvlrqy44lsvvdcnjx3qd.onion:8333 -ymuufa5br75liswfrb6pgm3hc6o67gnzhyg7vpfo2qsw3oyw7m7nsaqd.onion:8333 -ymxea74sswjyqvv7jsh74dnvimcsq4rnao5x5g7dfjnbfy67oj37l7id.onion:8333 -yn3avowdk5cox7qz34s3qiz2u5j2xg3irxckhzikfjv5ccjqrdiramid.onion:8333 -yna4zorq57ehghewlega7lb4zgx3t4lgv5k24orv7b4qcg27svymosid.onion:8333 -ync7fc7dz24s32kp6opdkbvohb74obme4jgo3rkkvjzywslxegist2id.onion:8333 -ynilvzuulga2tlv2hcic7ayc5qpd4nz7r7snsyejp4vxwnxlonf4gvid.onion:8333 -ynkv7njh6hj5xewxxy3gvtnu6ocyvu4tgrl3gnw5xxkdpfshalppqmyd.onion:8333 -ynqgzojvdwv2rui2rlechb22e5hwqipltusdnfkv7s65iz6fgrnybnyd.onion:8333 -yo4ykt7hngppavow7f2sz36ajl6w34bw6qrcfee6i3s6jkm6seove7ad.onion:8333 -yoat2b46hzeuhy7n57gjmfxgppei3xnzdxwsl2ipc5ny656j7zp6ovqd.onion:8333 -yobra7r3ketjuhr4g4cfdqumsez4om2eefvmgxrxq7wxnkouzmcemwid.onion:8333 -yogfxdco264tjbbeek22o26lznu2g2kwvs4lmft3ib3xelndagtf3uqd.onion:8333 -yomwxfciljad63gicbd5757og4lypcph5f5mqdou5kj5rowkyotaohid.onion:8333 -yon5gz4q7soici4i7jf2zaciusioym56jo2bat363tr3peoiurransqd.onion:8333 -yoobb72dyt62n5dpsu3aqpqa3lmfj6gfurno46o6vmqdbpwqw32ahjad.onion:8333 -yotcqynj24k2ckilo54hjhftjuvvwiacbzoraqc2kq5vtmsxloswddad.onion:8333 -yp3juo763dmi7ryhkv3kq2l262cllrru6ks5tlzcdlxdakmip3zosuyd.onion:8333 -yp47gud6fjsvjgu54oica4b3ij4zfreactcaon6fx7v7pfbxbrvqhtyd.onion:8333 -yp6klgnrvisq73qg4dk255h7un2k7pbk666jtzc22rxjs2en64ojauqd.onion:8333 -ypaazf2z3t5dqzudlygjjpyb2uvk63guovstzubsohbbeomometn7cad.onion:8333 -ypakyst4bbhh2juqd6r7xymqnrgwx3eajekpg6o5b4fazccy3mwovdqd.onion:8333 -ypkjkt4dnyqy6svecydigttwnsj5x643w6edk6qzhfo2hkxxu4ln6zad.onion:8333 -ypmikts3saaffj2uo5zmkbac5m7xnbblxkbhpw5xtxbamajqf36wgdad.onion:8333 -ypninar2hybv3jdovr7ax7teq6wpzvrw6n74csq7edos3hzumh2h27qd.onion:8333 -ypoinzgql3zo5d3strpmannbkdtndxkxlajwgcpaj4ngbc5mqrzzgpid.onion:8333 -ypp73pv2vcjfq23ltwhojuremxxfknwtgkxsvwe3widlaevyx34pepqd.onion:8333 -yq7s6pe7jzrzj5uxlorytwxd5bs4kljyvp27akdrpang765yd3sexwqd.onion:8333 -yqnal4phy7wz3lsoi23rziyb56bnbzvvypy2mg5ponzrk63qpyvle3qd.onion:8333 -yqoiqt3molj4ygq44zyme5gdbgee7catlf4ndjr4myiicduuwiev3fad.onion:8333 -yqvhbmvc45iy3drl7nceuhugdt2fevwx4x53zafio6h2626kflwtrcqd.onion:8333 -yrambbqlzkm6o5pkc5q563njvrkfallqobvscvpdik5owbdtnhbc5jad.onion:8333 -yrdtnt4lkpysyyrvryqhxw3k427gxwziosdtipf2dcifougwzomdfcqd.onion:8333 -yrlc4r3qfcr4x5wnciutrdvasrpahor3ui25lgdgkxbit3zwtmwfmxad.onion:8333 -yrmpasdjmb77ono4c6rjh24fj5gt7bbjx7nxurytkmxbww2gam6vodyd.onion:8333 -yrqolwaoxpa32cw2zegnaggmniuer66umflznja6dcp7udqpaoanqwqd.onion:8333 -yrwksigpx4foqlwnf6cxwtppx2z2msompig73dkcm34pwsmy5bwwg6yd.onion:8333 -yrybhm2es4siupjnyjffviemvqx24mqj5niwm2wf56spdqlwau44r4id.onion:8333 -yrzwl3rbfjx7eybyjvnjz2y7qmvpnkexkmylqpwsb7ivpg6ch42mmxyd.onion:8333 -ys2muyvcnpdadettzavleh7qrn7t6r7e2tobfp7yxftta7ez2i6rdxad.onion:8333 -yshp2g6b53ndeez34nxnk4bz6cqbzlfxqdggi7btqlwzxzuc7sweqcad.onion:8333 -ysq5rtpfzkz5gt2s62idbsd7secz3jepzlup6hqf5ttdutsdmwg2ryqd.onion:8333 -ysyx5eagwnqpfemz2nhwcxs2c3eueqk5f3jnyvyfqfno3pflcqfw6yqd.onion:8333 -yt2vub6llcegxuucu3iekjqfpmbyz4kreuxx4su2pqcetw7kbkbipzid.onion:8333 -yta7q7v5lkzt4zyp3m44cxcdtymxgmuqdntnagz6h3hwidmqoeavifid.onion:8333 +yqrnkmnwp23adyswjvnvw7uyss7vtbfcickq6ug7i35dafmgfjd3bnyd.onion:8333 +yse66djcdrlmjvxlyibyye3s7r5hv474iteas3tplq2p2famsxkczzid.onion:8333 +ytbeafalpctlsx2s2qphnawkabtu2jb3nvarkwv57bqdmxgmhe2jx3qd.onion:8333 yti2ofsqg7k4zbln6aqx4zqaor2zpmlsebyljxlu7jczsjqtd4ctd5yd.onion:8333 -ytkkqeik77zjjwabsdlctuum37jr3r2rg6ckxudza7y7tialqr2wfeqd.onion:8333 -ytq4uowr6vwyjmrjvac7aimjjlzylfmhqhn3z4ecenm5dd6u2ccsijyd.onion:8333 -ytqhsolk7pqur5cu2faxruehvx72yiiwb33p4szdnzidjqksanps3nyd.onion:8333 -ytqzrm7fke3kqgh5b62taq7yyejgtd3yxwaifj2pimoqbfq4p7xi7sid.onion:8333 -ytrhvysmp4iq2qumdrpgp54q3ushkf53b6i4oxpddg4rmlk7hbayusqd.onion:8333 -ytyn2e3bkmgavrygpk5rzydfdmhpkercccqcaks3xtnbgq5qsyg4euyd.onion:8333 -ytz6ov6l5ofhjudlfi5k26lsg4v36p7xwciafy2sdau4cn6ozxgmefyd.onion:8333 -ytznm6jwapg5h3firimqb7ao2g7uihakg3gt6hcpfqkkgcyemklfufid.onion:8333 +ytm5ihwofux4ktxhtxa45shbjaelybzmnb7uqillpx2iym5tkbnzfkad.onion:8333 yu6ilgxjfffdb3fq7srwwmz6ymp3fxberstpl6vdocmxbrrf5e3tw2qd.onion:8333 -yu7c5kjgmlci4arofpgq5d2qs5fvbw3zac52nampn2vc6vximc6qovqd.onion:8333 -yufe3o5x7spybs5tku64r6hzbrc46uq6izky6z3dyvba2ymblvehyiid.onion:8333 -yuhebtpb6urpsrr3g3vk7tcl5lp5dt7kcaj7zpgox5r4x6ptysxzvgqd.onion:8333 -yuqoihr4p76t2yupxuciurcpzsij5i32enjlsynqor25fhdvidx3djid.onion:8333 yux32z6r5leyhbdrgdpti4sggxyoy336qb73ia6sk5egfli5qsvkxvyd.onion:8333 -yv2ezeqqfeoprti36q4fds3ckq43vdv7vktqfpn2npv6isnbxay47hid.onion:8333 -yv7ainbyxz6wejjhpjgzx6ghcomdwd3k7fclru4woooxcovyjwrp7dqd.onion:8333 -yv7llcydwvi2m4xpnulhgxcrje6vswtsasu5bbmgxuk3lgln37tdvbyd.onion:8333 -yvgzvmh4ngi36zvn7pe3bocsxj6pccafh7v6wmswkdobbxdzh3b56iyd.onion:8333 -yvhvl5bvjp5ljmooujmw74wdyqnhvwlm44766wwgq5thnzctyni6yeyd.onion:8333 -yvnppv3n3hwexlvugfviwv33ycavxdwnh24dps5vp3y7kw6kze36v3qd.onion:8333 -yvsokw66m7kqqqjxb4mntjvwhnpoovoec6rrpqtdze6fdvpbtvt4iyqd.onion:8333 -yvud2f6wb6puec4xq3a6yruax25jydqepowhz65uvlbvblsyi64skoid.onion:8333 -yvvodwqb3szlgkx4egcyq7qmhpyoqxdyxdnksxl6ppnmagnsu4noemqd.onion:8333 -yw7tqaujnglpjmjak5r7sxvjg4gqeubwetm5h54e7fbfn7yx7kgr4kyd.onion:8333 -ywbprsiodgtlc2qoubvot5qm22logutr2dbizmlond4dcifklaxqlcad.onion:8333 -ywkxlaydopi6ygjeggtv5znptkrldzsh7peg6wabkjmcu4k3hmbjivid.onion:8333 -ywmh5zcx3r2rd7zmkyx5kymgxk43lsamie52kbhayqwqyod5togs6aqd.onion:8333 -ywq6oxdfdvlict3cuasd3akvcl47iw6bxykrvkalemrcyqzyzclbf6id.onion:8333 -ywqkdkihpzr3hx6la2lzqsguoqbuwkn36qcrbkhvltd62zdrguprljad.onion:8333 -ywqp3kjwchkto24so4nn4ofq5m5c454btnkux5jxftkkqz66ducu3mad.onion:8333 -ywqygs72qzxbkjekezlhsnrsfnnvm66igkovfoh267ru7ho3qtxtalqd.onion:8333 -ywvpyur4ny6zhfxpsva4mh6cd4htw4q7ylx7tissnxehwg2bid5fumyd.onion:8333 -yx3nnyxy3h4ex22uqdjwephoprte34jelnkpr4ua3d23ks7qxjrqzoqd.onion:8333 -yxa2iu56fp4i4mxzdkmv7xxrluyxtkylqvexuceivx4fqxbjyzme76id.onion:8333 -yxgvp66ll3c6ko7w4hm7xvzofd3cb3ku3jjqc4wihapnyk3wxijafrid.onion:8333 -yxlaxiaatyfnrx3l2vhb4p6d347djzux75gcl2d33aydlwspo5w5wpad.onion:8333 -yxlwpmsjdbpldhi5hlzopision3iqbjzpvyaaeb4yst3z73qbgqy5fad.onion:8333 -yxnuslj7hslwmofh36a37stlm5jjnq46vvvyntf42uw3zuouot3sjaid.onion:8333 -yxq3bjwdrck3lflvwixj2fc2l7pzqnea5l7cucviamoc63a2xozk7iad.onion:8333 -yxreb5ajudnpt3b7z5hyizaj6ufgd46o334wtduuyaakboxwztgji2id.onion:8333 -yy3bnszld2tbbyd45f2j7btrbdz2p5zsuzie27liqr7xgkfh37rcojqd.onion:8333 -yy7rusheh2cq2xghpsdzlrx4gpejgfvsfhq6333d2jttcovhh5jo44ad.onion:8333 -yygxdcvyp6tn46umpmxlsgsi6crg2xjchuhi3okobofsx4dqgwucnnad.onion:8333 -yyo5s4r6wr6p7l5p5umlp7xgb47ugeptugscv4gvpsxvjlwymfpwruyd.onion:8333 -yyr2peqznujer3t63yyhlcasjndbhllvtxxkmcvr7p4yxpuzjrcylcid.onion:8333 -yywmc2hhk7t56e7jun62oidqft6jvtvvlylexihzgcrtkzxe5axsd7id.onion:8333 -yz3izxf6pdtr3ucbriuo4bpgjn2visad4vgocktexnpv3rfgar3kydid.onion:8333 -yz4l7aqcjf3lcdtdcuxoxljedrcrlo3lu6kths2bvjeoil4wqx3d46id.onion:8333 -yz5i6sldywr2mqzh5qmwoqfgsta5f67bgdhqogejjmpengl3llafdjyd.onion:8333 -yzakgornrhzzenpclo4ahyai5lxsg6mjq4zrwlhqt3ff4sblxi42jwad.onion:8333 -yzbka2sygb5eqgrgk2svqin5hl3dfknzfdn6wzwncexsejmrp5wgm4id.onion:8333 -yzh2ineefkzohck7vkwcfe62kvplsly5xn4dmm25fpxbjq2va34bu5id.onion:8333 -yzigosfexpco67cy3e32xehlpwor37fp52my5pwtr2xsnj3mxl7gfoid.onion:8333 -yzijb7pu6mrrdwb7sku2e3epfyrkhl7t2a723vaisqulr3roaxoy4xid.onion:8333 -yzlai35raddd2kdjnukns7u5t4m4ngi5dfrlq72e6lqf2hp5dzkuszqd.onion:8333 yzo2vz4kuitm53zwynkm7ddfdw5escsp5fp7rgf6uspphe653mvdekqd.onion:8333 -yzqfzw7fgzzs63xpvsgznhnassxcadbfaxxaxbmkffvesgdxizhxkyyd.onion:8333 -yzrw7ukful7rhvlletmabm37wupkhsxwo2esqqotsoh6gxib57ss3tyd.onion:8333 -yzs2bdhwhxfgaozpcic4v66w7wwlxrr3v4xpgzer733qehcwewijipqd.onion:8333 -z23pfizxwpae2sbje722iesvd6rcxntazcaoefabzsudkc4xxmtbqoqd.onion:8333 z2eky4p4ozlkrrmuq2jqcz6w2k22re6hxrm3um4ypcnmzmpsi4p6l2id.onion:8333 -z2eo4uckd3ymgtsjitag7yqukmjsjpwuf3d3npq4oskeatpkcinxkcad.onion:8333 -z2gnzha7ttijmle75dvqdzaeqz3xyxzjrrqbzribvwbomh74je4xeiad.onion:8333 -z2ihxne7lyodwglkwpvdmz3a6343msirrvjmaf2pytuo3jysabrkiiqd.onion:8333 -z2lhlshxak5owviqqzacj73ioftqmvq5idawmrgt4k347bwr6yubmqad.onion:8333 -z2njilhjl33youet5rbdfmncadpt7tohtconls3qhpvuqfkreoteqfyd.onion:8333 -z2nocd4haqt257cyr6festid7enoe72qpmu27cuvveoon4rcak4femad.onion:8333 -z2yjvxbv3rfpso4cjkxc4i72f55xb5fihthcdbvh6dp7ghxz2q2tabyd.onion:8333 -z33gr6fni32nkhfmkovcbvpuk7s2atoqfbuzdgz2jszh5ua7zdu6uvad.onion:8333 -z36427rantiy4ikleyihwfwh2ga3pyqqz7doezrzkyv52bi3mpcgt2yd.onion:8333 -z3asgzuzdvhrrejqjnkg5qfeynspuwzzrl3sr7seqxlwkiemnrpsrzyd.onion:8333 -z3hdtpvmnaz2izvnlopzmfgdb2synsomzgy62h7vlxvsn3yqhgufqjyd.onion:8333 -z3hgdhj7zxtih2gkjlnex6occtzw3tpd6f5eobwrntrhxtiww6ke43qd.onion:8333 -z3jl2izfxwfmqnbbrac3tustn4bngymj2tia2sn7nuyconbmjskedtyd.onion:8333 -z3m3a6wii62jc37c2fw7huca7mu4eywnssindvhn3hrh3t4y4kwj7dyd.onion:8333 -z3od23fobhkvypxarneq3fqsdsksjt3hmujnlaiwb65hdwa2n5xdjiyd.onion:8333 -z42np5zjd3thnd54h5n45ibynz5vb3flbgypt4me2c3bnvntn4rsgryd.onion:8333 -z4d7f4dvqutzvvqkmj35znzpyorroqg53jhbft34gyk2h34wzorv2rqd.onion:8333 z4gvqymmj5jmg3dnao7k3vc245pzepqcrevzyh4s5xn5fcc6ape22sqd.onion:8333 -z4mmpbj7md2ljj2nzbk5b6stdromp2sxhysdexiq6kjqp2go2yfhlwyd.onion:8333 -z4pyvdupcieuqtzvhh47sbiahdyegvpgtwgfmlvfsrm4yj6g5mt6cgad.onion:8333 -z4qgvajgk3tr6aomi7zkpiilx5xb6tvavupvw42sgjf3bfqrgwk4tjyd.onion:8333 -z4rgrsudz3wjx7uykg2kmcadwixklibr5b4k5nulwrpxcjkasu6gnjqd.onion:8333 -z4s6g5bqdmo445vu2i6tcm54zjypfhl5uwnxqjq764bbu5h37gkp5gqd.onion:8333 -z4zr3v232rayjy7e4wuxxez2blz6p6apyv4souxjztqnv3mvaytb4nid.onion:8333 -z52bx6657mva3yjtrutjhxojkbwmrmndk3r3nptxc5xqz3nd62frfoqd.onion:8333 -z5ecnh7crpgo54nfll6qbwl4ybvfbq3izazsdu3pp6zqkam47nuux5ad.onion:8333 -z5v63i7lvhkfdqcex3ioeny62glxhptowtrfof54qbl545mlchkul5qd.onion:8333 -z62kddfut74o5njyehkdlj4caa6yg5orz5lznaccpbloqq2siiwbtayd.onion:8333 -z62r52qegmgv4otygobjdsubc6jffaei23he6n553akc4wnf5ryur4ad.onion:8333 -z63d77gd7artekfeamkqycni7tzrkvbc54fqr733veuoaqx45jwmytyd.onion:8333 -z63fpitzdw3ot62wtxtindh5334uatz2flxg6ronyy6jwx2ztjs4meqd.onion:8333 -z642d45aauehr2ycmv4ewv6zkwjlvlhwf5wlueuy5ynpu4qmffc7utyd.onion:8333 -z65lbxuvo5x36vuv5rgwgyoplqjzzciwvb2whvo3tlghzhp6zij6grad.onion:8333 -z6gr5c5yrp5seqsw73b2pkn3i4aqd5idmzgidjchjjm7f2hdgfkl4fad.onion:8333 -z6n3h75u5kkd5xkqfwbqasd2rekxams3jinrrqaj7p33qdxq7fdlmdqd.onion:8333 -z6n5kkyabl2huqtcp332n6xbo7kpilcw4b64govztw3swtzulgtxcjyd.onion:8333 -z6nq6lkmjoyjhqp5j3tg2gcjq4e3hgduo74unmtmnybd7a777hp4asad.onion:8333 -z6nuvxnjicev3v47o4vxjwakfz6g3jvyo3l4rds5qqfjptqie5re27qd.onion:8333 -z6okjxmclwc55pbwioqx5wyua7rjobcmbttpte525tlt2gexjcjtr4qd.onion:8333 -z6qmf32mld7uqjmx6hroqnkieerstp3vle3u3do6odxig3ubmv557qid.onion:8333 -z6s6t6bi4llpuod6rnakc344wn3h6ejpfejxrkjohjjy246shwfd34yd.onion:8333 +z6d7llz7maqgnooab4b6sogf7eszagl7higrvks2eykwogifwh3g6gid.onion:8333 z6soa5spkni5ze6p2xg6lnehu3d7hnqn5ddiy34jtedwegf4syqnnaad.onion:8333 -z6t6fxwhgndvi36vra6d5duaryx2m75v6a5yoz3cqjlj53ko4wm7fhyd.onion:8333 -z6tmafvqwf2sd4rchnafg4urcug4xpkylwls2owruyifaduaeneyqkqd.onion:8333 -z6u4s3uz6bxke3tyibyccbg7uaxt4cb4dued3cu3pbjw6frqc5nil5yd.onion:8333 -z72rd3arkarr6eehucg7rrkjmvqnzdbjmppfk7zcvzd7jqrvisf7rpyd.onion:8333 -z745wkcll7vkkrx7zamibvbyqjtcp3y7wdz5kd33gijxfz54cxzg3mad.onion:8333 -z7eb2xkiigjdfay4ch4pubeqxb2jwyzdb5fo5owkbteyhefek76qoqyd.onion:8333 z7f7lrvup632wkbzinvbkyyrhmguaf4fzt6zleiynk2vuvwdwt6ysnqd.onion:8333 -z7g3tx3nucmd5ozvs7wgq4i2riiufxlutv2usowr3p4lixfbx54fc3yd.onion:8333 -z7g4iekn3i7nliiowlt3ek7o6xlhi5tv2hofycacjqkpeoijghmiyxqd.onion:8333 -z7j2lcfj5b3isqznsb44ivi66lwmidcfspmvdrmhbfuyub2h3wbmnkid.onion:8333 -z7jbbwkyza6e37iqos6u7ln3nedom5i3dcnowdscr7wfj2xygre47aqd.onion:8333 z7jtpaghm4na5po5p27fwbdh2aq3z4rkpwhhzemlrhsoefru2z5eyvyd.onion:8333 -z7m7rmzhol6swqnk6l4sadrjgxwnggt5zwgp2jx6tadca74o5puyuyid.onion:8333 -z7mcuih5vw5qob6o5qg27jhozuczpqx5lmzl2ghfxra53tov2h5xtmqd.onion:8333 -z7rxmrmvtsbgrrwwh4k37bpkk6dtu3aq7f5d442ys75nepy6r2q2xaad.onion:8333 -z7u326iowflnv6tvy6uiwwkusx4vat5gdaxwamcp6jd2we35ih6zplqd.onion:8333 -za6k2u2t22ohdrpqbirjhl75eadxcjvnqfkl4bzeygbnliqsc45gplyd.onion:8333 -zabx7shizdfchrfthsjcuyypqy473ni23ebi4aedow4bg5c4tl4cxbqd.onion:8333 -zac6qhbqbb5yo4rvcsmbilp33odkzfwrftwma4yo5hor4brj4d3ksiad.onion:8333 -zad5dkykkoelu5tdj7l7mr24pdf6eos4o7cbs5nvx6bcg5443eqwaiid.onion:8333 -zafdafmd2h6ue2pmuj25chhmkqad3jdcxwtaess2opxkrroopwdqfvyd.onion:8333 -zagkhagdzvkgpuo5znflvxcqxal5tweg3vsaoaonsvsl7r7orhlwshqd.onion:8333 -zahrvinucuxpxu56h6nkiiw7cvutxrua65l4jynvwkzt2bzmeuvdpuqd.onion:8333 -zalrhwuj5j47tntffl77xrdehzfwq7c7duhaq4jwnq5vdtdtajwiucad.onion:8333 -zaw7gnlyeqrlpgcmsp3e63anveudschhifaaezu3web3z6pjjdtvviqd.onion:8333 -zayfuym6j35mxprdsm2x7pvws2vyaoinsomdbgrqbe22rcc77j7jtnqd.onion:8333 -zb226sk3eljxccaswfgouu6mitu43sf2dan4feygrqnlvrot6z65oxad.onion:8333 -zb2qixzmsethowd6fqnwikvp3yeeeo3zvhgjmq2yb27tfslscgkp2zid.onion:8333 -zb62u4o5qzst7rzjaq6tafgzoybi2ncogcjp3sf7zbto7b2xmicwvyad.onion:8333 -zbci2c2pkku7hwg64ek4z4cbyn6o5bnzpzyriqwjckzgs34xmu62szid.onion:8333 -zbmhiorqlldelgniyhwogswpvrlcdjqxxcfm6vulenrpwiadvv37anad.onion:8333 -zbnovu66ikceaodzrkpwww4vop6iwvtebbeznngo2mtjkikwknqzgrid.onion:8333 -zbwbqxytihkvupc5zhezoh7oibfb7bopfcw6y4qbhh2kugnsw6zur4qd.onion:8333 -zbwpgu4z2lfuto566v6duz2qw5kkyvor37rpihk244bfjzqiuohdcyid.onion:8333 -zc2c56k7hcdux5wrlpixrx6lfutylfamr676tu2nr5z2vf5gwoyzrnid.onion:8333 -zc4l45jx3txlag7hduov4su5kl633sykaw7guioejg5pq2qyuescabqd.onion:8333 -zcc4wsaenndkzqdp4xsfzn6ilsdhwzpqiswumdc22dv5ejejec3o7qyd.onion:8333 +zbj3cbl6t7oj2f6neql7bhpqlmimp6if5pbzmczji7l3uzyhpjcdeaqd.onion:8333 zcdv7z3vetrpeo7souyie7u3vyy6w43cuautaogldhs4n2fitytsihyd.onion:8333 -zcezifa7mmgv4voul4jf4wbqmr24djgrskwszktkt5hihywblltpahid.onion:8333 -zcif26i4yzp53k3uedswyrqkdmsmkflpmclmasdo6hat57pqjpm2omqd.onion:8333 -zcnl5vojc5aufydmssv4yxeotzeqpvyoxyae4kmoskty77j4dx4aykqd.onion:8333 -zctnwv5ln3yktcyqsbgie3qcee33x44b5quhjdq4zwjprl75r3snduid.onion:8333 -zcugrsfyxb3y5ucbdndifvt5ilp47a2233sv42ryf2cvzoncrgo2mrid.onion:8333 zcw6xk4bfnl46fx3mkrmlnknbwnpssxsp7hlllj34fdrkutzts6yepyd.onion:8333 -zcyumipuaiotm5fhffmhit3ajzrgqihhibh73lvjo5hdt4aituudguyd.onion:8333 -zd2mgisets23i4mslxjl75froqjygtue4lnoq56qk3ohd4qcxpop7pqd.onion:8333 -zd3fxn7nwlj76qyjseubm4o2gs73jv2g22px6t24z7p5oeogqe3icyid.onion:8333 -zd7irysta3wti4efbjq3di2jfv237nhwotupj3rtufvvav4e5umtkfqd.onion:8333 -zd7uq75dlcseq546lmbqymh37cninokajwkixpvupillb7fgpqgbwjid.onion:8333 -zdi46azujxcjqa2wnvdecld3bdkps5erbodcvw2mn424gk2by5mterad.onion:8333 -zdm5zxotwdsma3jvij3jmlke5wmblwy7qa2kikfctlzltexx6l35u2id.onion:8333 -zdn24r3iovbxfkp5qx5ng7ribn4cqm4v5ers4olnbzugyp2gbhd56yid.onion:8333 -zdovdneke7oxtxdnee7f43vcu5mjzoa5m4bexpxgvopa5kaxyrcwa4qd.onion:8333 -zdovy6gcj6nrmxaygnjqf3ym5hbd3s7h3irznsbrjmgdywd2rkj2m6ad.onion:8333 zdoyjklv576u3w4paxyjb4jmdhx2id7xoqkd7zn3sspodasmmazbbpqd.onion:8333 -zdqon7u5ofin5gy4rcmkixc7u42xypwklntwceohpektisokskrn5gad.onion:8333 -zdqxfzqxbaa654nsngnaqdz3jfsfe2u4hxs42covbct2dou7z7jpa7id.onion:8333 -zdtchifs5gqldijr7vzcgqqaftlcydhatm57owdwzrgudns5vpdcx3qd.onion:8333 -zdzkcrnoctqhn26hjbngpcl54nmvozbodf4gwf7anfxjrwhjxgurrdad.onion:8333 -zej7mizjlb26qecppzvgyswervt7ov6f4x6fwrot7obvab23xsv5jjid.onion:8333 -zejyatwyaptvvubp6b22cpow3an47bsrve63l6rerkldmuwwb37b74qd.onion:8333 -zepqddw4zaqqawkx7aqezpqwykxmxxeh2opnl3xnq2i6piazcvyb6qid.onion:8333 -zeso2dbskp3curnpgug5mjyvhs7i6rero3zbqo5n534wccstcok6ywad.onion:8333 -zexnlgnfxldyx6leiqvyhuimrfxznjfjoko2ek6rdtu4dvwkvztfysqd.onion:8333 -zf4cm7bgv4qollcjcj7kpx4qrtqzcsa3q7sds2jc3mxu45gvazlts3ad.onion:8333 -zf4k4efdpcwsfyobz444dgdfnsa6tdbd6aor7p2s6mpuol3ladssb6ad.onion:8333 -zf6nwlrrtd6q73svcimgfp54pinn46hbcriqnqqsitz3fbibzmkev3qd.onion:8333 -zf6tbmhchmzo46lmhx6vu3smjj3y4hjjrv4lnwpa3uq7bvtjcwapmqid.onion:8333 -zfhx5nerqkerm3jfoq4763vlmay4pifit5a6a6jtcjxpu7t4galhxwad.onion:8333 -zfo72va3rnioxbhh4kuth4epqwqque74aehlonvde3re6mvhz4uzgaqd.onion:8333 -zfomias3uj7w6sai3ty3coxhnb6voldudbeyldgyedxqo6kfc7rg7sqd.onion:8333 -zg2yslkwabguckkqanyxwbncrtozc2fjivsyesrcd27xxkowkbcwnxqd.onion:8333 -zg7obxhb4c4j3dgzg47zffbetclv2so4foyutdxizfnedhdkhjzo2cid.onion:8333 -zgaubbm4h7qckt4pgtp5zawrcf6aazby2zk7aeo5xsqpgwsc2yrlbiyd.onion:8333 -zgegpxbr7z34gupenib4tuwywyk4nlevo5dkfg3jt6c2jw23len76qad.onion:8333 -zgjrto32gianyp6i4gc73nlilodiqyo2s5dkr5ev73yq4qvcjxkwycad.onion:8333 -zgp3f3dmwbnr7257rouxkgddijr34keobzrtk5gkm2dgfbw2bylcwqyd.onion:8333 -zgrpshddeijmdp34xfyw2kz22la4jxgwce42pupjp3bo6xtchsorrxqd.onion:8333 -zgvklnnz2avqcnyiffw7t6umb3is4tfthnkzbhnyfr76sjtwu5u35pad.onion:8333 -zgwclfbi25s4ta5hfiwylboeitti64xzoan5aewuqimp5j55nye663qd.onion:8333 -zgxg4d4jifuihgozqblrt3kjkrh5zhbr4uyivtrzf2khnbtbe4z3qxad.onion:8333 -zhabxolberrktnga2eixvhe6vmaoxour3ktd6jgjq3emzkgthsmaq3ad.onion:8333 -zhapnpxpk3lmrfsmhluytttodeosmie7yabywa3aaxmtkreh2lmeemqd.onion:8333 -zhdd42th33pv6qnfi7v3w3gddy3tlgu6pjo2bhh5ezuytutxhivbtqqd.onion:8333 -zhea7pvhuzw4cte7pkd7u6lwjyiqczxi7wgvzhfovtjd7qwdc24pleqd.onion:8333 -zhgdvhnh5zymbwrmd2rfjncparbxfiyraqh4imk6kl3tkltgccl5cgqd.onion:8333 -zhhkv5u7pxuu36y7vzu6wlbjpd3wftxfuadsst3ifs3q23eydmako4yd.onion:8333 -zhhxxlz3wvdaj4scdetokkqgs2ndmdvyfwq4qwrn3l3hv2iftlgsucqd.onion:8333 -zhrzks7gkdvyef6s2aogxxuw7iqheixmrdzgkqotpvl5bjz4vq5tkkid.onion:8333 -zhwmsba7q6vn4yfi63p4tc3dobsarso4322ynl5ofggjbyiozefttcid.onion:8333 -zhzpumb4itgdxy53chqowtu43ru23ag3f37r77ydjs3t5o7bookfe3ad.onion:8333 -zi77cxawtknqkjiod4rhf7gsughbvv2z6e7mg5kax465uc4vtg4cwlid.onion:8333 zike5s7xtcgp6frbjgzjhcz6gsvd3pghkl2jin3sdasrek3vy7l4ibqd.onion:8333 -zip37ysefmcbnyqvt4jiag6dj3h45ie7h56hmw7ktheotkuagippyiyd.onion:8333 -zipzgdr2m6gmjfucup7xpertovt746f57hrgb7lj6m4rxeniem6zdgad.onion:8333 -ziquiv5d3hditb2r2qmt7hn7knosdcokxe3khj3kgn253l6cynl62zyd.onion:8333 -ziyp62u4xfsuljn5ae4n7jea7wfd6vfutket2e73bzrhpstozs5364yd.onion:8333 -zj55khmgsehm24efh4nmye7oao3u3l4tjuk5edghey3mt2ippfste7yd.onion:8333 -zj7jf7o4b3qztdorj2stojv4us7lzqs37fbubqpqq2wu4dxi3cxpa3ad.onion:8333 -zjdf27w3vt4rpyb6usa3r5yi455svyaha4qtsfwvyrmf3hmz5hckbwad.onion:8333 -zjgnxih45rz3kalgxvhyebyavcnohmoa3bcnl5cwkmq5pmbyypavqcyd.onion:8333 -zjx5rmakdzormbwzl27w4xcucehwiat3dnncoqdiwesbmb7dg4fpmgad.onion:8333 zjy7d5t6rxljc64pvta3hqi6yxzfsnixtbslafamoxiiw6ptcmv3kfyd.onion:8333 -zk3cgisxp3uxevuxmbzbmqyhvkhezspeydo2bmhu72b6mw2kl6v43fqd.onion:8333 -zkc2lid246a5jr2dpxtvmtu2tfiwt5dbry3xybu22b62vguco5a4qvid.onion:8333 zkisbl3pv7dsz3szdawti4r7mhrhssqxf3uopi3vrib5dpt6u2u7ckyd.onion:8333 -zkjnuuenigzhs6d5y62jct4tira6fzijqx2k3yzsdsyulut6ywp5muid.onion:8333 -zkjoev53w4e547zot35onpmij4fiube4aomnysttqtv576zdr7wex4qd.onion:8333 -zkl2fsiisu3cyhhsua7qlr5afhyvmfh4qmapgubioyhoepqdb46jceqd.onion:8333 -zkl7x3u7365zj6opig53dxtty7ctw2ijidwa4lbdbhcv3wkld22bvxad.onion:8333 -zknqouk6z7g7h5y7rmycqb6sgzykylbbfpvf5efmzibww377iminltyd.onion:8333 -zkq4fgcc4bxksbsi74pjwjfby5tdwn26yhjnmewy2qy6a3l5p6bnaaad.onion:8333 -zkr66xkrvecgu6jkyan6nxvtefynf2mpsls5csvf6lt6ltqvoscw5yqd.onion:8333 -zkxe2fnm4tsmbu4bdge7i7j2cesfrq5oznfzobf4mwtejbhenp7ubxqd.onion:8333 -zkzj45moxjhjvrzqweh5g3iyucdb2qaqby7vdtmlqbvxmm5u337aglid.onion:8333 -zkzj4uhvvpav6ee7djkfj2uem6tyswi7idzupkozspbgr2kfvrk5biid.onion:8333 -zl27cum3gly7nfhwl7ulnob6pyichpxglnss4ffqv3terkquhf3dm7id.onion:8333 -zl3dx4nswje7l5p2fgvypve5wugfqtcru2ud55qo77tqdp2btm6kp3qd.onion:8333 -zl4gt6uafawn452rlqb4w2mujut5tjcnq4ahdr6ucdyeu2gtzlsk2jid.onion:8333 -zl5voqvgyf7deglpxamz6hpg4bierfngqsmmu72wpeut7toja47v6bid.onion:8333 -zliat4frxeuirx3nbijcljvgr5wembicg26fdpgda4pnps4oguaobmid.onion:8333 -zliy5o4uqgpqj2nbgyadqnlomnjtmdlwoxcuduwcfavzsguj4z4iwzqd.onion:8333 -zlkwqytpxbhkg4umwpqiynz6niefzqjbiwzryg2zpwwmvmw6pmssngqd.onion:8333 -zlpztcqey4osd3omtpsm7micrh6jrxuqzeeendpngk25iyfhleieekqd.onion:8333 -zlx2jkuv2iuzffo35hc264rnvoimzccvtlljdbmut4es76qe5pnvs6yd.onion:8333 -zlzhg5hipy7nc4ulsaprgro53f63mjj7je7m5xptgkksibgvbc6r2fyd.onion:8333 -zm2j2k2nl7pug2amadjkrcgs5omdnxctyl7b6kmlywsphcfl6c22gtad.onion:8333 -zmfmdmzlsyy7owe6vpgugvdq664vjhluqura3skjlm6fzpgqe6udm7ad.onion:8333 -zmfmmn72dg5jjkovy4jt56c6btg7pgp7wmeh547zlvavwmlbrbsl5yyd.onion:8333 -zmjncrrwtui476nyn6sqbp67bvgdhotllq33vzwygasumv6d2us64iad.onion:8333 -zmmtddrew2mjtghs7zjiyi2eelmyss7miyj2axzwfgnmvzthx7phevad.onion:8333 -zmn3jyv5a2rod2udnreygi6uan4zq5ul4mhewyfyrf7a3ury72bycuid.onion:8333 -zmqvv2cdxjj3vbclq7l6rfdmjegmixwkxsnzzd6qezwp32vxkr2cbiad.onion:8333 -zmt7psgtnnqxk6tibhvwkdfuhtgtjatz6bpoyyl4ptuv3u6ko2b5o5yd.onion:8333 -zmtd72b4nsa22ocez2hbjsxxrdfuxxyghg3zjtqjob5sgnjpustat4qd.onion:8333 -zmuuhwxhoa6h53jijpb6mczcvtxhw6zyjymm53dwzsbmkc3kkv5v64yd.onion:8333 -zmvriguathsanquofxml7kgcda4tkihm5qked7a6ntbqk7rmz7qadkad.onion:8333 -zmvritlexdmgatfqjlexl7wsx3lmf7y3qxe2kqeergb7ntkfu4nky5ad.onion:8333 -zmyavuyz774c2fo3eb55yokivpr7qfxdpjy2t5wpeygunhulck7yxzid.onion:8333 -zmzjx42yxlpepdgya34rvwb3wc2peggturiedmn4sfjltgy6gjtspsid.onion:8333 -zn3gjkpqkajav76kaem2espqt2bw6ggfvmn4u3gmkonds7pqd5heqkid.onion:8333 -zn3mj2tggwpbzzkvtsovkrbdshbsvac7n676hbi76r72de2b4gknpdyd.onion:8333 -zn5purhx3rnikkks5tx4scnjlhewwll3uzcs4pgde3qeqawof3jefhid.onion:8333 -znaiehv3qrtloxdi5rkbs4eqpmuveazuftob3sqzw3ta5pyakuwhx7qd.onion:8333 -znbv4cupk7rrdk4rqi6xncbouhscxnqdlbxtltp7564isfv5vtbyu7yd.onion:8333 -znc4xhwywjqejoioap3ssxvtsdilsc6i5o5s2rnp2ecmxqe6xe2nh5yd.onion:8333 -znea5ol7qgniizv3og2gfcbxw2wi4qhk7dfkdlt7bbxpy5aflljygbqd.onion:8333 -zngxgkdgkqpfyepa5cvxlaxvlyluzdryhzmviar4ojzaduxw37hhdmqd.onion:8333 -zni7kioacgsy5haqiftnexr74sv7rzvgy5o6lmz6dy26vvwg5lffioad.onion:8333 -znlvmmj4dvpju46kbb6mob4kufyf5a4qivyygmjj36kymbaa4nzi42ad.onion:8333 -znmgbi6qlwwwdlizjxsc6eujnfwgytufu6guo67b54av4y6inwgxllad.onion:8333 -znmwoazdkcffprail6h4p4opy7i4zqomhpdxe5l5nc6ejqagvt4i7yyd.onion:8333 -znt2jb6nivjgl47s2gdcgac3merqjfq5h2n6x6mbjegx6fumtl2ownid.onion:8333 -znvkqu376ienu62x5hprstn36jfqxospcnfhpc3kq5quwcd6436pzuid.onion:8333 -znwekshd4os5a2n222xrllgjuyvsw7hsb2y6br7pkwjatywk5lerbtid.onion:8333 -znxkxyd564sfftgjscsmi3a73jsazxwhsneix3bgto4suyjx356xewid.onion:8333 -zo4fczw4drgcbsumtgmigjkiso4miz34ltauajaawqmqoa6oxmzy4nad.onion:8333 -zo5jasvz5qo7pkgrgn4r45twdic4zake6zpjfemj6x2ioxcwvs7yzlid.onion:8333 -zobj27bempyxsigdvawc7foivyyuek73hemep7zf2tajof54353ok2yd.onion:8333 -zodjfmegrevmjbppq2t46iluruefbgh3b46tbrl2s5qkprvbetk3euyd.onion:8333 -zofseltpp23n2xb6fsmfgkwgqggwhrelxmt7zq7toazybgehbs7d5fad.onion:8333 -zohxazkomcr5ggqlj2edu23zs6xiay7wfsrxuetrn2k2s5gwhwhcngad.onion:8333 -zokmgys3gsgs5oivjcqp3xiki25iexezy33ekzuratdz3j5unqpxrzad.onion:8333 -zosjvclhqzwklml43hvsdmupglajj5lfdb5h5frgym7hsqo25rwrbdad.onion:8333 -zosk6fx2a3mxkfaeayziiuizq3y3j3azzp4ylwyh76wq2sqtaenuwdad.onion:8333 -zovm6wkattzmxc755cgqqd4sxugn3jaxw44izlm4yfpot2ucfeqnukqd.onion:8333 -zowc7rklhd6xhje724xomkftwimuihacwcnxkt7vhbjpvpkdahvlhxid.onion:8333 -zp3vpkpcfdx5lxvnuellqaf5qdvhu4luf4zqfx5xjo2dge7cqsxhsxyd.onion:8333 -zpgobpk2j2suauhuzfmh4iiz3y2zhj3xvb3g2t4a775t72stt3majryd.onion:8333 -zpgybnbaxfvzjeus7qna45zchxdkekjpk5webdkeqtxfwcglgogm2vad.onion:8333 -zphjbml3fqtbez63bjvd4s552yc2xebitadkpw2jon2qkbapbiltijyd.onion:8333 -zpnoo3qordv4xj5hjynkssu6wechvup6to7pamrgbi4ljmfugjyzwwad.onion:8333 -zppmhj76a6dyjch5qtubosxcyvtwjnb6zndsfywxci7dy3vc6lbfusyd.onion:8333 -zpq2nzcnlasmy3rmwtmaybav6t7xfrvorqqdwntnbgbxqujyy3dkwlid.onion:8333 -zpqvo25bxu4n2u3mh2pdzax7wmpsitd3qsszgw2ye3mpfdpjbg52kgid.onion:8333 +zlcqdqzbgq4dhaspf6d6ehkhzjx5vwd72iospxxbdobjaxi4eo6ggoyd.onion:8333 +zmasrnq5gqwvg7yv62ts6pywn5pijnohgfqbo6jytiuikqdufp6v3zyd.onion:8333 +zogiy54bertbyhcs5vye7xjspuwvyggomehc6n2tbkwwdzyp3hwrhpyd.onion:8333 zpx2tq27yviwzbpc4nyjfqtlhigoa5k7cwl676nft7bkajo6jq224hid.onion:8333 -zqlwzzfzdoacgngtsnofmyqetag6o44f5r72opj733y434b7npnb4oyd.onion:8333 -zqq4g2eikcfgls64ffstsylfbqrfstm6n2otvrsbtvvjpqwgyqdnmbyd.onion:8333 -zqrj4fhhp4mq5eh5xptzcxjzpae37brkdn3voz32qsohl6noijygdkad.onion:8333 -zqrwah6dn3t5fuj7ohlyka27zzopduhxy4wyknfrtqpx4sykece65fqd.onion:8333 -zqtyvr7h277x5rxin6rhsrsbhwcfsyyiqgghpk6jlbewej2v3tn27yad.onion:8333 -zqv5nepyrwezkym2ba5s2sskmi2qck22snw2rygeke45bxg2o4vckuid.onion:8333 -zqvbnqwwhtoux2sxicng2blfiowk5mvty7c5xnssxwtlsjzalhg3zqqd.onion:8333 -zr222c3ybuqxn6a6piydvfos4zjnaklfgh6kofmujmolpiprfw4z6vqd.onion:8333 -zr6ffisxxo4gelmkoyb7izfm7ehjrbqbnzuguw34to34bqhxeeqzzjad.onion:8333 -zr7sqclimv46jdnmmeazqrhflhiqkhhrz5i3ed7yvyue63swk3qkjnad.onion:8333 -zrrfr5sr5wrgdt6rn44cxnotlvwe7cl67rgssw5dwsax42evokdaw6id.onion:8333 -zrrhgs52ftlylshuwp5e2uesgqnwct7h6cqhzofdduwoi4sz3shmxxad.onion:8333 -zrt3rg4paxmo24ucd56eehl7apindhbubq3ej3q5nhr6i72jv2eznryd.onion:8333 -zrvsjjrb3lgvmeftz2vfjva4pl63htmv5qyviq7zhnfmlk42evrxdpid.onion:8333 -zry2rqlcqf5p5e46wc6nmtcbt5vd45mf4hyf4nxlqogckoniufdjklid.onion:8333 -zs47b66pljpz4ahompanciv73xtztnnzkx4wjklt6hh4drsge4m26iad.onion:8333 -zsalwutefh6m6x6yxccbhulzrz2bmo7dzu2ggu4hxp5zv3xx2j642dyd.onion:8333 -zsbzferezmnyxhpktxtccn2xxuggmdzdnrza7pqjlnwjorgx57y2acyd.onion:8333 -zsgtoyy2svehhfba345dx3dazp7tfdio6o34zxlcgylq6pi67gjq7nqd.onion:8333 -zsi55x2nvjc4oqrpzzopkneukb5fudnm4e6drao4x73lf4zshhcvllqd.onion:8333 -zsipwsjpm4f3p6ueczh7lqei5rp3cusl6t4d6nntnwxq72hori5f7jqd.onion:8333 -zsisadra7jlxp5nhec2vsjwspvvnk6jemjxk7zn7arypl6cm6dy7mwqd.onion:8333 -zsr43xqj6nsrqh6qgxghadctltwytnaw4zmlvx6exqybt2qdt72f5yad.onion:8333 -zsxgefpkofjc3nti4qusk3pdqcfinkljajlwcb2cee2tduxltxbmrpad.onion:8333 -zszufrszpweaoysubpdnqparmyotjnev6nhhcnejhjjftu5sb55kesid.onion:8333 -zt6gkop3n6aggrxucnaqp4yrjeu6htwvuy2nyn3vadjjrodwxfhfv3id.onion:8333 -zt6hvzyoalzm4a576drn7yfvdetdvzwwouvfz435wzrf5pcnxqxplaad.onion:8333 -zt6v7eqh7vvlwy5kjzbdfgkw3syj3nnhckyghlzgmwwfccxvyfusuzqd.onion:8333 ztcmlrstdkp7coheeolpwj75gp3imzgiw26xnoiucquwhxxcofao63ad.onion:8333 -zthmey4ueoutf7q36nwgujxu7hq76s5ifbtanvze4mxq2s2xq2cmjwad.onion:8333 -ztmwsyo35zkogpftujm2o7oilhucjxe3w6bjagsaiwtb2bu62vgjptid.onion:8333 -ztou4ytvgvpcakjaje2c6l5j53rxcxes7qhkerszi4haffxfpj3kdnyd.onion:8333 -ztwryklhcnfoeck4qntt2aitoilit2cmmr2geyqo6cjc4nwr7jlludid.onion:8333 -zu3ekh3vtqjfnxqjqlmnq3jbqlg2zum4ehgirz5cggwe2thjmgkz4cqd.onion:8333 -zu3yh7mvqw342e7qt5amwtwe2btjubi6t75k7wgcpsyoicsnpgbgj5ad.onion:8333 -zu76ecbahyc6ofjiiutna6myxmfdcsuhcrhtgpifbw3vfo7njd4b5tyd.onion:8333 -zuaotutv2ngbf5ot5kvz75uehbh5e2j726fglhqw7omk3b7xnaastpad.onion:8333 -zubmiztmnfy2vqowqmpyzbqtf2a43jgazsex6zlxokhfmnzmi3rht6yd.onion:8333 -zuc7sobx6ttj7lswk32raexasfbxc5kd6a3l6td35srqzkj3emsv4uid.onion:8333 -zunmnr7czrxvfjgxtvkwk6ziti5kskx4fi3j4dzahhdljfsqtz7yeqyd.onion:8333 -zuoml3m3jdkoh5bdrwfecnew5f4mrlcwhmhkn456qsa72cp274pbgtqd.onion:8333 -zutyd7pzkyejctriyr2lqlrex3arkunntsdjo3kgw2qj5u3fj5uyusyd.onion:8333 -zuzdl7nnjhy6inyqwsc5i7fae2nregm7wnyrtolaxhi6oiufyc7l26qd.onion:8333 -zv2nusexbcrncbutlcprevwhvbtqlyri3stjwmgl23x7fdqkmae6owqd.onion:8333 -zv63heoa7jstwhq3wg2nibip36bw4icd7jphccy3li3nut7gp2gojqqd.onion:8333 -zvbhycudpglrdi3sk7yixe64eknydwzzisc4n6xmxwhb7xyyzevc4nqd.onion:8333 -zvgutw2u7tu4dx7t25leghdp6j5n44u464mmoypafwstayp6ggabtkad.onion:8333 -zvjn5jscn7jncqss44uh53gvi6b4eycjqp42t6pv46bsr7gine5cbrqd.onion:8333 -zvmxfy5z7nxeknglvpbh7rveoppkyvvzvnpwxon2kgkepafnq4igheyd.onion:8333 -zvpcm7eemfvlklgqio3fgzcwa2vukg3n7caov5itik36kdua6mvm43qd.onion:8333 -zvzirfk3h4hk52j4u254y2np6ve2xttd2nugiccsqw2liiw7aqmglkyd.onion:8333 -zw4olgpxujj6iydkmhuxbx37b52syl5bm6embyebesysep2ignp2dgid.onion:8333 -zwbnovgpo4qxidylubpdrhxm34t23iwaniawfshiqrilttwqjnnlohid.onion:8333 -zwbqgh5le73aurfmbwf5ivjb7ycemwnjiq2jnq4sqz6epl7rdtd6rtid.onion:8333 -zweiy44ngrkfzhnaoqov3fopwqd3uhwsen4v6sdyf3ynmhlpuluvzeyd.onion:8333 -zwg2cvvkm37u2hicwbjasqzdqdhcblwvtzsulmz4kpbebf77jheiaaid.onion:8333 -zwrp2kb2covbrr3xdz2pxr6gg6ndnhpcgfvjkjr43eudnl5aswxgvbqd.onion:8333 -zwsapfrsxzsomsoty652jifwii56st6fg7bs2crr6boveh5o6npl7vyd.onion:8333 -zwtjkx5blzs4i6e7hwfeekcwufdl2lba4j65243tvkajder5iodkavad.onion:8333 -zwu3ep3zqki62b7ldjbsxk4dm4rlppkxpzzqfwsfvkoihxltm3y4qaid.onion:8333 -zwwpbfpymszcmkwlfozzl26m66r6n7xzgnw6bs4nf3pypqh36ya2w6yd.onion:8333 -zx37fw5b4eatt3dekaefun3ln67agpt7oqobeacvyq4keurbj26azwid.onion:8333 -zxaujdps5ce6wvk6ykbfquygtbli4ecvpokj7oyfxjqiionn3u3fdsid.onion:8333 -zxbq3k7hwswo2f374ahsmlgkpdj7ju7pyygurkvzqaoh35vmxleewsad.onion:8333 -zxc2bzuqdkippxthxbg7n7e3lznbcnx7zyitlhwvjusbwr5v32oxueid.onion:8333 -zxcnzlo2eigfig66vxyx43znm66a5i4ieuiosycgddgzdff4vhn6zhqd.onion:8333 -zxk4bqrede3tnlb7ymjlsoyupc37r2vqe647otr3nczqmgfeoyiu75id.onion:8333 -zxqdpu4gmvn5vz2kdld6c2swqdzknwh2czwsw55vx323orvtk6a6igyd.onion:8333 -zxqe6efq4odzd2mvyeglqto2cfggagoicgcvlvca4mxycg47jei4uxad.onion:8333 -zxzfz3z4nbb7u3ifcv2p5xenzpbnzuuezelbbjcfrmupxtqyoh7uhyqd.onion:8333 -zxzqhfwi3gdheuxmzagp4aw4aks6cii2llljapcvqhtqrxlksxddo5id.onion:8333 -zy4jeshnpx3i3wjcqrb27qcea4qetpez65wpocat5sqncz24xeo6sxyd.onion:8333 -zyccgvzokepone36ulu74l54ad4dtqv7a2bjzcvopj6rg5xhbc7ihjad.onion:8333 -zydziohabauwybhbqkegn4d5r4257bmfain36fatcxdbj2nw5zoa5vid.onion:8333 -zyetfkanxicfp6tt5tegkxlkoz5rl2i3zsc6hyyqizahywbktezfuwid.onion:8333 -zyjfoui3hrpsw3fo4owxrztclffqhr26wdedizvz5xvlgurgixit2mad.onion:8333 -zyku4bk6pdifla26hympigytlwsx4htajcn43hhobdbrv4tfojv3snqd.onion:8333 -zyl4kfejs3t4vefsvuqrqopboxrmztuun62jick4uh3wpu4mw7dpqlyd.onion:8333 -zyphknlr4ogrknj5t64qya246kdaasgirn4iercvesggqplzzxsisbid.onion:8333 -zyrodumrgvgpinhygbi5molpbhl6ndfs3lwtt55pumd6wy5k7nb3esqd.onion:8333 -zyvgumk5pcanh4zk3z72glefxgbd4dpyhsbzvqlsp2gspaw37lrhjyad.onion:8333 -zyyefl5unnw7lnrjlgfyvnytw4iy4n4cy5bbs2nudjh7wp7psvefmfid.onion:8333 -zznngqwcp6g55wkjg52rzeogk3fcdpopyl3zprh2fz266nykv4sqveyd.onion:8333 -zzntdfpcb3spf5pb3g2gczw2njmhwwksgxt3twbzjhbaisihg7h2ywqd.onion:8333 -zzsi7brufwylb52w3bcbqvp5jx6vribh6geiqfy5jhxpihqjjaox7vad.onion:8333 -zzthz644hdjxn3d54xrfe7snnuyhsx2cguy4kqb6dpc5u7aun5lflbad.onion:8333 -zzuipjogcfvs7uyfhfgesehon6viegga3sc6c6265n235pqmkwyqfmyd.onion:8333 -zzul2xvyhqvajnd6zfs2dzljoppx5lsp2xt4qad7256kpxrv3wzyiuyd.onion:8333 -zzx4r2yrkxul2kg2ojoeijwce3skll4wbkkjw5xprstn2o2xw6n74wid.onion:8333 -zzyp22x6ryzyin43pltkup6jki5ynboh6cwpucscx5a3md2tooqn52yd.onion:8333 -zzzzzzzz5bs2qnoijxlhxd3ibxipajesgprqlrxtpfbygw4zcaf6oaad.onion:8333 - -# manually updated 2023-04 for minimal cjdns bootstrap support -[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333 -[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333 -[fcdc:73ae:b1a9:1bf8:d4c2:811:a4c7:c34e]:8333 +zx5ttamyvo4vz3x666eqaez327buy7t2mxl6tfivbc46cdhrtkrrqpqd.onion:8333 diff --git a/contrib/seeds/nodes_main_manual.txt b/contrib/seeds/nodes_main_manual.txt deleted file mode 100644 index a3f00ad52e..0000000000 --- a/contrib/seeds/nodes_main_manual.txt +++ /dev/null @@ -1,1029 +0,0 @@ -iy7go4454pb4p2zmnkwrgsi6v6oqv53zxnmalz6rnfjemxftapfa.b32.i2p:0 -j225nrmndwviihpe7ib6mm5h723cg62wrb7vnwofopv472ue3zwa.b32.i2p:0 -j2m526lqsujvt6b6xl4ipzbjkvkuecrye3vkggwo6jadvzqu7f7q.b32.i2p:0 -j2pyenyhoppsjexenznxvgqrcs4buv4nssctowgpg6czdoo3nyiq.b32.i2p:0 -j3usxovx7ukl645u77jud2mpmrk7ryh5yaxno6rceu77hqlxkuta.b32.i2p:0 -j42dsnjlg4vv33tshgs5jyham6plf3suj2sn2k6ew4tmcz3fpaqq.b32.i2p:0 -j4tjrfxnwcmbhkixmqlnotginhfxgfdvjahr6yn7j7rkbdqngh4a.b32.i2p:0 -jb3iui7grnljdjmsz7qbustrl5vn3ip3upnkzbaegaiklric7cha.b32.i2p:0 -jbmqtghha7hscwbwpi7ps2dnghq2bvxjnfeb5glngnvgjmeackaq.b32.i2p:0 -jd43pc2l73ek6hk2tp6hiyada7ed7vshqo2fvxbga2daylcghfyq.b32.i2p:0 -jd63whebd5yuls7r34mi3lnnuuhqxxr4lns672tzliru4vk7hwrq.b32.i2p:0 -je6ju6ihybxm5wkw5daeqjet74lscvi4ls5wn5wf7kiaczfggafq.b32.i2p:0 -jeidstlwdlt63lju7cnj2mh4fofysjnc2wcvilphynprd7jw64ma.b32.i2p:0 -jeox5nruuoopedsfpuoi6kwewmhbbsnhf7kib2q6oafvchxvmnnq.b32.i2p:0 -jex3ykw2nmw7owhgbtio5flv7us624bxwp46nr7rhmteujrmtvvq.b32.i2p:0 -jfdh65i4nhpg4obnoe4aqi3vzvbi6fyzjj2ee7s3qm2gbcnllkvq.b32.i2p:0 -jh2qxkjqngj2m5tn2ecaidfqac4awgnmkgsajntoqs5qqyjtp5yq.b32.i2p:0 -jh7ev4a5zfzmeyekinhtbqfi6c7xhvc4msdpyi67j3sxl6r44ukq.b32.i2p:0 -jibaw7ynbnxueqsy7k7jyvoj6ldzbuckppfx5wozt7mftihy5vcq.b32.i2p:0 -jicc5kwy4tv4j2nn6gfbis7e6dxy2kdvet3zpxdbyp74h5gpnxuq.b32.i2p:0 -jimdydczt6e2lceezopnl4fgz7q2jeqqhlqaxrgen33ouxk57xiq.b32.i2p:0 -jjangl6h4py2pd2gwamhqlsymyuocmpioneinzf5bb5qvvdjzzqa.b32.i2p:0 -jk56z3febpco6rbkpzzv3jszf4px5uztmoxzkpss7mxnzqlpsdla.b32.i2p:0 -jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0 -jkvey2vfdto2ucudi4jlgsbpmlls3uwmlkjonfhk5yminkwzwi2q.b32.i2p:0 -jl4vr5kac7njyltivn7ut5afyq5ipzc5woxl4523emodxixci3zq.b32.i2p:0 -jmebfluhrl6ad5pt4ipevf3g3a4trcu7axalpubpkir6zlwovm5q.b32.i2p:0 -jndr5i4qhxs6aa2bqvufrgttq6enavyghi54dqfuku2qnstdqa5a.b32.i2p:0 -jopiw2tup5h5xh2hwef4oflgskawbpfmswub2iosmqocejijd4fa.b32.i2p:0 -jrert3o2rhbkpquybwg7tq4bdvlxeh6lnlcr5ddexkuguvi2l2pq.b32.i2p:0 -jrobuecgmuuqmpdsbxwbqeldt2735cgcemngoasnbbkdz2ufdlmq.b32.i2p:0 -jrvg22xvbmjyrkqg7mr622zhnda3ijtua65cqngwrven7sf5zd7q.b32.i2p:0 -jsg4dsxvgjcqz3c2qgtwi4ip3l4n4hlxodbvgukwaipycwo26zua.b32.i2p:0 -jt35uwbl5wx7ponyxomksrjjs7zy5yymvtud3nmogt7ci7xxlm2q.b32.i2p:0 -jvaoh33cpczp626ldwr4azh4hb5cjmxlbz3dq3cxisdlzn7z25eq.b32.i2p:0 -jvlj7qyxcmolf76wneyvmdxrpiezsxkiimapwxbdbiw2phvlyjba.b32.i2p:0 -jwqlvqmfvodnrslde2idqt25qxiyvgqdlr2q4uod5s6lkmlempya.b32.i2p:0 -jxjc7oe24vxdepkfvl365qfwrxcad2f3j43fnfuchtvqqkqd2rzq.b32.i2p:0 -k4mch53m72zv7jdda3poa2zn7bi3jacqwfb45peealxbhysdozcq.b32.i2p:0 -k4pjt6m25dcxno3udek6rasooz5ztqnywa3f2owpvcjzvisg7nga.b32.i2p:0 -k5ars7hsrfubadroe5h7oypjnqwi6v2vxxy6rmns7zubf66aivbq.b32.i2p:0 -k6eeshsk4vf34b5gfnraz4p5qb6scv4kw6eiltebel5exw6keppq.b32.i2p:0 -k6gt64xby5igmln5hfcuzspt2tndimzrdvj65yo76h22g5yhlvja.b32.i2p:0 -k7kcnrqe3ybqu2w3fali7zext6na7o5o65rx6f5oqza2lonsry6a.b32.i2p:0 -kbawcieyelwwitrjow537zpmdkncwiq42rhjgayw5o7u562mk23a.b32.i2p:0 -kcqkothplemakipfpeajxmu4xsszpaxpprgtuv5tgfdaqejg2sqq.b32.i2p:0 -kdrcbr6wg2bj6oipsbeqy6bp3v7dqpth6cheviysmvo4bdta7fda.b32.i2p:0 -kehosmgk76fxnjywqjj6nqs4ohg4hsutljdzjo4sswhxlj5l5tca.b32.i2p:0 -khxruoaom7juockko2tbxqo3bnrjmoqjhdoady3yyr4qacz4somq.b32.i2p:0 -kjaa3zlp4sipfxikketgvlx4oxq5ok57ifxenbiewmsrew6lcw7q.b32.i2p:0 -kjvrzgckasb57yqhluvjblx2ngxstumfg6uufz5mc7zyetkjlr7a.b32.i2p:0 -kkihsh2faw2gxil6it4glol4u37ccruuzsusyikquzmkffj3wn6q.b32.i2p:0 -km3b5j6cqrcqewdpuveibptw5gguwktwan36jlow4xykpg2dgr6a.b32.i2p:0 -kppcor54kkge6cgq47nzevlfrhbxingcjfmk2emkrdaejpixkqdq.b32.i2p:0 -kskidltmbigp2etp4pdl67ke2qzjjw66wqairzr4wn2apq4o7bka.b32.i2p:0 -ksxxinje357zctkobwnxsy44ddivq7yp2n3n5gopk4okir2vghaa.b32.i2p:0 -ktua3j43ijxhhhfeljsp32kdiuic5nlnfnkx3ealy7ojva4vwkoq.b32.i2p:0 -kuzu73gzvlnog4cdtdk7edbusxr4pigknvwg2bjo6l46ugsgmrtq.b32.i2p:0 -kw3v6gq5semgt4gg6itum3qtaylanyof7wn6bnbngdeby4xixuoa.b32.i2p:0 -l364nudwoj63fe5nsjmniiun63e3ycdqrjyknbfixxtre5spx7ga.b32.i2p:0 -l3ach5wbdx3n5nq53sv6tagijrbse3nwa2gkqz5oj7aifyaizpcq.b32.i2p:0 -l5fita4r7niir3hxmu7mzcwrigxinkrn4oqeembdkgao7k2yztha.b32.i2p:0 -l5obkk7zzop3nztnt6ijugz4okqsyhhb5o6gkbqottgqzzzcgvla.b32.i2p:0 -lai3534z6zs2tukzixdagrciezum2bkyuask2srxjrn67yu4c57a.b32.i2p:0 -lbif3mgg2b2ir5dkz7u6iatdrui2h2a64vlmffcfgqnpjuvwzaxa.b32.i2p:0 -leu37bptuuu5377mi7cb5t2vsu4hesblyxl5zptnnk4vodhovwea.b32.i2p:0 -lfuvzzzceuik5u5pnd2i67amegel5ua2rrnncxkyyc7bhteq73aa.b32.i2p:0 -lgpojpoix7zd6dhpo5hdrnwm4ueyjvi7tbot4qsqybk3upuocnpa.b32.i2p:0 -lh7qjombcmiekvv6niz5eflr55cnd3oxx7nuus6vmehqfodr67za.b32.i2p:0 -lhupu3owhuc7qwvyfazgkbcmr7sjp5qqxps732vy52v67fsn5guq.b32.i2p:0 -li4vuovafxjrf54kvfg3mjrg2mebs6edpl5yrr2dohddvgmxjyvq.b32.i2p:0 -liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0 -lmlf3yjyg4djrb7wtzmrb4fbkorqba7k4lvk7ax4omay4mbytupa.b32.i2p:0 -lpal67whroip3c2yj4fxbayj46d3tr5osyqog6el5n6ctktdnakq.b32.i2p:0 -lpektonr2uyiohuzi35shtj3oaa77rklmqsivuydxkcxkea2dwuq.b32.i2p:0 -lpffyejskwwap2go7ommmryex2autlkmcnnpk2tm6aitxcalwrha.b32.i2p:0 -lpqkgbek3ci3w4qobpeqepjor3bukz555rzlmghck4o7wwb7ajza.b32.i2p:0 -lprgmkc45te7skx7rffpz72ca5c3zdg3tabiksdboao5w4wceu5a.b32.i2p:0 -lqn32kgic4cincyqlybpwbywcrowcxmscfcm4mqt4fgp24qs3y3q.b32.i2p:0 -lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0 -ls52j74gwtsrqhlgqcai2cjl2rcivfib7jzovc4454h6tq3i6k7q.b32.i2p:0 -ls5otp5mybmxqsaeaid7wlori2ukieehr644adjfwdxux7jxlvga.b32.i2p:0 -lttdnbluvybzbjq52t5vbdkk3pvzc6zyi2oji7yjdpcgtgz732bq.b32.i2p:0 -lunkwblewltvq4spt7j5u2nfpqyndvgepl7edkiru322mmtpy2lq.b32.i2p:0 -lvdbqavgdom5h5denwkmdwslfzxckf6eddwflelbog7tgo2m7usa.b32.i2p:0 -lwjrapkfexjyjqf2rrdr4ghhxmlr3jdygsonetgtheglvmru5x6q.b32.i2p:0 -lyg26sjkcx5ied5a4a7jdxmfeplfcnux3fux5rsxzkm5mgbbsllq.b32.i2p:0 -lyqmygrc6gujxa4xlnwqku3vtfkbrszdiirsagn6xd2yw4kvodrq.b32.i2p:0 -lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0 -m2k7ajij2wvgfpsbg32zuorbsjt72iye3ozz6dbyxtj57fx7xsqq.b32.i2p:0 -m3hlmj2gz2co5gu4ss3wj4b7ebeg2xbkrr65ogxvhn76uxna5qma.b32.i2p:0 -m4o2kndr75clxemwbq5m6vnok7eiqshf42wjjvag7dtwxtafxhra.b32.i2p:0 -m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0 -me6x2p4m6jw3cxi2xl4a37u4orzmv3xdopr5t2vgwjmauiuqrmzq.b32.i2p:0 -mf6tmlegp7uga66cdael5376uaz4qd3wacuh44yvepa3kbu4fk3a.b32.i2p:0 -mhgxec57s6h7eixgemsghlcuhmgh7m7p7phqd5kzmm4wovrp2pqq.b32.i2p:0 -mjpulaafdyuanouslfpjcsvumi4edtckfu3ffn3ipabkxj4sn35q.b32.i2p:0 -mlakhs4ixcqwvk4vo4ce3loa54wmdlfingk73jookrkbra6ppq4q.b32.i2p:0 -mnkqn3r4jmg6vrmlprabenndyft2z2jw6g4nsnolt434coiklmyq.b32.i2p:0 -mnrbc3qi4zuk2tzghmy55kplawncih6jkmt75qczfu27enu3gcea.b32.i2p:0 -mnrrefebq3yxr2avprp3ay7w42sx27ijv6stjljzpwohnfnkg26a.b32.i2p:0 -mo27t6wym666b3wfauhndqocbetdsssxksep6x4dcpuh5dxe76oa.b32.i2p:0 -mo6mp2tymma5l2swob6kqzzb25ccmgccfj5pic6omjkktv4wve2q.b32.i2p:0 -mpi7bivbr2pywsgasslw5we766m757os2667h3hqnhcftaszdv3a.b32.i2p:0 -mpqb3jdmdibarrflyiik5wj3ekitxpe2oqieztlax3uomxspgsvq.b32.i2p:0 -mqocuhx3qwcwfuuin42yuhtqgm76drlmfvzikf7urot75qw3ykpa.b32.i2p:0 -mrbhw6ow77bjqmb67rurbkcl4xs2ocj4pti6hnz4wcsg6bduwtya.b32.i2p:0 -mrypjr2fagjhg6z4ixr73f5npkeyoxsjamcdv5uc6oj5oi2ylsvq.b32.i2p:0 -msjl4a7mdp7x2bcllmbxurhfmtxvolykonz45psmh7j6pptfyy5a.b32.i2p:0 -mtlznxqya5nbuyorybzul4cpdlrnvlrhalx2eogwjce5j32js5wa.b32.i2p:0 -mv7b44duaxqpzbdztnrdvnj6ypsp7yhs4z3dc2q64jov6pritmja.b32.i2p:0 -mvs5a3s6rgfbvvgq44wzyd57vf5pr3jcthc5qdo75xgj4slsm7tq.b32.i2p:0 -mwcqoe2lu7u6ogwo77kr5sr4wx6pxnotkdeck3yyjfh4uklytj2a.b32.i2p:0 -mwevh5r5dkzddlo2ol6bojpdds3kno4xqoy6p6ulid3paamgrtla.b32.i2p:0 -mwyjzdrgtypbwjyulw4ifetejz6xusqstvzylztsphpg2r2zf7ua.b32.i2p:0 -my66tuvzfyy6kkbdeqvgfpk3xuoxerucxt73tw6wxv3ian2p2snq.b32.i2p:0 -n3f4ngbs2igvp3j27vsi7thguqxoyvbfenaqhgypuqdz5iovek2a.b32.i2p:0 -n3fa2yuf3i3opdktiwyxzhbpudcut73valxdrlre2xs2ooepddaa.b32.i2p:0 -n47e4gkf5xujcamnsarfuy7435hfsgs4zhndcxaw2evafn6r2rma.b32.i2p:0 -n4n7bivjb2mffgll2ulpwyb4m2oomv5roxtdj6bmlb4cgpf3wdja.b32.i2p:0 -n4zwusew5coibur4p2g436ktc3cyogz3sklztu6ruulag3je6ita.b32.i2p:0 -n7ykk3cxcqzcoeipo7ghzb62ko4d6bxzfgenzxistvg6fuclebva.b32.i2p:0 -nazasriqoa6qoxdlgzjwsggubxl6i4nge5q7om7nijaqi24ulgua.b32.i2p:0 -ncdjjthck6v6phz4laddyc7a7czoujys55melfcoptvl2h4izqlq.b32.i2p:0 -ndtoi53fz7e6ml6v6jn33675nwciw7mu5msn7afzbhebprusqg7a.b32.i2p:0 -ndunnsjyp6l4w3jebow4zgsfrdsy2lrapjgslb3tv7dg6oypfbwq.b32.i2p:0 -ndx23xqvt4qezezih4wlj7mqtwc4nzbvmgseq6fc6e2ddywrmkwq.b32.i2p:0 -nejmippeopyo75wd3gjrhca3fr5mo2g37owzwdezxmg7uhx6ygxa.b32.i2p:0 -nfsi3fenzrzoccj7bpzuvjbxnij7dmzuprg7ia4geuortoquja7q.b32.i2p:0 -ngn5elnvbm234yyun5kbjyr76oy5nhrvyckn33cqcbx25hw4lfoq.b32.i2p:0 -nhpbv2ravt6t5fhxyvuhrxyma37wph6dzuzpddlw3uoivzl6tx4a.b32.i2p:0 -ni4ns3ou7v6zh5qrawvkwnmshnrzcyc5zojkw647rrniplmurrba.b32.i2p:0 -nigrfbou3zt6wxegn5im4cyminjcjmbsqror7ntcr5i7yv6chwvq.b32.i2p:0 -nij7pzb6mhrra5glb3dyghjt55sngwrikzdlagmpsf7jn2onvoaa.b32.i2p:0 -nisd4was4gm3pkvuwjh3sbaoo35jtxop6y2d7ug4iol4cffkrk5q.b32.i2p:0 -niyz7v5fdhqqtlr4y3tcgdoeu3myntub4trzvgixlgjbmowccgja.b32.i2p:0 -nloq52novup3cawccvaakmbudooatwkw7dqltnr6q3j4qy7r6oia.b32.i2p:0 -nn7p4y7pun3m3txaqbkeptkxykzwrf75ru2zimadnewj7g3r4una.b32.i2p:0 -noj7le7kkj54umo6mdftagvvk327cuir7q75bnvuphrxa7kjujna.b32.i2p:0 -npcmehkhh4z2wtk3f5426izrytvqvyf6aa7hyx6hf6jdbxveqima.b32.i2p:0 -nrrg4p7tztllzthlkqzomqi3dejfcak7t63n7zzuomt5atzz5m4a.b32.i2p:0 -nt3ysas4wpjgkft5pohrfstm2vgj7t2vx34u32voy7rqon7dlbga.b32.i2p:0 -nu2ao72zway2ponkhrf322wyfrrn4mdmyp7n5q5xzmjhcge5odma.b32.i2p:0 -nufliiw3uav3tzdalit224yhbfpcjtgfrm5ic7ob6l3mmsay6cpa.b32.i2p:0 -numilh7hhhf6inzkzway3hzif4kiroqstxqbz7hzvoy2ctgpaqda.b32.i2p:0 -nuwphtuudfrswids22qjq63zgxh5wu7erafl36jyniuxhz75ikyq.b32.i2p:0 -nvmuuajhaw74g565l3a7dpezs4rkzm22ub5jhh6mdvzu43j4a6dq.b32.i2p:0 -nz4lq7pmswngaevv2uqyainqzutfxlkavxgde2w2slo2p6e2kcfq.b32.i2p:0 -o5ijpzor3en5xnndm3ntti7o4fxvv24t3veh4g7mahk7ogesb67a.b32.i2p:0 -o6b747qkpgu6gvsem7leylvmxsaaqby67pu55fmqn52dgazuvbxa.b32.i2p:0 -o6t4fr5ayfadzieutstgwcllvwxeuzjlxmzsmpj3hpkvefhzfaea.b32.i2p:0 -o6vbupdnpd5bwvcx7ivaecgyo7x5vdu5em4va6cmx5iwcf5tyaca.b32.i2p:0 -oaeqbkgpek4qnm3nly76x2tfrad2tun2xefliez7a3uxddeq4i4a.b32.i2p:0 -obf5kfk5n4nnsw7ez6ls6chqu4lz4wlck7utwvmjnlin4nzfnspq.b32.i2p:0 -oeydvkjoeqy3473wxkkbmoc6zz5m6zcmf6ov2hfkci54efsityua.b32.i2p:0 -of2gy2vblht57tn6yfczslnmp2xybdiazzta43y24w76tl6tu2xa.b32.i2p:0 -oggn6qbpmbag224gumagzgno53mgozb65tpzt5lezjbfbbiqky4q.b32.i2p:0 -ognn4mwwtmtjbrnq2kur7spcfohivxlrvz3sfamt3t46pk2e2ibq.b32.i2p:0 -ogqdcq2igslh3n5jn3utz2vpevttul366bt2246vilfnowuyvova.b32.i2p:0 -okjamsyd4wutvhfhsffejwk6ioru4mmvwagfssoy5hcocg2gj76a.b32.i2p:0 -om32whhwvcsbrf4g6uh5hupsl67oapccourkxyr7uf5zwaqxtxbq.b32.i2p:0 -ommky7qetuh45h4lk3raili27fnbhsgxv3zucinoaymnymo5735q.b32.i2p:0 -omngcjfwtiyqwbfqqggzbkttqgm3blywu43kpto2py2e4gp7fhra.b32.i2p:0 -opnpvz7mzfw6nypgmnn5zgtlzx7xuc4w7vat5bsr4mdtp77kz7eq.b32.i2p:0 -oqrl573nw6my2o5mup6uq6pm5immw3gnviahig5cceges4wfnyhq.b32.i2p:0 -orvshryqq24l24e4dvockx2ekj4hu42otqxsvyvy7tm7hhdjsz7a.b32.i2p:0 -oukeldqgovavh3npgb2by7w6hug575uae24z6uqfdl6flh7ma6rq.b32.i2p:0 -ovnk3wfbrkvvute6vkn5glhdtlxr6nyvebiflvr5l6ws6sorpa2q.b32.i2p:0 -owexluejb3eszx4p3b6zuxyggsxxtkxfgxoylkagfecs3bgfnpja.b32.i2p:0 -oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0 -oznpphdisfvlcjgkvny6ma62wy637nh4vtpxww47ifpmlqkjv3ba.b32.i2p:0 -p3au2w5jnkqugxnkukj4rusvynvz3oxawdf4ajzeyxvfvyzhmetq.b32.i2p:0 -p4tsqwvdpaitvlgaujfr2m2qbr36qiwusas5zkiut7w2wjcp3sqa.b32.i2p:0 -p6o3tzllswm2j4wah35niry4tcdu6lq5b67ehevcx45sae7pb6da.b32.i2p:0 -p7ifeij3vhds3diihx5qimucyzgck5omfkqxc4pkbbjtfu4hp6wq.b32.i2p:0 -pbag76x5yyo5d3wypvtohxmgbtdrjjb35ljnq4w5fpoguyt5mj6q.b32.i2p:0 -pbftrtdthbj5qcecraden3hdvwomqrgseec6ib5h24n2zcivdqaa.b32.i2p:0 -pc4d5v74tr4vz54pbr57ejga765ep6vwk5kox55gfobi5572apta.b32.i2p:0 -pcc6cnry4maul7zlbd32khalaavkcbw5hdjuk4zjwposaorjicca.b32.i2p:0 -pcdlqw2awppohbiued4rffgs6n3lv3thhon3r67jmx2652qx2khq.b32.i2p:0 -peteksofgwgndsdh6ovh2ydkrgpyqgttit4ususs4bzksvdqkbea.b32.i2p:0 -phendyytrqdr2vfsw3kil6yui5vb2p4v5xuddezg57wsdw5uyquq.b32.i2p:0 -plhoz53xhplmyuejnsg5bkfe24ow3pbldysoovuupu6qwb3nttca.b32.i2p:0 -pm4nukrzndd2lvd3shivpjrcbjlontmxhag2xzdf572snwbr3p6a.b32.i2p:0 -pn5cx32ljrvzj6x7hpgyff3rlftextqpp4zn3nkfufrrpnpuimzq.b32.i2p:0 -pnhspu3rloczdbzsysa2iftsgoiy3zgcd22jodmk7zdjanhiemla.b32.i2p:0 -ppe2jfsb2xrmgwugbq7agy44ucb6yq4qbufaf2sh76b4kwpa4jcq.b32.i2p:0 -ppez53yrs6lanyvyxuxblqxiuvhnqvvtafmwaid2kgp2dx2v5iaq.b32.i2p:0 -pqnqwxl7jsrok7vgpgcvlxwlkg6yckx33n3g4xf5lvuntwn63b6a.b32.i2p:0 -pri376r6uuwgnbnevki7c363h4ryfwjza7pcbfswqqxk6hnrkhja.b32.i2p:0 -pscw5yzaj5js2fn7gzrzoj6teonlsohlbnvdco65ubdefpnpwhpa.b32.i2p:0 -pt3mqmvkv7aleja7vattlysu6x7gjnbwqvwtu4skzabvkjztfi2q.b32.i2p:0 -pu6e2b5bz75qnmp2rox252aksllnitv2grnn7qfyzjkfio7w5h6a.b32.i2p:0 -punslpht6pysnlteht24rgvrkmzdd437lnpflojwakl5dy6mbema.b32.i2p:0 -pv6g7uin653rerdiivdgtoirjvokjowi4b3fwatszdlteyos3i2a.b32.i2p:0 -pvqyvn2lpvoeyhgcgunoqtetkrkp76iegyoii2af4crnlto6gb2q.b32.i2p:0 -pw42656k2vbwxmvrc2qbsz3jslvcxahln7rehsbia5jdio2knh3q.b32.i2p:0 -pxbyhv62tcdqqpl6pbp3og7ajzzcnbximv5kyt3hid3djd3uwkdq.b32.i2p:0 -pyf2csixjugwp6ad3bkry2ulkzj7inc747dsmpk7iebuidk4l3ra.b32.i2p:0 -pyole4gslrmenfcmd4ilqyzvsuyrjyffjbw7angentqjkkljitqq.b32.i2p:0 -q3ueujd332k5qjxdqkjtjlgkm3ktvdy7ats4c2ogcvokog4wm3vq.b32.i2p:0 -q4o7bf37e6afx7evwdyovsqptjwo6td3c6qtjh4rtdngp3trwi3a.b32.i2p:0 -q55g5g6s47hi7pcuomug3vrcd67vji7us2gqmfe7qn2nkq5vz52a.b32.i2p:0 -q6lzsezu4idxpdwro4x6svwz7j6h6gso6enidcxv7jhc2gbepuzq.b32.i2p:0 -q6o3eqnyg44uzjzqeudsankgdouylshkhdhl7b4bqxkbmdnm4iaq.b32.i2p:0 -q76g4lkosb2sxenh47eutqgwwzjyph52rirc635wkwnxsejrzdda.b32.i2p:0 -q7ntdwy6xueyvghbjamfrh62aqtuu3ikwg622em44pa3czomrdjq.b32.i2p:0 -qa77lz7dl64qwtj4fxxlz6otkuvv42dciggnmx62eobs2xqi3vlq.b32.i2p:0 -qaqvxmyvq2m4wombmtaz3our3qmp7eet3qle5flnrs3a5wgfhxba.b32.i2p:0 -qawed5ou5vb42ugi42goxr2s6cqzpyh3s5atkhvfvyhyc6anxyaa.b32.i2p:0 -qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0 -qelsaseevnmz2unpovh4nbpjpshjg45iudiaf5zbngealwwuxe2a.b32.i2p:0 -qfbughfr5hhgoomasyviwk3zin24uerpl6urz5smzxc2div5ixxa.b32.i2p:0 -qfl3i45ipgugo7ueswy3ynnbaet77xawiplvmm3kp4fj72qvzc6a.b32.i2p:0 -qhuk5zq5v7h5p7o62gsxgtqqo7va4i77o5vei6wttxqcgaw47h7a.b32.i2p:0 -qivuqkrr3pv3rul4wgx4o4zon5wegidt5auylv3bhebfuj6oqauq.b32.i2p:0 -qjdftbhcaghdslzxjqx3nmem4z5p5jt7e7ou5bdz5llnqlxshe5a.b32.i2p:0 -qk3iq3wr6emttdilvdqbv6vnqjshuzz6mylwyfo3z6vpjywvnfca.b32.i2p:0 -qkohzoxigef43ro7mf2bd76eyneuuj2vfyremufvufssksbvj3jq.b32.i2p:0 -qksthizqtfdjjxcrahqxkl3bev75k24blagrkoszxen45zelijpa.b32.i2p:0 -qlhklv3q3rrszbrkxw755lpdburxwcj5dkxwicas46flztlkdcja.b32.i2p:0 -qmtg5ukzxemsktsxw2brwmohehyehwlleky3kuzeqzy4ledcou3a.b32.i2p:0 -qndgqhj3cpbxrktu6r7ysaooccqzvselvn2tphu3plx2z5ouocgq.b32.i2p:0 -qnqojlthym7z4gwizcblhpd2thy7v4a6ifme57bzyl3nxzkj6ica.b32.i2p:0 -qorzdjceszf432obxa73tnwhqb7ltxrxlfkkqmw2flmfjhoyv36a.b32.i2p:0 -qp5ppgozzbkuingg22zgamf4ozpe2n5hjlu4i25r6pjqw2ngrhoq.b32.i2p:0 -qpddavnflr5tdmeypeu5lrjjwsgtdhz7hw5emxiyjkcp7m7xysca.b32.i2p:0 -qpo3u565rmgeioruszadbc4vmpgjyoh7qorv4lyefl7geewyyz7a.b32.i2p:0 -qqiakw24obfwz375gfb6muzaz7tr6ani3od6leoox7jwzrizyxkq.b32.i2p:0 -qqmxvujwi4ktgj2cuqmw4kiujkf7ukrkoe5ryy4bjb7tyleplsja.b32.i2p:0 -qrpz67rcwrbpcockid5ml24dtdhhhekty3xd66ekkyatpfjd2wka.b32.i2p:0 -quzkrgzb5pmn4465647ke5lsfbseqnorr6ljvfsxcagj7rzl7hcq.b32.i2p:0 -qv5e4jlcmmkdlmh5spkvv2wgj343vm4yoty2hofuzi4lornn3hzq.b32.i2p:0 -qwhvlprhk3ntswr5xntnc2hhgmvd3bbgzgkbombiibhrsj7k6gyq.b32.i2p:0 -qykavpjbecssape77mrxjxwxces2gbjd6gzewd6zys32uhmnnw3a.b32.i2p:0 -qyqwn5xs24h65rldrle5msyarmqof3lb33uz7sutauwdg5qiuhoq.b32.i2p:0 -r2p5kqr7xjo4ncz7l6ekdx2ge6su2j22j2tdsoxu4jw3u67z7poa.b32.i2p:0 -r4ukdj7c2k557k7qd6siauhhqucshwy2rrkm66twzyh4jiucimaq.b32.i2p:0 -r5d5jgscvs6ix5v646ohwa64vutu7umfeknrc2hrezdjtlr4lm6a.b32.i2p:0 -r6d4moarp22wnnsnmsxqt3s32gzyscaccackcazvimrep7sa26ma.b32.i2p:0 -r6hd3knqi2p6kaw7hybrcf2q5lcarulcczs3sgcuz4yc2saj3gya.b32.i2p:0 -r7bug6wbhevqqlbavouj3ggpa7e57sbd3oivkzqeyagrtxshmjpa.b32.i2p:0 -ra7ztq7oq7jcozpui7c4zv76gh7rjwhq5fkpxp7dvw7ritick66q.b32.i2p:0 -rb7tyjd6gi7evmt5mzvtboramqip43sh72zjxnwhj5k72zfi3g6a.b32.i2p:0 -rb7x26lmepfbcd7wtxu42pf4tdxbe5p5zsf3cwuukd4fs4zhxtba.b32.i2p:0 -rd2cw3iukuth2lwe44q7fipawrne2io6y3fyyv5xew6vd3hos2qa.b32.i2p:0 -refo4v727jmff6ylrpbkvd5emlfr2hamaeh7zho6oval5dmnwlta.b32.i2p:0 -refrtydbdslzcgcsmmph3435qigyajh4q2nvl756f5yojouln4yq.b32.i2p:0 -rfgsjhyvqbunef5b5r2emjuoxx2i7rcsl7gathy2n4gwjyyat6bq.b32.i2p:0 -rg677vpfzyhsckzzcvoyvqdbwtdkqig7lxv4unmxcz63vtr6tgza.b32.i2p:0 -rgbq36syjadm2ex2gftc6xztivckrqzcjszla3jacwfo5hqutzqa.b32.i2p:0 -rizuiypjfhukt3bqnetppoauovuaqq5e6jzgd7tgy24zrwa2ydxq.b32.i2p:0 -rkhb3463btvfozwta37itlkt37iyncpkzak2xhoe4kg7tqafqria.b32.i2p:0 -rl4b3r5h5xodo7kiw4nykd4rhoc4j37kxizzyb6ukgcomyc2qrya.b32.i2p:0 -rnsjgirap5lfhxpb2xczuawgoztb4ptgdwt5rcb2bz72vhtai2jq.b32.i2p:0 -rrm2pems425buhonptp7lbtbprmwwjhbftey4ujvk25nclx7rerq.b32.i2p:0 -rvjzxak3jvwwti7klfb64wrsmlfcs6ceiqhzbbmjynokn5tz3egq.b32.i2p:0 -rwgf2wj2x66xtnjx3dggxhkuy6gvihvur42tbkoej6bd7iukoqiq.b32.i2p:0 -rxatc4b7obgosvznpqrmyrl6ty2yixhi7rpbh45sopqwzglyimga.b32.i2p:0 -ry3iuaabf5ek73otfvchwrqryez3nsgq57bpmzkyzumqhfbhgtaq.b32.i2p:0 -rypsyqod2yq3zagcvvc2643vydtv4zm2ew5r3w5kjzyq2snvzv2a.b32.i2p:0 -s35hlnmumkgdsvj2gepnwro4wo2h7ts7ddjhhihqggywn7qcym2a.b32.i2p:0 -s3rbe5n7lyy6smerpkgr4ictzbvkciu7gxyj6zqw3xyw62rmivha.b32.i2p:0 -s43w4tsmzmddvu2cxugh2lx4o5mup3rkvjhm455u2qqpg4bqlhyq.b32.i2p:0 -s4qlly4iwzevejk4ex5zfqhb4t666o73mvdmy4gpu47tpb775nja.b32.i2p:0 -s5ls42vzfaqzgrjr6cvgkmgifei2rtvj7uzaljkpsmt62jwtmvxq.b32.i2p:0 -s6umfzwe27x7az2yjsgqftjzawoj5lrcrgxldkfwfq2qwobml2ma.b32.i2p:0 -s6vsdby2liaahn2fh7qvrehqfus7gaz3p3u3rpjtfjhm4ahvz46q.b32.i2p:0 -sa3k2xipbuwm62bb5n2mwaqyyjcvxzb53kmzinoojgnjpnqurzeq.b32.i2p:0 -sadnlzguaa4k6kvpiky27izp36er3i5h74l452povbnajqullpca.b32.i2p:0 -saj5uchj7dzmxjv3kdzalgtbqzw6wu4wzxxdiobc23m452ehk3zq.b32.i2p:0 -sbalp2doxyedtr52kj57va2rmbi5npspv4drk4vxnujag72gtpiq.b32.i2p:0 -sdxfzbgwxpf6hbik7k4bqm63wm4xld7qgo3hjlhknnehzxyyeu5a.b32.i2p:0 -sh5hww42vwlsl57cdropaeqmmwozinnr2tg6wq4prg5wrkusvxja.b32.i2p:0 -shpd3cifcjoebw6pskj4pfmrm7lwecrygjnje55heorhsxm2lnrq.b32.i2p:0 -si5x3fon3ew644friidc5o3syrf5v6kk4pxxjvhibev3odxk7nyq.b32.i2p:0 -sikkmrxv6wat265rpay2tk7jywyvlzkekpolmwyp2el5g7iihsvq.b32.i2p:0 -sjpqyf3rq7ojcalldlybvyyh5lqiq5j3ade5w6txe3473ybhk3sa.b32.i2p:0 -sk7aivked563g6g2ri2saggni7jqzxmucuqa6xkudcgjvpbjsyda.b32.i2p:0 -slbbsiq2pmouqht3hznafnowq7sxzlidmwghfch7iiq64rzdhwra.b32.i2p:0 -sle3cbbdom6rknc3drqtawctpy635ica5d5gerjjdahfymkok4ma.b32.i2p:0 -slnmute5o6h23ldim34wro4zh4qa2pchnskmdpek2nzc7u5oz7jq.b32.i2p:0 -snfinsblh4j4wsv2n5kmkfxbvqzcei2ryfyu4heqy6u73mosep6q.b32.i2p:0 -snsw3ewf7wjtwspiuj33h3vtxnybllurzcwm7u62iutf5phoitkq.b32.i2p:0 -sooo7ajo74ajo6m2yomcc6jcofdgkdoyjcbrpl3nyvvusr6fw7ta.b32.i2p:0 -sorobw22rerrhpx5t67joyqai3ou6xsvqxb7wdomtnwnqztm4sga.b32.i2p:0 -sotpvcqqzzmty6llimwlvknqsdcypn4wsnwk677kepzmy76w2gqa.b32.i2p:0 -spbb34lslk2tldwzr4ydi2culk7sxgl3imb2gg746xbxqqcj7vzq.b32.i2p:0 -spuaa2y6qsaywypklz7itcb5klesogef2x66m4flws2r574qjc5a.b32.i2p:0 -sqjjqyrhh45jpgfp66idiirgh5ck7f4s76ee2l5bli4obsotu7zq.b32.i2p:0 -sqjorsqambyienumg5qpw3foftkp44vpsd4lwklgbl4lag4mm6gq.b32.i2p:0 -sqr66feh2g3f6bknt2tnltmnhqdkzoq3jhdaatfusshrv6v2zhma.b32.i2p:0 -stltasmf4b54srrjb3mf7hjtjvmvvms26btxakccdtllgrm2qzgq.b32.i2p:0 -su7d4biurihkyr3qeea7makkxzikxr5zi4znvryh3bjespppfhxq.b32.i2p:0 -swmtaospvaup7me3dvzlw5xoeohhj4zn5q6agivif7kxtseweriq.b32.i2p:0 -syhxehvl6rublw6k5ysmzcsqrzdsnd7eqrbwalfkvhgfccpu2osq.b32.i2p:0 -sykjw3jnb7n6bo574wnpiaxhp2nm4gc6hc4jh4v6trsbpboysooa.b32.i2p:0 -syqxyl67b4hdo5u3jtkkzsabccvtjaerpushov7nrc2f42x67fja.b32.i2p:0 -t2e45js4dn4cfsyyevm26z5ltvmu6lftxziji4fm3v4v2t3ykaoa.b32.i2p:0 -t32qcc2tbjgqxrydr2txgm4ahhhae3zkkojmguehw5gsbtrdvxsa.b32.i2p:0 -t43qqzux7ik7kki2rxtillcgbxrznuhjac7wtqh52sqovk5ay3xq.b32.i2p:0 -t4notlid4bejwz2tzucpvednkeuskenpnu5sqcbdhh3lqouigqxa.b32.i2p:0 -t5cd7q36no6doxduuvk5psdx47zl7ousnckjgw7c6zr3o3ke7ffa.b32.i2p:0 -t7gbmefspnynaezmvx445fjapp24pjjf7wx3evpwlmolzyu3wi5q.b32.i2p:0 -tanmhvkoyd35kf6a2nhj5rmbwpt3shc6thypsle45my565womjya.b32.i2p:0 -tbqehmm3nuuf2spwsjobrc4hg6uxji4mdelivhywz4b7f5lv6rka.b32.i2p:0 -tbrjczwl76v7ob6hon36z6f35otpv5g467q33pgzyyakp525wwfq.b32.i2p:0 -tcx3ftsdl36ukysuuewydapdzuu4alewyg22squei2wda4a74tba.b32.i2p:0 -tetoqjagsf7fpejajiwm4rosqscy5huqbz5hcqgfuha5tdfnlrnq.b32.i2p:0 -tf4tozh5unsgyzpdsmrdcpbgekw2agu7tp5jvyclzcs5kjudwwpa.b32.i2p:0 -tfuvti7yonn5pjptzzvpshh23x4rqjvm2usolrbnlu42laj4mhyq.b32.i2p:0 -tg6goh3flzmcer5voft2nf3tudm7ikyez334zry66vqxmc4ieixa.b32.i2p:0 -tgt7rdhywtlwob47flp6ccq7prrbh4ipnwm3xszuykq7be2pksyq.b32.i2p:0 -th3dj5sqw75lga3tnffbsywajxafv7cvlb7sed6w7q3w3sxuqo6a.b32.i2p:0 -tj2upmck47iktfh4vncmyajnkbatqglqzy4coqef7wioor4hbsjq.b32.i2p:0 -tk63xbzug7def6esivofwq2h2c53ar3ot7hsezdq3amxqqaoyr5a.b32.i2p:0 -tkzuysa4lkad53cywbt6sgpcndvvvdkjeatpkwyfweorx7rfe3ba.b32.i2p:0 -tl3xkknuukvyinyhvt7saz3tvz24ptgyqtzy3igygyfapcf2o3lq.b32.i2p:0 -tl66bkfoqu6eameaqtlwrvfttyc6xj3s57za3hd7omnfnjg3i44a.b32.i2p:0 -tlfttkbshrcixu6i6syntl5xjsoh6mtgfpix54knahyeuhlju4ga.b32.i2p:0 -tmmjmcrwegjke5fzv2hha2wkis7l6xdaa7fkq24ge5rbvqpwxzpa.b32.i2p:0 -tobdew6554c76jhrulcd2ssgvef7dryini2xjxem2zushe37ycua.b32.i2p:0 -trucvlawpufrszky4zzhhxtddnhio4mnqawzc47n7kik6i444m2q.b32.i2p:0 -tsfr6zvcgsmw2ekaxqqtkdrnbib5uio7lgmrtmscrvwe2d46g7jq.b32.i2p:0 -tsrlbxayhihugr723z6rkyafglnhcyzi2zhojzsyfdjsqkkd53bq.b32.i2p:0 -tv3x4kddbu753tnlghgh3txogp26tlydt47rl5scx7eoxgnocf4a.b32.i2p:0 -tvbutrv73xhwqbtosmbp3cesdyc5bbtslay4gjsf7rzdx4ztgzaq.b32.i2p:0 -tvotv5p3emxxnti2bnvucbfy4to7gxptwvh4qznuhy62hghnju4a.b32.i2p:0 -txpr56jvbf3lmqgaozqdqzgckfpugzyd4cwplkjootvf3hk42ibq.b32.i2p:0 -tyfkhz6ggpi2rykez3v3j5f3evnjxfoau7ve7m2heaukrcqiui4a.b32.i2p:0 -tyvsuqy36cx2yvf7jhnkd5ojc52g6vxl2rw5qshqwpk63ptovdda.b32.i2p:0 -tz5txdipkxcnydzcsuqw47qxdvpob644u3cttlbrbfg3zp75vl7q.b32.i2p:0 -tzudbbctweb7rpnf2vswuw26j63ysqztsbt7lfpfj6xautueiklq.b32.i2p:0 -u2tnrysboqqwjn73awg4hfxtfjgbqab6vrdgyu43s672jdcanhca.b32.i2p:0 -u5ixxcd6slvzxouj532njusx7ec4wemrfwmg6gwltlnkruubi63q.b32.i2p:0 -u635477uxqs7z4uvwx224u6ojn3c3ewcb66f3j7qlbzqyrrevxja.b32.i2p:0 -u6wrw47yfjdzk6a7nc6c6scvfokwuqmvuhxehqvymrv7owiajxia.b32.i2p:0 -u7uklnwthbrynr3z2gc3yxfmi5yoemsugjbb4nm44x26f25vxp5q.b32.i2p:0 -u7ygn3heosxu6l2die34y7wteexfp6h2w5j3nhr424yoblysigyq.b32.i2p:0 -uags6hm646f2qsyqfhzjt2xlnjqbiopiodghywosdgz7bwtbggta.b32.i2p:0 -uc52rzz4xu5ikx6hl6r6sqxfmiyyxsffpcu5frrtepczidwjwuha.b32.i2p:0 -udfxh2r5yfu5z7ynzacur7p3g7ug35kfa33ghes2bazpdivxlhsq.b32.i2p:0 -udkwqdo5odg5npn52rueipghn5omhvojthzdmvcvuomgzglum7fa.b32.i2p:0 -udzbx5jyvrp4g3iujlca7jnlaaaa5m3e4jv4sbr7tvp6k6cdjc5q.b32.i2p:0 -ufgoaa6g746zzpphuvxuomuizkyfpz45chqta7skrywqq6cjbqna.b32.i2p:0 -ufittrlr4eautphuqzuotc7b3xx27n4xgy5afm4foc6nsv56q7ka.b32.i2p:0 -ugw5zbhs2pvsgxieklmc6z4z6d5cvyux4pctpf2udhjgxvajot2a.b32.i2p:0 -ujg6b4cyxhi5pf4puwvwupur3iddm23uibapigpwl4bstvlt4cva.b32.i2p:0 -undzufsjeb4qlf7y5llh56tji6zlhtshlsyht4yjdsa2k4ayx7vq.b32.i2p:0 -uobwophnzqq4yhpp54aisud5ojgrxq6pasmq4aq6qw7dhgjcoqpa.b32.i2p:0 -uodycjdscpurlego2nrs7ptoze26p6236t2r2tax5ubdgi6duqaa.b32.i2p:0 -uohuxnjd27cftarbf6kh4czmotwvstpon2sgs2vpffqkgmg7guxa.b32.i2p:0 -up2kudwqomqrwvfognnhz2mjwqvkgpknfyscp4ue5ioev3q4jd5q.b32.i2p:0 -upme7c64dwjgbt7w72yf5ydl3dyp25dtenrkq6z3aw6hbircqzsa.b32.i2p:0 -uppxodf6bz3qibvpzzvtedl5lk3h7fslrwmed2cmqvdpgtvqkv2q.b32.i2p:0 -urqlr3cei7pp2cruga4txxmmvel3bh7nsbqzqzpe7omvmbm4v75a.b32.i2p:0 -usgqijrwhtwgoekjcr26yqcgpncwpsescrr3eek35e3rhkrtptoa.b32.i2p:0 -uu47uxdqqtv2pqorbaxnhhfmcsxmknvpreambqqkosr45b44h5ia.b32.i2p:0 -uv44mjoqrj3m3gzz5wxlnszt5pvgk3iqlc3pmqfe6un6gxays2cq.b32.i2p:0 -uyshm6nokdjyq3l43224at2rigpa4zmiyybuufyq22t4l65ialmq.b32.i2p:0 -uysvdsh2bzicmdqqdl7ezuftxcywzapohbzl5ap5hyiinki354mq.b32.i2p:0 -uyy4dbfyx2i2x3goobc6uxj4nb7ktzsu72zlksypjfisgka3xnta.b32.i2p:0 -uzgfmsjcbjxitt6bed3p3gpdzviyop2rz3cxqyu64ec3z2r5imqa.b32.i2p:0 -vbzp4sjkgqwymn2z4ikbae7rv3clbo7vv4mwv4ft7tu7ubrmbeha.b32.i2p:0 -vcksnyuyw3i6hfviob5yzoynq7okxi677bw7224273fjhsk2kgra.b32.i2p:0 -vdpfoahxse7cjciw5l7ffbwzc6e4xdlf5ulvrk34mzm2gy4mhlwq.b32.i2p:0 -vdv2aitgqica4taqcmjexw5xfbrfbhvf5kuxwvfjf3yiki5a5cjq.b32.i2p:0 -vet6qwwa74jrqrjzcm7ylfprzwpnt3hlzjvkbnaoiv4o2zzkr3sq.b32.i2p:0 -veucihmd74nnumiunvruyjs6kpjs5sqw5dprldlzcf7i3h4igkda.b32.i2p:0 -vewdrismzwnlxlvni7slpq722wlwfami2elghudm2ofcjhpjcs6a.b32.i2p:0 -vf3l3f5unlwrfmr3fiphpomgslxgm6m4chg72itf45yfu3brmy2q.b32.i2p:0 -vfpzasrsrqh3llkudmas5fymwn2ohswqi3vakclgm6fn4nb6s5xq.b32.i2p:0 -vgkou4ysuxvhlxrwf5n2ihn4ffyvvedluun47l6dobi5ycziy3nq.b32.i2p:0 -vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0 -vj54d2pkdeqvcuj5ykeggr6jnhhnmq5q6qe7nttvb6yjetweadma.b32.i2p:0 -vlwovj6fxzvtsypnmslocootmphezr5txanyfz2gjhn5lanrn2fa.b32.i2p:0 -vmatpbu2vf5p76k2emzg2tjyqi6p6yj3cl4z32ncdhz37ubprkha.b32.i2p:0 -vmbyttxf6sw6ivdamftxung44mktqb4vphmm4lqzdqqpcmksterq.b32.i2p:0 -vmoogdd5lztt5wpzkwhd67uwnvpupye7ycsbz55jl25sueowcxxq.b32.i2p:0 -vn5rsr26rp7yxrqliq7vo4zb6aoichaybd3urvc5eedaspxjp3la.b32.i2p:0 -vnxjmzogakc2a4xn5w4qormiqt5khnjptnoaro74ehinrv4q3yga.b32.i2p:0 -voi5u3azhajnt7476tcikl5mactxcvtsbnrzixwkj62qhpaw5ujq.b32.i2p:0 -vpevx6tl6ma6mnlj42d4fke57en4v5r76yx6rcmhtvw47guo34uq.b32.i2p:0 -vpmkctqhkdqgkekt72srqm4sqaliug37uq2wp2ywady3p235cpaq.b32.i2p:0 -vptzpxba7oys3w2htjgh4uxogaedursdh2yz5k6e7yh4b3pokuna.b32.i2p:0 -vs67sj5crkcjo7m74tdunzefj6ahgrgohs6egj5jxmneszwaoo7a.b32.i2p:0 -vuqk76jvxfk55bkovqcmmkvycmndee7j3tuv7ezdb2slrfpjyvoa.b32.i2p:0 -vxokhkidetjp4tjrj7idojx45hguhnl2azvqnbulougvdkstf3ma.b32.i2p:0 -vxs2es6f7uw2uuneslb7ipvmg6kqh6ytpjezoj2ptwx7od4jqmxa.b32.i2p:0 -vziy2cbrbvliqpi27feak2hiewovxtlkqppsagtaxeib6nkonknq.b32.i2p:0 -vzqowkd4aoyekapcskylli77aj3e5fomixsjyiawnldzj6c5nxtq.b32.i2p:0 -w2a73mo4grdgwvkzdsh6nyutagd4bmywywacxviodw7xnof72aoa.b32.i2p:0 -w2mgaza75amrvfocl7wt6v7eimprlasuj3bi4xezdr2wyqhkxzwq.b32.i2p:0 -w2zi3xos4jaz3ft5yca2x5zf34esctpmzqlqpdrqntjmi2o3gfba.b32.i2p:0 -w3hyqnlueb4yv5lkzj3wlnrjp7fzpxnig6x6m3w5du2ptfjcm2jq.b32.i2p:0 -w4arykcvc7eckzuqr7kvs2njsjpknzb6vvsodpyzp6tvu27bzoka.b32.i2p:0 -w4k4gm3chiyskfzshilxjchpgtpx2xmc6euvkyzkyjvzvdbqroma.b32.i2p:0 -w55r4ykzu6qt6uhp33exqbqmlt357cts2u2zoi7hkuphqmv5iupa.b32.i2p:0 -w6jl2gubyscdpubizes5bp6s42cito4k27xwcjwh76rvuik2prha.b32.i2p:0 -wacfewi6ehmfxvftxqmracfh7se2t7ozl62u4hsuyd4c5xfzuajq.b32.i2p:0 -weidpvshind3dnblwtb4zpssazeenkf7a63favavkc4crhqdk76a.b32.i2p:0 -wgrbhqemtf7qu4c6acjicb7uyee6rlinafyysvxc2yocq4t2ilca.b32.i2p:0 -wjfukwyohljaxgv4woewdtpoxi3q6hnwcnefpgrtif2kqfrxslnq.b32.i2p:0 -wlepjf4lxs4e553rtpoys6kqp2ozcv4pqjwzoybawcl3zhrdvz2a.b32.i2p:0 -wmly6cz5j54w2g2gibnhlpvuhh3bky26cq3a5jy6dp2hg3hc34oq.b32.i2p:0 -wnp26nyphqfmq3udocgcwenpsgfwk4ssw53st4wvwt6mwf7wm35q.b32.i2p:0 -woanasilvwu3yfurvhvqj3lxd25bzj4fxwy3ef3qjbso3cozvyca.b32.i2p:0 -wpnewole7fofvwvrvkkgf45sgcverlodocu7fstm2axp5jfykraq.b32.i2p:0 -wrqu543ssub7kiwzfug4o7m6lc5ibmaamdc3o4uo6a7ntxiqzd4q.b32.i2p:0 -wsbf5tpo7ecsafusflyym72k6tbyclgvqav56qafvyc4j3spzdoq.b32.i2p:0 -wtfebbwmsxoywu6nw5cowlxqhtokxrxftve2zee6flvrpqg4j6ma.b32.i2p:0 -wtoh5v7xm3wx4rqutbyvqaixybwlprx5ua2yiv2gac3prria5emq.b32.i2p:0 -wuikfwkext6lbl6urhoysr2abcyff5lkm2ojr6mfenqq25nzlluq.b32.i2p:0 -wumjwpr45uhvtggq6jkzfda47e4iqk2onizw6vn5po3bd3uqcduq.b32.i2p:0 -wv335vkr73gsaza4t6foqypnovccubvwfsarkmw3xtc3t3sncmya.b32.i2p:0 -wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0 -wwbojywnrcf2mci7f3zgbomrukcm4d3nv6pttb3dohjpge2sz27a.b32.i2p:0 -wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0 -wxfs2ccar4szd66dlmlijh3i3r4muehqjxjmabwbb46cq3gpbsoa.b32.i2p:0 -wy2udklgydh7iknnffbzvldoiwsct6dy3o7fjcsjcdjoq4b65vha.b32.i2p:0 -wzui6sc7667w7aabs6iebiex47o7cysxpryfdaltaklw2z2xgtuq.b32.i2p:0 -wzvki5234ffqhri26fqoxosqq3xengl23eoitkvip4mp7aipo3lq.b32.i2p:0 -x4cetuarbwiqphebitvgv4x4kzh6yhyyvu5c4yjlm4jsyl4bvs5q.b32.i2p:0 -x5qtgyzzgkovoko62l6n54p55xma5pbstbp6t6xc6hbugxz5ck2a.b32.i2p:0 -xasewpiqpzhyggxwsajmnkrppi2ozmapqv6673zuuymoueq67tla.b32.i2p:0 -xbetybs3nyeykskasolpatj4qrfnigz7a2bx7wcsyrniqd3usnaq.b32.i2p:0 -xd2byhr22rqkawocapbxedovmifyk77qrh6br4ctx7ny26hpmusq.b32.i2p:0 -xdoonpwnxhr7sjoyca3lkqsapmefd2puyar22ztocod4drjju6fq.b32.i2p:0 -xdq2g4tkaukzcu6mnvdukchinma7koi6c3noflpjabrzjrgeumfa.b32.i2p:0 -xegcohfrnnnuz3hdmb7r4e6pzxbmtg466n6mty2oz3tcoqutxj7q.b32.i2p:0 -xfyzfugo3qtfpq3s5zccbbqrxfkgy3ttlqhz6t6ovmtgrsuyce7q.b32.i2p:0 -xgbz5vpek6vaeej2zejxrjloqg2sqb67gim72qqpodqfq62rflvq.b32.i2p:0 -xgqzxudkvgbqwosaha7zb26jgza5wb7m66727rk4v2zj72xgg2ia.b32.i2p:0 -xgsk2huqghiftyznr6llr6ztepo523hiwqscxjpawcbme7xtjrta.b32.i2p:0 -xjebyiaydsbb76gqzetsmccgh67oeaxt3c4mkwmt7gjlfym266ea.b32.i2p:0 -xlfxusgnzpmatutaredcvx27zoiecno4tpxm52jicdvn4sr5dyya.b32.i2p:0 -xm55wnfhgmsy4wz24swjs2ziguheut6y72kht4ytwyfdmjsxslnq.b32.i2p:0 -xnb3pxtmai6ofbarycclwwueaarn4r3zt3zgkeepo4pgmswqvfcq.b32.i2p:0 -xnvsgbonlja7cmeokr2msvdelqlasbkwgqndqg7eakw43t3m465q.b32.i2p:0 -xpqubs4ftu7ym4xwrirlz2e36gvyjkil3chvq74bj4lf7djcrw4q.b32.i2p:0 -xrrx2rcpj3zefshtt7kamz3uflnwebpv2gkgd6vlrdazxgln57gq.b32.i2p:0 -xrwuqylcgkr2ovsf4pziosd27ywd7pfaohnreoyzm72qlnvoktrq.b32.i2p:0 -xtxh4wtmbjls76wxnehe57etubuqvsdiunwgve6kwjt4acwswnjq.b32.i2p:0 -xud4fgmeq4hl4cgsbjn3ubz2iyjguogskn7wreesvpsm3ib27kpa.b32.i2p:0 -xuivvnpcj2rhsxmkyyjzmyq6a7gwgusnqwdklgimamvkzu7rnnmq.b32.i2p:0 -xvpzaqftlfx2etqys733mndm7jr3l2j3if3wskfljzaow5s4rrfq.b32.i2p:0 -xvtvmaele7ns725mjaowsajpx4bgfecburyh6pqmdnn37cq7cs2q.b32.i2p:0 -xw6ble42juwkfrjetb3hmk2ep6jnyufhutoenyrou6ieoqiomw4q.b32.i2p:0 -xwlkpubkvsdsyaeylqfmxfk43juk6sz3hxnmwe4zencjq77aznea.b32.i2p:0 -xydzqrwggskdbmeqrhgt6alroglzbkcarzdlhabmvrszm5u6cfuq.b32.i2p:0 -xyhlemqmoeusqbbzr4oqph6kgmvm3a3lrbuanxkmyetwohxoynna.b32.i2p:0 -y365lf3vlh6vg4rs6trnjc4ia2xqplahk26y3tyqjly2q2vpfnqa.b32.i2p:0 -y3equ2tc6zsxqtndugsfzottuenfgxnl7eqgadmnzjkoigxvseka.b32.i2p:0 -y3occl5rqc2mz64esu5mqzoyfzlbxop7tttf2b3gyxjust57txfq.b32.i2p:0 -y45xhqkb43ncokfwhsmr4z6fwykuit6o3p2kbso3emv7stpiwwoq.b32.i2p:0 -y4njm6ftdn562q5thzd3fvb2f5mbi6bglmyupukcmcpt2tuo6slq.b32.i2p:0 -y5wr2bw3rt4rvw7hqqj7qtlf7vdds6zk6cs3mu3myyduasieqoka.b32.i2p:0 -ybjgylnhvk3fzyacxvyh6dwvrh7lk273qh5qws7uquvrhhwr6rka.b32.i2p:0 -yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0 -yemrkyqmjzwwn2yast2ga6dcnsovnxwip2rjpid56grdg7itugpa.b32.i2p:0 -yfplj67xwcblbiu4ozddmzlmjl4ifa7bhkzzu6fu6jkoyqui6v6q.b32.i2p:0 -ygtc5m4mh3qhi7tct44gxqbenhkasp2y4ydjn5qua4l5vh35osdq.b32.i2p:0 -yj3v3ocgldnackxptsjmwasa4xzxj3it6rtuhmlpxvwlq5kmyytq.b32.i2p:0 -yk2srkdlbm7kebv53dx45ss7q2fjcy56m3gywqvw65eya7co7hgq.b32.i2p:0 -ykppjmwunzqzuuqc6qqsijomfzdgieeq2mkidapc4awrww2ninbq.b32.i2p:0 -ykv62rivlxurq2wkecagzs76tulfor765c237bsjn7jt4436kn2q.b32.i2p:0 -yllvqk2utimxjtoyzk7l24s4n5sqp5dbn5vwsbt3g3dd6h4dxseq.b32.i2p:0 -ylpyfcs24ij67dkl7ighyou4z2gpfhjlt2iellj2ad4ddrxci63a.b32.i2p:0 -ymo2cnldmstzqlsdhx7kurii7aaffrhpgafxlli3s47pzbfe5evq.b32.i2p:0 -yny6zqtb7qve7wwfctsozhzhbq4hyitlqco4uhc5q3rvjex77oaq.b32.i2p:0 -ynzhhxlieigtmj6l7f2dq54ypnsaf723au7o3uhnismlgnkmcqjq.b32.i2p:0 -yof4yvv4agwhfmicj5u2drem47nvfkihnp6bil7ocg65gydyzzcq.b32.i2p:0 -yojuyryq6vfoy2mftrdmybmq2hjefuzrwmpqqfvk2kd5hptgr3qa.b32.i2p:0 -ypbq5aleoqqoxto4tkxlmlxh2hrstjxzpgonj3lk7dzweahs3hhq.b32.i2p:0 -yql2k4zjl64dtybuculjgg4v4u6sje4smnyay3vslv7irrigzxka.b32.i2p:0 -ys36rtuedg44sahelbysqi2mbc2l3rcfdy33zdvhvfkx5uocacba.b32.i2p:0 -ys7np3pmfhiyq3z2rcoeylb7agfbyfuhhp7ky2uzvvuzswad6cia.b32.i2p:0 -yuqb55drzrhxfnvobycxqau47kibaaf4voamk3kxl77xbb42xkqa.b32.i2p:0 -ywfauauaekbrxgwaahcjzifemzdq26xsshw54sg4bpr5z74scwiq.b32.i2p:0 -ywpsgu6nlnf2l4sy44tit2av7hfzwwttbjvwbtsbtqur3awiax2a.b32.i2p:0 -z34pw5tlowwi3gpj3ycb2dptgyuq65bpj7w36xahslgikggo5eaa.b32.i2p:0 -z3j2xshl4tpbxaybcprhzq7cuz6urboqoxvvpnfriv4n2lq72jsq.b32.i2p:0 -z3pgyfiwfzcd2g7v4rs6el5tvc55y7a3tai4gcbpso6flaejckea.b32.i2p:0 -z6mlyrxcjddpcaoumxnw5peulnkvj56hgwqmnc5adoutp7piujaa.b32.i2p:0 -z6xsstyq4zynzvagwv3wr7htz4vxttrotzb5izefotlwqm7kjtua.b32.i2p:0 -z7cjxpy4taui2ka3ekfqtoumsb7pg2sok3wfey3m2roeuppcrzhq.b32.i2p:0 -z7cjzfmv6wadjguzaavu7pfsqhujbczspbf5sxxrqndeovu3lt3a.b32.i2p:0 -z7gkesbkbl27lpcpbnhgfofjz5fhnvljzfvyydu7ky3odzdqs4lq.b32.i2p:0 -zafd45c2hzd4w2t24qtjqqbqm3z4hayb6vadj6sd5oukjyij2ara.b32.i2p:0 -zbkqcqtiiw4nwsds5pjel6alr5i4hgiyqf5giwurdygfysacru2a.b32.i2p:0 -zbz722dh7rvu6ugdydmlmtgfyc7rnpeslae525c7mhr7rgsekjba.b32.i2p:0 -zcwgqw7hlw7437a7au6n6obljdb4arnshoibdqo6voree4xiznoq.b32.i2p:0 -zd4ns4zcyvgpwkioftiiftgj74n6mf4m4ieq6aedqaznmdi6rhdq.b32.i2p:0 -zgwseerxwqnid3zhculzuqbkhghthsbvsbnqowredostfqlvawsq.b32.i2p:0 -ziehuxdpyg5dvvnzedmcqxszdcflsrx6fqmgzb7odefqwqaxrs7q.b32.i2p:0 -zk2r7kzzigzu5kz67xnrbe56u5walngylcsk756bkmt66cmeeydq.b32.i2p:0 -zkbjgfp4ouockpsmpbdyli4ilo7f3lbfjsboay3nf47ymir2ldrq.b32.i2p:0 -zki6halesukhfel76pziutgica4zrp5qtbmlmgyqf6dnnomk7hja.b32.i2p:0 -zkij473aummp6rvwvi7wbr5iio6xu2uh4rophbhyot37uxhrygiq.b32.i2p:0 -zpvqqdrcnagad5ayutf7hkp6prtvrbmknhqdul3qweft7oa5ikzq.b32.i2p:0 -zqft7c6riv7aux62qwe5xfqki3dcb4urvbfy6m4wz7f46j2us3la.b32.i2p:0 -zqhoqgf3enj2pv74sjov6dthpr6jqafw5qqzzsvnfdqzycychxpq.b32.i2p:0 -zrrki54mn56fytizkfmhx7eubea37padxa3zliwq6gtknrsxv2aa.b32.i2p:0 -zsfpcnbk4g2bwxl7yy5ebrcvlxd5gpcxatewdrgpige7oqykunwq.b32.i2p:0 -zszq7enaxbz5p3f3idhfkkd2u2ygpeqwj3o6hkofffcmllnymwqa.b32.i2p:0 -ztr3c7qz6v4hrnegmkzjsr52wyi4u6ery4m74sk3m77oup2ws4ka.b32.i2p:0 -ztyxbjae7ucfyupxpy75jwpzdktg4gbvhl43nh2crwqrx2uhveda.b32.i2p:0 -zuamj63ad73jmnw7xnxrmjsbjg7vg23j46w3mpc2udpcgjfkcqcq.b32.i2p:0 -zvchlrjuzqdlx37fhibhnym4y6p56vtlymujjuzhh2cp34yqfrtq.b32.i2p:0 -zxsd3fqczh6ddgejc24nnmb3ww7nalieq3a7cs2mqiy6tmff3wia.b32.i2p:0 -zy2ywvyqds5bgdoo4tgbu3bwjp3ygyn3zfuby44jemc6xa6fbwta.b32.i2p:0 -zzre44vh766jgfordw2ehu2r6p44j23uyovgvm7iwuhp3g5iz4ca.b32.i2p:0 -ycdw2e4ufgfwhcqna4g3m2qsvaly23ozaexawcj3x4gtgcehgwujjgid.onion:8333 -ycfvedulkprd5bmivqejur5aptcs47daqtcvzotnnhfvwu3o6gcp5cyd.onion:8333 -yck6l5ffw6oszgtoc7et4fytvp3sqdf5awyky4tlpgem2n4y6icxqoqd.onion:8333 -ycnepnzktkhfysqijlgbjk5awivls3eiqb5kjudotjvnvlbe6ah2k5yd.onion:8333 -ycwrrabomoixkxggkxldyxkqoc7qqy2t5wxcsxjgodlvuydwch6dqoyd.onion:8333 -ycwwrwkqibvkftpc5kyqs6nf7hrzetrmqgwo4yae7bq5otvubkfsread.onion:8333 -ycxjdh4jr4vun447cdszcoge26pbdnqblfi2osmk5e4uqmrigw7y4byd.onion:8333 -yd2ami3rem3i24q2b76l4ujyq343ycrowrthwqycvpcsofgpwlxyryqd.onion:8333 -yd4nyusqking6tkcwmmopznlxhyfhk3gsw265alz7vpo6toqg3kwn6yd.onion:8333 -yd6b3wtmu6bz5km7hw645omyv65one627xech7f3vnlwkblsvqdtmiyd.onion:8333 -ydforbx54mnz7g5u2mu2ulkomvakdbwxoad6araknijb2i47gkfeh7qd.onion:8333 -ydiqekqpcf536w5uwsdclw5pt4n2fkz52fo4vwdducc5t5l4ghqaxnad.onion:8333 -ydl5kqr2auvie5mtjkm37hzkqh43pobibty4msfzkbu4junpg5gak6yd.onion:8333 -ydojumivjpins2lwgql5xaywbngrmw56nvmtalvfiy7sr42ksvr6apyd.onion:8333 -ydvbxdzs6w5wefifiqsqntpbd7tliofenqih5hlnz34546fvy4ab7iid.onion:8333 -yeat6ea4esvd4nimhg2rcb3ghpusoqzjb44alb3hhdj4d2nimn2vpoad.onion:8333 -yeficzguf443sojjdcmh7lzk7l6y43a6v2jbyk3x2w4n7xokjs4crnqd.onion:8333 -yefjaylovpdhbb5b5bhjx37digt5u62lmzyc54ygtabwdphm3zwd77id.onion:8333 -yeghpcuryadlbxzk6o3ujebmfuumkpoi32dr2ctfmql6vqn5wjioehqd.onion:8333 -yenw26f3i6kf5u2nad6xligxk5iyizjvl7msx3pzjcatiesogdef4zqd.onion:8333 -yeoadueo3ukf6s3fetywtbvgmpvrtkja5rlp7wcp4aich6tfhh35giyd.onion:8333 -yeqjrnnuf4fbgzik74qfhrohcymj7ccbze6ndky4pe673chfsjconfqd.onion:8333 -yernmfgru46g43vsijjv44n7m35tpoznnkd2p2wl3uqzkietukxqxoqd.onion:8333 -yettfzp2vanmkehwxeaugotqcsg3wsomcargvetk4nhwnebrpq7ah2qd.onion:8333 -yfgo33tiu6w3nrvnfyw2nmpcwtfozinctn57566y5l4hfcttuvgff7id.onion:8333 -yfmujam6pa75vm7p5q7gvgkocqzcwm7lgbnodwtmzfw7usy5dvlgqyqd.onion:8333 -yfpqwz4qogg2r5sdweggggz76pmhxtegnisz55urw3egvcq2e3amvkid.onion:8333 -yfpucmv4zspytubs5epnze4xc4joqny52s7ifjk3vu644axwkfyfurad.onion:8333 -yfq3sexjxzuww7tnwc7jj2ethiu5f5r65ewpy66os3ozhoeje7na4hyd.onion:8333 -yftuiua74fspnqanvait246qn6vmab4aoympjd3omppu46jkq777axid.onion:8333 -yfxz53gdbxu5hapg3e5kaa5pyxpbrpiql6j7sfe4i7fqj4blpqpufzyd.onion:8333 -yg5xbesziuiaigwyxjrn5c5hvj6fxef45edl7pir7risnr6un6esjtid.onion:8333 -yg75fc53cicbsarrpfv2s4crpkx6vdjub4va7cvbducwzhsf6qehx5id.onion:8333 -ygczn2llqhks3ohxvfck4ks45ekg4xr3loriyynnejw2jfmi7hjsfead.onion:8333 -ygdfwrg33s3qwiarwxbejalkirmqui3wjz7wfccprjry6bm5la65vhad.onion:8333 -ygh4hx4ugapidwxodkjr6vgl6vkaqvievk2eiie7v3ewuvjvg2mzp5id.onion:8333 -yglvvnb3dk2vh2wwgpcnvm6t4lgbdhnvpy4jfj3ee4ugb4xzvjrrcfqd.onion:8333 -ygospbn7dc5a6haqur4eoe2oj6jttjohs43rhl5m22ltruh4fz5isxyd.onion:8333 -ygowwz67kvvri2lcwknsc5xjdz7ffat5tqkm7fmxrrzfgvqnxoxkvgid.onion:8333 -ygwuwz5autfc4tqluyuoebghc7f6lgjykm6oprynh3h2vfp4xmhiapqd.onion:8333 -yh4edjvpbo55vsankh7e33u77ep7eah5h5gvfgu7t7mbb7kkmjvgirqd.onion:8333 -yh4uoyfzey53dnoj6zm3frihhgwpqfqkw36sjmqsvfnl3rqohs52wqid.onion:8333 -yh5us7dk25ttxkt6miers3bazlm3jiums5nwz6mzd4i6kn5oizjccuqd.onion:8333 -yhddybpp6lgu34i7uurdqg5jznfdajwr7co3twiqf7pgnj4yjgzbnpqd.onion:8333 -yhiswltkrs3upvkrygsuiou5i2njnyxk3gwtsmcr5yn4lfinzifbpkid.onion:8333 -yhjkylctf577degc7ufffvg3gsdxgnx64pdhzfujxjgfhbulmtc7yaad.onion:8333 -yhnzb5pmcbeiqs6bxm3xvzdy2dgblteiswvvtg6vhkum5gjjw7abjzqd.onion:8333 -yhqytulgwdtvozjhuyod2cufnkbh75mgyw43k6w63ah2fzulskfssyid.onion:8333 -yhtxfuf5zxqoqkuodfpmzsnnmtm354y5rtexqplt5l3fkzzksjkkzvyd.onion:8333 -yhvyxjfauptpsjrxrf3oxtv5zlju2gdpitwsabcmj5gdpjr6i4z4ulyd.onion:8333 -yhxcgpy2bwwhhpmgellyghjpkw7cfrjlq6trq2yl3632rxerwbmkvfyd.onion:8333 -yi2k4otmwujg7bi5iw7ewqntnxb26jyplx5xyk7bjvvaut2y2mhcgqid.onion:8333 -yi32omh7hh54oeot4i2ze2tif4l4cwdhzxxn4bzmtqrotfxrepttfead.onion:8333 -yi4gxqy63csutkea3zss2oryz4get22hcfginwcejy65g35ec5t4uzad.onion:8333 -yi4nvghovjd5bzcbhitvezh4uwg32n6r23et633odlacu4eamfym5mad.onion:8333 -yi5x6isngj7pivr5wt6i3drntlqsvbzijpdy254lbjdnihxmfy2cdgad.onion:8333 -yi6umkklbb6vr4j75buoss7kqkgcsdsx5fvgi57h7j5bzuleoe3ae4qd.onion:8333 -yibgffpo7dimyvjlbzfr3dnmnl2r5hbrpxbtcpksthsko6udsrk5uzqd.onion:8333 -yiiyiuwns45zhmkwi3wjumqhnyfkwkahbggd6hrxtnrxfqwn2vdx7pid.onion:8333 -yijdxmlgnfcwrb5zxvchjhgtc5357mecuopminujkono7bwjgqu4acyd.onion:8333 -yise75jksg27th74bxo3a6rcr3huvromhmuhnmy3n3ngcgfpagq445id.onion:8333 -yised7sf3xzsnlggeuioas2of4crrllkpz2gfbdy7c5cysa5sxi23lad.onion:8333 -yisvuvmqtn7wht6dndrqzsdl7vuspxwrmfwwu5o7wldnzn4mbzeb4yad.onion:8333 -yitceyo3wv2mk56omv6mon3n7dcfr7jiggdmzlmtikpoam2otiey64yd.onion:8333 -yiuesqqc73nn7kxadavmlwc7ymciszzk7bxs3bd4fwucaocme6qb7lyd.onion:8333 -yiz7d2lkgk2mftp6i5e2tqhotqkqjgxbdmzbnflwvsioyfydqrvll6qd.onion:8333 -yj3gs4nvumsfztawn7ku4cmner2zlmcn5kke33g4j2vywxsrqmbd7kyd.onion:8333 -yj3q4iustxfcq4bisbuw3jvqc7ph2ggld56mvyxqvgw2tmsinbwlnzyd.onion:8333 -yj666fxjddvz4xzkhtzhh53wvkiobvildczzxb3mixjipqqiqaz3bzid.onion:8333 -yjdhdurh6vqxuykgmuskpabjzjni3ehxxh3zq5redu5hqdmhdw5b5jyd.onion:8333 -yjkojvjsg6yhfj2ln2bpcrh2e6fr42ul3yzsebbz2kkytg7pf2zzjzid.onion:8333 -yjudzsswyvfqyeth2eghfvegxg6z6ubnx72kmqjljhdewrckw56lggyd.onion:8333 -yk2foofoifxgbrp5a45okwbelrsvycgqgw24xv56hmuqxlpmw6msndad.onion:8333 -yk4sercvyzvqxgbgn7srm6eeivlzoa3t4sz363aygcyciubcieihhxqd.onion:8333 -ykh3t44zjojpj76ouqeo662ljhyc2t6e3mike76iqpelcdztgaxuw5id.onion:8333 -ykkhln6x6hcmhyrx5rxaf3c5auh5k4plrpaisits63r33ecwkmtexhqd.onion:8333 -ykqehwl47hwypuhhuuxkpoexocldvllixqhplpsy6ym65vbjfa3yfbid.onion:8333 -yku2clwr3x3ndzfjdk3o4spoztoqy6ndatken5wopgapg7qkvypuqoid.onion:8333 -ykwrwuffwvaxlwivt3hlhyz2yo5xde7dw4x67ygc4xh2t6m4i5cftkid.onion:8333 -yl2preaby2yqyhmviyq46roapupmnijt2g3mzmvwtxptvybz7rbs32ad.onion:8333 -yl2stshaozpyqtut7m6ln47z2qhledknuwhij6kvxsuaai4nwy6fp7qd.onion:8333 -yl37nyh3vujz2fyrz3eoqoteixyiz3dj5rfnnmrglcgcswzbeqbjhiid.onion:8333 -yl3bo5zwwsg5dbhrrcjkvoyvwwxp3kbdgprhe6md52ob2lra7ynrbwid.onion:8333 -ylaoywooejvpfosewxmyxjhc2ahfepjbvuyjc4p7bymwirexlkdituid.onion:8333 -ylaprgwti4dsumx5xvlhul3esf3yi3ebyyubb2dwfgwe3zysv3e6nyad.onion:8333 -ylblnrd2jnfjtustl6yt6pix4mgqr5qqoevunmwk32e6fxq6uj3dchqd.onion:8333 -yldtx7o5y5jf2utrrtqf5yf56akol55wars2uwxuvjoubustrtmuqxid.onion:8333 -ylh3vliup6k27pt2thw4xgfguiziaosb5y3ovee4w6dzwcb6hc6czwqd.onion:8333 -ylsvnjqrcgatkzj5gfkwt6cz236z76yvgpeulggzml3xb7tnbsttjnad.onion:8333 -yluwecwlibf5dw2sup64dq4gs4cfdhtkfhoy5cszrvu75wljeqanr7ad.onion:8333 -ylyuglp5b2p65gmiofhe2irpxswlhecdecg7d27qhcwehegr2efmesyd.onion:8333 -ymgyodvztfs4nnijjnwiv6eadetxjm765iv3ryuyhsq4upnjwncpvsqd.onion:8333 -ymiw3d4klephwuwbkgdpllrs6hssb4svcg2um7sdm3hsnnksbnvj2vqd.onion:8333 -ymnypd7xmz2fka2r4yxvq2ibf7rvdyl6eemppo74rfehu2d2oqkclcqd.onion:8333 -ympp5jlakwfhj2bozw6w33qailkrqbroizxm3pdfxvjdbrkwtyx5iiqd.onion:8333 -ymrunm2vhoarw7rpo6jdmq4mev5hz63umljki65q2v327vmnw6wjyvad.onion:8333 -ymt2hdfgdxo2awvj2k4y5tbpvapj75j7v34tvvlrqy44lsvvdcnjx3qd.onion:8333 -ymuufa5br75liswfrb6pgm3hc6o67gnzhyg7vpfo2qsw3oyw7m7nsaqd.onion:8333 -ymxea74sswjyqvv7jsh74dnvimcsq4rnao5x5g7dfjnbfy67oj37l7id.onion:8333 -yn3avowdk5cox7qz34s3qiz2u5j2xg3irxckhzikfjv5ccjqrdiramid.onion:8333 -yna4zorq57ehghewlega7lb4zgx3t4lgv5k24orv7b4qcg27svymosid.onion:8333 -ync7fc7dz24s32kp6opdkbvohb74obme4jgo3rkkvjzywslxegist2id.onion:8333 -ynilvzuulga2tlv2hcic7ayc5qpd4nz7r7snsyejp4vxwnxlonf4gvid.onion:8333 -ynkv7njh6hj5xewxxy3gvtnu6ocyvu4tgrl3gnw5xxkdpfshalppqmyd.onion:8333 -ynqgzojvdwv2rui2rlechb22e5hwqipltusdnfkv7s65iz6fgrnybnyd.onion:8333 -yo4ykt7hngppavow7f2sz36ajl6w34bw6qrcfee6i3s6jkm6seove7ad.onion:8333 -yoat2b46hzeuhy7n57gjmfxgppei3xnzdxwsl2ipc5ny656j7zp6ovqd.onion:8333 -yobra7r3ketjuhr4g4cfdqumsez4om2eefvmgxrxq7wxnkouzmcemwid.onion:8333 -yogfxdco264tjbbeek22o26lznu2g2kwvs4lmft3ib3xelndagtf3uqd.onion:8333 -yomwxfciljad63gicbd5757og4lypcph5f5mqdou5kj5rowkyotaohid.onion:8333 -yon5gz4q7soici4i7jf2zaciusioym56jo2bat363tr3peoiurransqd.onion:8333 -yoobb72dyt62n5dpsu3aqpqa3lmfj6gfurno46o6vmqdbpwqw32ahjad.onion:8333 -yotcqynj24k2ckilo54hjhftjuvvwiacbzoraqc2kq5vtmsxloswddad.onion:8333 -yp3juo763dmi7ryhkv3kq2l262cllrru6ks5tlzcdlxdakmip3zosuyd.onion:8333 -yp47gud6fjsvjgu54oica4b3ij4zfreactcaon6fx7v7pfbxbrvqhtyd.onion:8333 -yp6klgnrvisq73qg4dk255h7un2k7pbk666jtzc22rxjs2en64ojauqd.onion:8333 -ypaazf2z3t5dqzudlygjjpyb2uvk63guovstzubsohbbeomometn7cad.onion:8333 -ypakyst4bbhh2juqd6r7xymqnrgwx3eajekpg6o5b4fazccy3mwovdqd.onion:8333 -ypkjkt4dnyqy6svecydigttwnsj5x643w6edk6qzhfo2hkxxu4ln6zad.onion:8333 -ypmikts3saaffj2uo5zmkbac5m7xnbblxkbhpw5xtxbamajqf36wgdad.onion:8333 -ypninar2hybv3jdovr7ax7teq6wpzvrw6n74csq7edos3hzumh2h27qd.onion:8333 -ypoinzgql3zo5d3strpmannbkdtndxkxlajwgcpaj4ngbc5mqrzzgpid.onion:8333 -ypp73pv2vcjfq23ltwhojuremxxfknwtgkxsvwe3widlaevyx34pepqd.onion:8333 -yq7s6pe7jzrzj5uxlorytwxd5bs4kljyvp27akdrpang765yd3sexwqd.onion:8333 -yqnal4phy7wz3lsoi23rziyb56bnbzvvypy2mg5ponzrk63qpyvle3qd.onion:8333 -yqoiqt3molj4ygq44zyme5gdbgee7catlf4ndjr4myiicduuwiev3fad.onion:8333 -yqvhbmvc45iy3drl7nceuhugdt2fevwx4x53zafio6h2626kflwtrcqd.onion:8333 -yrambbqlzkm6o5pkc5q563njvrkfallqobvscvpdik5owbdtnhbc5jad.onion:8333 -yrdtnt4lkpysyyrvryqhxw3k427gxwziosdtipf2dcifougwzomdfcqd.onion:8333 -yrlc4r3qfcr4x5wnciutrdvasrpahor3ui25lgdgkxbit3zwtmwfmxad.onion:8333 -yrmpasdjmb77ono4c6rjh24fj5gt7bbjx7nxurytkmxbww2gam6vodyd.onion:8333 -yrqolwaoxpa32cw2zegnaggmniuer66umflznja6dcp7udqpaoanqwqd.onion:8333 -yrwksigpx4foqlwnf6cxwtppx2z2msompig73dkcm34pwsmy5bwwg6yd.onion:8333 -yrybhm2es4siupjnyjffviemvqx24mqj5niwm2wf56spdqlwau44r4id.onion:8333 -yrzwl3rbfjx7eybyjvnjz2y7qmvpnkexkmylqpwsb7ivpg6ch42mmxyd.onion:8333 -ys2muyvcnpdadettzavleh7qrn7t6r7e2tobfp7yxftta7ez2i6rdxad.onion:8333 -yshp2g6b53ndeez34nxnk4bz6cqbzlfxqdggi7btqlwzxzuc7sweqcad.onion:8333 -ysq5rtpfzkz5gt2s62idbsd7secz3jepzlup6hqf5ttdutsdmwg2ryqd.onion:8333 -ysyx5eagwnqpfemz2nhwcxs2c3eueqk5f3jnyvyfqfno3pflcqfw6yqd.onion:8333 -yt2vub6llcegxuucu3iekjqfpmbyz4kreuxx4su2pqcetw7kbkbipzid.onion:8333 -yta7q7v5lkzt4zyp3m44cxcdtymxgmuqdntnagz6h3hwidmqoeavifid.onion:8333 -yti2ofsqg7k4zbln6aqx4zqaor2zpmlsebyljxlu7jczsjqtd4ctd5yd.onion:8333 -ytkkqeik77zjjwabsdlctuum37jr3r2rg6ckxudza7y7tialqr2wfeqd.onion:8333 -ytq4uowr6vwyjmrjvac7aimjjlzylfmhqhn3z4ecenm5dd6u2ccsijyd.onion:8333 -ytqhsolk7pqur5cu2faxruehvx72yiiwb33p4szdnzidjqksanps3nyd.onion:8333 -ytqzrm7fke3kqgh5b62taq7yyejgtd3yxwaifj2pimoqbfq4p7xi7sid.onion:8333 -ytrhvysmp4iq2qumdrpgp54q3ushkf53b6i4oxpddg4rmlk7hbayusqd.onion:8333 -ytyn2e3bkmgavrygpk5rzydfdmhpkercccqcaks3xtnbgq5qsyg4euyd.onion:8333 -ytz6ov6l5ofhjudlfi5k26lsg4v36p7xwciafy2sdau4cn6ozxgmefyd.onion:8333 -ytznm6jwapg5h3firimqb7ao2g7uihakg3gt6hcpfqkkgcyemklfufid.onion:8333 -yu6ilgxjfffdb3fq7srwwmz6ymp3fxberstpl6vdocmxbrrf5e3tw2qd.onion:8333 -yu7c5kjgmlci4arofpgq5d2qs5fvbw3zac52nampn2vc6vximc6qovqd.onion:8333 -yufe3o5x7spybs5tku64r6hzbrc46uq6izky6z3dyvba2ymblvehyiid.onion:8333 -yuhebtpb6urpsrr3g3vk7tcl5lp5dt7kcaj7zpgox5r4x6ptysxzvgqd.onion:8333 -yuqoihr4p76t2yupxuciurcpzsij5i32enjlsynqor25fhdvidx3djid.onion:8333 -yux32z6r5leyhbdrgdpti4sggxyoy336qb73ia6sk5egfli5qsvkxvyd.onion:8333 -yv2ezeqqfeoprti36q4fds3ckq43vdv7vktqfpn2npv6isnbxay47hid.onion:8333 -yv7ainbyxz6wejjhpjgzx6ghcomdwd3k7fclru4woooxcovyjwrp7dqd.onion:8333 -yv7llcydwvi2m4xpnulhgxcrje6vswtsasu5bbmgxuk3lgln37tdvbyd.onion:8333 -yvgzvmh4ngi36zvn7pe3bocsxj6pccafh7v6wmswkdobbxdzh3b56iyd.onion:8333 -yvhvl5bvjp5ljmooujmw74wdyqnhvwlm44766wwgq5thnzctyni6yeyd.onion:8333 -yvnppv3n3hwexlvugfviwv33ycavxdwnh24dps5vp3y7kw6kze36v3qd.onion:8333 -yvsokw66m7kqqqjxb4mntjvwhnpoovoec6rrpqtdze6fdvpbtvt4iyqd.onion:8333 -yvud2f6wb6puec4xq3a6yruax25jydqepowhz65uvlbvblsyi64skoid.onion:8333 -yvvodwqb3szlgkx4egcyq7qmhpyoqxdyxdnksxl6ppnmagnsu4noemqd.onion:8333 -yw7tqaujnglpjmjak5r7sxvjg4gqeubwetm5h54e7fbfn7yx7kgr4kyd.onion:8333 -ywbprsiodgtlc2qoubvot5qm22logutr2dbizmlond4dcifklaxqlcad.onion:8333 -ywkxlaydopi6ygjeggtv5znptkrldzsh7peg6wabkjmcu4k3hmbjivid.onion:8333 -ywmh5zcx3r2rd7zmkyx5kymgxk43lsamie52kbhayqwqyod5togs6aqd.onion:8333 -ywq6oxdfdvlict3cuasd3akvcl47iw6bxykrvkalemrcyqzyzclbf6id.onion:8333 -ywqkdkihpzr3hx6la2lzqsguoqbuwkn36qcrbkhvltd62zdrguprljad.onion:8333 -ywqp3kjwchkto24so4nn4ofq5m5c454btnkux5jxftkkqz66ducu3mad.onion:8333 -ywqygs72qzxbkjekezlhsnrsfnnvm66igkovfoh267ru7ho3qtxtalqd.onion:8333 -ywvpyur4ny6zhfxpsva4mh6cd4htw4q7ylx7tissnxehwg2bid5fumyd.onion:8333 -yx3nnyxy3h4ex22uqdjwephoprte34jelnkpr4ua3d23ks7qxjrqzoqd.onion:8333 -yxa2iu56fp4i4mxzdkmv7xxrluyxtkylqvexuceivx4fqxbjyzme76id.onion:8333 -yxgvp66ll3c6ko7w4hm7xvzofd3cb3ku3jjqc4wihapnyk3wxijafrid.onion:8333 -yxlaxiaatyfnrx3l2vhb4p6d347djzux75gcl2d33aydlwspo5w5wpad.onion:8333 -yxlwpmsjdbpldhi5hlzopision3iqbjzpvyaaeb4yst3z73qbgqy5fad.onion:8333 -yxnuslj7hslwmofh36a37stlm5jjnq46vvvyntf42uw3zuouot3sjaid.onion:8333 -yxq3bjwdrck3lflvwixj2fc2l7pzqnea5l7cucviamoc63a2xozk7iad.onion:8333 -yxreb5ajudnpt3b7z5hyizaj6ufgd46o334wtduuyaakboxwztgji2id.onion:8333 -yy3bnszld2tbbyd45f2j7btrbdz2p5zsuzie27liqr7xgkfh37rcojqd.onion:8333 -yy7rusheh2cq2xghpsdzlrx4gpejgfvsfhq6333d2jttcovhh5jo44ad.onion:8333 -yygxdcvyp6tn46umpmxlsgsi6crg2xjchuhi3okobofsx4dqgwucnnad.onion:8333 -yyo5s4r6wr6p7l5p5umlp7xgb47ugeptugscv4gvpsxvjlwymfpwruyd.onion:8333 -yyr2peqznujer3t63yyhlcasjndbhllvtxxkmcvr7p4yxpuzjrcylcid.onion:8333 -yywmc2hhk7t56e7jun62oidqft6jvtvvlylexihzgcrtkzxe5axsd7id.onion:8333 -yz3izxf6pdtr3ucbriuo4bpgjn2visad4vgocktexnpv3rfgar3kydid.onion:8333 -yz4l7aqcjf3lcdtdcuxoxljedrcrlo3lu6kths2bvjeoil4wqx3d46id.onion:8333 -yz5i6sldywr2mqzh5qmwoqfgsta5f67bgdhqogejjmpengl3llafdjyd.onion:8333 -yzakgornrhzzenpclo4ahyai5lxsg6mjq4zrwlhqt3ff4sblxi42jwad.onion:8333 -yzbka2sygb5eqgrgk2svqin5hl3dfknzfdn6wzwncexsejmrp5wgm4id.onion:8333 -yzh2ineefkzohck7vkwcfe62kvplsly5xn4dmm25fpxbjq2va34bu5id.onion:8333 -yzigosfexpco67cy3e32xehlpwor37fp52my5pwtr2xsnj3mxl7gfoid.onion:8333 -yzijb7pu6mrrdwb7sku2e3epfyrkhl7t2a723vaisqulr3roaxoy4xid.onion:8333 -yzlai35raddd2kdjnukns7u5t4m4ngi5dfrlq72e6lqf2hp5dzkuszqd.onion:8333 -yzo2vz4kuitm53zwynkm7ddfdw5escsp5fp7rgf6uspphe653mvdekqd.onion:8333 -yzqfzw7fgzzs63xpvsgznhnassxcadbfaxxaxbmkffvesgdxizhxkyyd.onion:8333 -yzrw7ukful7rhvlletmabm37wupkhsxwo2esqqotsoh6gxib57ss3tyd.onion:8333 -yzs2bdhwhxfgaozpcic4v66w7wwlxrr3v4xpgzer733qehcwewijipqd.onion:8333 -z23pfizxwpae2sbje722iesvd6rcxntazcaoefabzsudkc4xxmtbqoqd.onion:8333 -z2eky4p4ozlkrrmuq2jqcz6w2k22re6hxrm3um4ypcnmzmpsi4p6l2id.onion:8333 -z2eo4uckd3ymgtsjitag7yqukmjsjpwuf3d3npq4oskeatpkcinxkcad.onion:8333 -z2gnzha7ttijmle75dvqdzaeqz3xyxzjrrqbzribvwbomh74je4xeiad.onion:8333 -z2ihxne7lyodwglkwpvdmz3a6343msirrvjmaf2pytuo3jysabrkiiqd.onion:8333 -z2lhlshxak5owviqqzacj73ioftqmvq5idawmrgt4k347bwr6yubmqad.onion:8333 -z2njilhjl33youet5rbdfmncadpt7tohtconls3qhpvuqfkreoteqfyd.onion:8333 -z2nocd4haqt257cyr6festid7enoe72qpmu27cuvveoon4rcak4femad.onion:8333 -z2yjvxbv3rfpso4cjkxc4i72f55xb5fihthcdbvh6dp7ghxz2q2tabyd.onion:8333 -z33gr6fni32nkhfmkovcbvpuk7s2atoqfbuzdgz2jszh5ua7zdu6uvad.onion:8333 -z36427rantiy4ikleyihwfwh2ga3pyqqz7doezrzkyv52bi3mpcgt2yd.onion:8333 -z3asgzuzdvhrrejqjnkg5qfeynspuwzzrl3sr7seqxlwkiemnrpsrzyd.onion:8333 -z3hdtpvmnaz2izvnlopzmfgdb2synsomzgy62h7vlxvsn3yqhgufqjyd.onion:8333 -z3hgdhj7zxtih2gkjlnex6occtzw3tpd6f5eobwrntrhxtiww6ke43qd.onion:8333 -z3jl2izfxwfmqnbbrac3tustn4bngymj2tia2sn7nuyconbmjskedtyd.onion:8333 -z3m3a6wii62jc37c2fw7huca7mu4eywnssindvhn3hrh3t4y4kwj7dyd.onion:8333 -z3od23fobhkvypxarneq3fqsdsksjt3hmujnlaiwb65hdwa2n5xdjiyd.onion:8333 -z42np5zjd3thnd54h5n45ibynz5vb3flbgypt4me2c3bnvntn4rsgryd.onion:8333 -z4d7f4dvqutzvvqkmj35znzpyorroqg53jhbft34gyk2h34wzorv2rqd.onion:8333 -z4gvqymmj5jmg3dnao7k3vc245pzepqcrevzyh4s5xn5fcc6ape22sqd.onion:8333 -z4mmpbj7md2ljj2nzbk5b6stdromp2sxhysdexiq6kjqp2go2yfhlwyd.onion:8333 -z4pyvdupcieuqtzvhh47sbiahdyegvpgtwgfmlvfsrm4yj6g5mt6cgad.onion:8333 -z4qgvajgk3tr6aomi7zkpiilx5xb6tvavupvw42sgjf3bfqrgwk4tjyd.onion:8333 -z4rgrsudz3wjx7uykg2kmcadwixklibr5b4k5nulwrpxcjkasu6gnjqd.onion:8333 -z4s6g5bqdmo445vu2i6tcm54zjypfhl5uwnxqjq764bbu5h37gkp5gqd.onion:8333 -z4zr3v232rayjy7e4wuxxez2blz6p6apyv4souxjztqnv3mvaytb4nid.onion:8333 -z52bx6657mva3yjtrutjhxojkbwmrmndk3r3nptxc5xqz3nd62frfoqd.onion:8333 -z5ecnh7crpgo54nfll6qbwl4ybvfbq3izazsdu3pp6zqkam47nuux5ad.onion:8333 -z5v63i7lvhkfdqcex3ioeny62glxhptowtrfof54qbl545mlchkul5qd.onion:8333 -z62kddfut74o5njyehkdlj4caa6yg5orz5lznaccpbloqq2siiwbtayd.onion:8333 -z62r52qegmgv4otygobjdsubc6jffaei23he6n553akc4wnf5ryur4ad.onion:8333 -z63d77gd7artekfeamkqycni7tzrkvbc54fqr733veuoaqx45jwmytyd.onion:8333 -z63fpitzdw3ot62wtxtindh5334uatz2flxg6ronyy6jwx2ztjs4meqd.onion:8333 -z642d45aauehr2ycmv4ewv6zkwjlvlhwf5wlueuy5ynpu4qmffc7utyd.onion:8333 -z65lbxuvo5x36vuv5rgwgyoplqjzzciwvb2whvo3tlghzhp6zij6grad.onion:8333 -z6gr5c5yrp5seqsw73b2pkn3i4aqd5idmzgidjchjjm7f2hdgfkl4fad.onion:8333 -z6n3h75u5kkd5xkqfwbqasd2rekxams3jinrrqaj7p33qdxq7fdlmdqd.onion:8333 -z6n5kkyabl2huqtcp332n6xbo7kpilcw4b64govztw3swtzulgtxcjyd.onion:8333 -z6nq6lkmjoyjhqp5j3tg2gcjq4e3hgduo74unmtmnybd7a777hp4asad.onion:8333 -z6nuvxnjicev3v47o4vxjwakfz6g3jvyo3l4rds5qqfjptqie5re27qd.onion:8333 -z6okjxmclwc55pbwioqx5wyua7rjobcmbttpte525tlt2gexjcjtr4qd.onion:8333 -z6qmf32mld7uqjmx6hroqnkieerstp3vle3u3do6odxig3ubmv557qid.onion:8333 -z6s6t6bi4llpuod6rnakc344wn3h6ejpfejxrkjohjjy246shwfd34yd.onion:8333 -z6soa5spkni5ze6p2xg6lnehu3d7hnqn5ddiy34jtedwegf4syqnnaad.onion:8333 -z6t6fxwhgndvi36vra6d5duaryx2m75v6a5yoz3cqjlj53ko4wm7fhyd.onion:8333 -z6tmafvqwf2sd4rchnafg4urcug4xpkylwls2owruyifaduaeneyqkqd.onion:8333 -z6u4s3uz6bxke3tyibyccbg7uaxt4cb4dued3cu3pbjw6frqc5nil5yd.onion:8333 -z72rd3arkarr6eehucg7rrkjmvqnzdbjmppfk7zcvzd7jqrvisf7rpyd.onion:8333 -z745wkcll7vkkrx7zamibvbyqjtcp3y7wdz5kd33gijxfz54cxzg3mad.onion:8333 -z7eb2xkiigjdfay4ch4pubeqxb2jwyzdb5fo5owkbteyhefek76qoqyd.onion:8333 -z7f7lrvup632wkbzinvbkyyrhmguaf4fzt6zleiynk2vuvwdwt6ysnqd.onion:8333 -z7g3tx3nucmd5ozvs7wgq4i2riiufxlutv2usowr3p4lixfbx54fc3yd.onion:8333 -z7g4iekn3i7nliiowlt3ek7o6xlhi5tv2hofycacjqkpeoijghmiyxqd.onion:8333 -z7j2lcfj5b3isqznsb44ivi66lwmidcfspmvdrmhbfuyub2h3wbmnkid.onion:8333 -z7jbbwkyza6e37iqos6u7ln3nedom5i3dcnowdscr7wfj2xygre47aqd.onion:8333 -z7jtpaghm4na5po5p27fwbdh2aq3z4rkpwhhzemlrhsoefru2z5eyvyd.onion:8333 -z7m7rmzhol6swqnk6l4sadrjgxwnggt5zwgp2jx6tadca74o5puyuyid.onion:8333 -z7mcuih5vw5qob6o5qg27jhozuczpqx5lmzl2ghfxra53tov2h5xtmqd.onion:8333 -z7rxmrmvtsbgrrwwh4k37bpkk6dtu3aq7f5d442ys75nepy6r2q2xaad.onion:8333 -z7u326iowflnv6tvy6uiwwkusx4vat5gdaxwamcp6jd2we35ih6zplqd.onion:8333 -za6k2u2t22ohdrpqbirjhl75eadxcjvnqfkl4bzeygbnliqsc45gplyd.onion:8333 -zabx7shizdfchrfthsjcuyypqy473ni23ebi4aedow4bg5c4tl4cxbqd.onion:8333 -zac6qhbqbb5yo4rvcsmbilp33odkzfwrftwma4yo5hor4brj4d3ksiad.onion:8333 -zad5dkykkoelu5tdj7l7mr24pdf6eos4o7cbs5nvx6bcg5443eqwaiid.onion:8333 -zafdafmd2h6ue2pmuj25chhmkqad3jdcxwtaess2opxkrroopwdqfvyd.onion:8333 -zagkhagdzvkgpuo5znflvxcqxal5tweg3vsaoaonsvsl7r7orhlwshqd.onion:8333 -zahrvinucuxpxu56h6nkiiw7cvutxrua65l4jynvwkzt2bzmeuvdpuqd.onion:8333 -zalrhwuj5j47tntffl77xrdehzfwq7c7duhaq4jwnq5vdtdtajwiucad.onion:8333 -zaw7gnlyeqrlpgcmsp3e63anveudschhifaaezu3web3z6pjjdtvviqd.onion:8333 -zayfuym6j35mxprdsm2x7pvws2vyaoinsomdbgrqbe22rcc77j7jtnqd.onion:8333 -zb226sk3eljxccaswfgouu6mitu43sf2dan4feygrqnlvrot6z65oxad.onion:8333 -zb2qixzmsethowd6fqnwikvp3yeeeo3zvhgjmq2yb27tfslscgkp2zid.onion:8333 -zb62u4o5qzst7rzjaq6tafgzoybi2ncogcjp3sf7zbto7b2xmicwvyad.onion:8333 -zbci2c2pkku7hwg64ek4z4cbyn6o5bnzpzyriqwjckzgs34xmu62szid.onion:8333 -zbmhiorqlldelgniyhwogswpvrlcdjqxxcfm6vulenrpwiadvv37anad.onion:8333 -zbnovu66ikceaodzrkpwww4vop6iwvtebbeznngo2mtjkikwknqzgrid.onion:8333 -zbwbqxytihkvupc5zhezoh7oibfb7bopfcw6y4qbhh2kugnsw6zur4qd.onion:8333 -zbwpgu4z2lfuto566v6duz2qw5kkyvor37rpihk244bfjzqiuohdcyid.onion:8333 -zc2c56k7hcdux5wrlpixrx6lfutylfamr676tu2nr5z2vf5gwoyzrnid.onion:8333 -zc4l45jx3txlag7hduov4su5kl633sykaw7guioejg5pq2qyuescabqd.onion:8333 -zcc4wsaenndkzqdp4xsfzn6ilsdhwzpqiswumdc22dv5ejejec3o7qyd.onion:8333 -zcdv7z3vetrpeo7souyie7u3vyy6w43cuautaogldhs4n2fitytsihyd.onion:8333 -zcezifa7mmgv4voul4jf4wbqmr24djgrskwszktkt5hihywblltpahid.onion:8333 -zcif26i4yzp53k3uedswyrqkdmsmkflpmclmasdo6hat57pqjpm2omqd.onion:8333 -zcnl5vojc5aufydmssv4yxeotzeqpvyoxyae4kmoskty77j4dx4aykqd.onion:8333 -zctnwv5ln3yktcyqsbgie3qcee33x44b5quhjdq4zwjprl75r3snduid.onion:8333 -zcugrsfyxb3y5ucbdndifvt5ilp47a2233sv42ryf2cvzoncrgo2mrid.onion:8333 -zcw6xk4bfnl46fx3mkrmlnknbwnpssxsp7hlllj34fdrkutzts6yepyd.onion:8333 -zcyumipuaiotm5fhffmhit3ajzrgqihhibh73lvjo5hdt4aituudguyd.onion:8333 -zd2mgisets23i4mslxjl75froqjygtue4lnoq56qk3ohd4qcxpop7pqd.onion:8333 -zd3fxn7nwlj76qyjseubm4o2gs73jv2g22px6t24z7p5oeogqe3icyid.onion:8333 -zd7irysta3wti4efbjq3di2jfv237nhwotupj3rtufvvav4e5umtkfqd.onion:8333 -zd7uq75dlcseq546lmbqymh37cninokajwkixpvupillb7fgpqgbwjid.onion:8333 -zdi46azujxcjqa2wnvdecld3bdkps5erbodcvw2mn424gk2by5mterad.onion:8333 -zdm5zxotwdsma3jvij3jmlke5wmblwy7qa2kikfctlzltexx6l35u2id.onion:8333 -zdn24r3iovbxfkp5qx5ng7ribn4cqm4v5ers4olnbzugyp2gbhd56yid.onion:8333 -zdovdneke7oxtxdnee7f43vcu5mjzoa5m4bexpxgvopa5kaxyrcwa4qd.onion:8333 -zdovy6gcj6nrmxaygnjqf3ym5hbd3s7h3irznsbrjmgdywd2rkj2m6ad.onion:8333 -zdoyjklv576u3w4paxyjb4jmdhx2id7xoqkd7zn3sspodasmmazbbpqd.onion:8333 -zdqon7u5ofin5gy4rcmkixc7u42xypwklntwceohpektisokskrn5gad.onion:8333 -zdqxfzqxbaa654nsngnaqdz3jfsfe2u4hxs42covbct2dou7z7jpa7id.onion:8333 -zdtchifs5gqldijr7vzcgqqaftlcydhatm57owdwzrgudns5vpdcx3qd.onion:8333 -zdzkcrnoctqhn26hjbngpcl54nmvozbodf4gwf7anfxjrwhjxgurrdad.onion:8333 -zej7mizjlb26qecppzvgyswervt7ov6f4x6fwrot7obvab23xsv5jjid.onion:8333 -zejyatwyaptvvubp6b22cpow3an47bsrve63l6rerkldmuwwb37b74qd.onion:8333 -zepqddw4zaqqawkx7aqezpqwykxmxxeh2opnl3xnq2i6piazcvyb6qid.onion:8333 -zeso2dbskp3curnpgug5mjyvhs7i6rero3zbqo5n534wccstcok6ywad.onion:8333 -zexnlgnfxldyx6leiqvyhuimrfxznjfjoko2ek6rdtu4dvwkvztfysqd.onion:8333 -zf4cm7bgv4qollcjcj7kpx4qrtqzcsa3q7sds2jc3mxu45gvazlts3ad.onion:8333 -zf4k4efdpcwsfyobz444dgdfnsa6tdbd6aor7p2s6mpuol3ladssb6ad.onion:8333 -zf6nwlrrtd6q73svcimgfp54pinn46hbcriqnqqsitz3fbibzmkev3qd.onion:8333 -zf6tbmhchmzo46lmhx6vu3smjj3y4hjjrv4lnwpa3uq7bvtjcwapmqid.onion:8333 -zfhx5nerqkerm3jfoq4763vlmay4pifit5a6a6jtcjxpu7t4galhxwad.onion:8333 -zfo72va3rnioxbhh4kuth4epqwqque74aehlonvde3re6mvhz4uzgaqd.onion:8333 -zfomias3uj7w6sai3ty3coxhnb6voldudbeyldgyedxqo6kfc7rg7sqd.onion:8333 -zg2yslkwabguckkqanyxwbncrtozc2fjivsyesrcd27xxkowkbcwnxqd.onion:8333 -zg7obxhb4c4j3dgzg47zffbetclv2so4foyutdxizfnedhdkhjzo2cid.onion:8333 -zgaubbm4h7qckt4pgtp5zawrcf6aazby2zk7aeo5xsqpgwsc2yrlbiyd.onion:8333 -zgegpxbr7z34gupenib4tuwywyk4nlevo5dkfg3jt6c2jw23len76qad.onion:8333 -zgjrto32gianyp6i4gc73nlilodiqyo2s5dkr5ev73yq4qvcjxkwycad.onion:8333 -zgp3f3dmwbnr7257rouxkgddijr34keobzrtk5gkm2dgfbw2bylcwqyd.onion:8333 -zgrpshddeijmdp34xfyw2kz22la4jxgwce42pupjp3bo6xtchsorrxqd.onion:8333 -zgvklnnz2avqcnyiffw7t6umb3is4tfthnkzbhnyfr76sjtwu5u35pad.onion:8333 -zgwclfbi25s4ta5hfiwylboeitti64xzoan5aewuqimp5j55nye663qd.onion:8333 -zgxg4d4jifuihgozqblrt3kjkrh5zhbr4uyivtrzf2khnbtbe4z3qxad.onion:8333 -zhabxolberrktnga2eixvhe6vmaoxour3ktd6jgjq3emzkgthsmaq3ad.onion:8333 -zhapnpxpk3lmrfsmhluytttodeosmie7yabywa3aaxmtkreh2lmeemqd.onion:8333 -zhdd42th33pv6qnfi7v3w3gddy3tlgu6pjo2bhh5ezuytutxhivbtqqd.onion:8333 -zhea7pvhuzw4cte7pkd7u6lwjyiqczxi7wgvzhfovtjd7qwdc24pleqd.onion:8333 -zhgdvhnh5zymbwrmd2rfjncparbxfiyraqh4imk6kl3tkltgccl5cgqd.onion:8333 -zhhkv5u7pxuu36y7vzu6wlbjpd3wftxfuadsst3ifs3q23eydmako4yd.onion:8333 -zhhxxlz3wvdaj4scdetokkqgs2ndmdvyfwq4qwrn3l3hv2iftlgsucqd.onion:8333 -zhrzks7gkdvyef6s2aogxxuw7iqheixmrdzgkqotpvl5bjz4vq5tkkid.onion:8333 -zhwmsba7q6vn4yfi63p4tc3dobsarso4322ynl5ofggjbyiozefttcid.onion:8333 -zhzpumb4itgdxy53chqowtu43ru23ag3f37r77ydjs3t5o7bookfe3ad.onion:8333 -zi77cxawtknqkjiod4rhf7gsughbvv2z6e7mg5kax465uc4vtg4cwlid.onion:8333 -zike5s7xtcgp6frbjgzjhcz6gsvd3pghkl2jin3sdasrek3vy7l4ibqd.onion:8333 -zip37ysefmcbnyqvt4jiag6dj3h45ie7h56hmw7ktheotkuagippyiyd.onion:8333 -zipzgdr2m6gmjfucup7xpertovt746f57hrgb7lj6m4rxeniem6zdgad.onion:8333 -ziquiv5d3hditb2r2qmt7hn7knosdcokxe3khj3kgn253l6cynl62zyd.onion:8333 -ziyp62u4xfsuljn5ae4n7jea7wfd6vfutket2e73bzrhpstozs5364yd.onion:8333 -zj55khmgsehm24efh4nmye7oao3u3l4tjuk5edghey3mt2ippfste7yd.onion:8333 -zj7jf7o4b3qztdorj2stojv4us7lzqs37fbubqpqq2wu4dxi3cxpa3ad.onion:8333 -zjdf27w3vt4rpyb6usa3r5yi455svyaha4qtsfwvyrmf3hmz5hckbwad.onion:8333 -zjgnxih45rz3kalgxvhyebyavcnohmoa3bcnl5cwkmq5pmbyypavqcyd.onion:8333 -zjx5rmakdzormbwzl27w4xcucehwiat3dnncoqdiwesbmb7dg4fpmgad.onion:8333 -zjy7d5t6rxljc64pvta3hqi6yxzfsnixtbslafamoxiiw6ptcmv3kfyd.onion:8333 -zk3cgisxp3uxevuxmbzbmqyhvkhezspeydo2bmhu72b6mw2kl6v43fqd.onion:8333 -zkc2lid246a5jr2dpxtvmtu2tfiwt5dbry3xybu22b62vguco5a4qvid.onion:8333 -zkisbl3pv7dsz3szdawti4r7mhrhssqxf3uopi3vrib5dpt6u2u7ckyd.onion:8333 -zkjnuuenigzhs6d5y62jct4tira6fzijqx2k3yzsdsyulut6ywp5muid.onion:8333 -zkjoev53w4e547zot35onpmij4fiube4aomnysttqtv576zdr7wex4qd.onion:8333 -zkl2fsiisu3cyhhsua7qlr5afhyvmfh4qmapgubioyhoepqdb46jceqd.onion:8333 -zkl7x3u7365zj6opig53dxtty7ctw2ijidwa4lbdbhcv3wkld22bvxad.onion:8333 -zknqouk6z7g7h5y7rmycqb6sgzykylbbfpvf5efmzibww377iminltyd.onion:8333 -zkq4fgcc4bxksbsi74pjwjfby5tdwn26yhjnmewy2qy6a3l5p6bnaaad.onion:8333 -zkr66xkrvecgu6jkyan6nxvtefynf2mpsls5csvf6lt6ltqvoscw5yqd.onion:8333 -zkxe2fnm4tsmbu4bdge7i7j2cesfrq5oznfzobf4mwtejbhenp7ubxqd.onion:8333 -zkzj45moxjhjvrzqweh5g3iyucdb2qaqby7vdtmlqbvxmm5u337aglid.onion:8333 -zkzj4uhvvpav6ee7djkfj2uem6tyswi7idzupkozspbgr2kfvrk5biid.onion:8333 -zl27cum3gly7nfhwl7ulnob6pyichpxglnss4ffqv3terkquhf3dm7id.onion:8333 -zl3dx4nswje7l5p2fgvypve5wugfqtcru2ud55qo77tqdp2btm6kp3qd.onion:8333 -zl4gt6uafawn452rlqb4w2mujut5tjcnq4ahdr6ucdyeu2gtzlsk2jid.onion:8333 -zl5voqvgyf7deglpxamz6hpg4bierfngqsmmu72wpeut7toja47v6bid.onion:8333 -zliat4frxeuirx3nbijcljvgr5wembicg26fdpgda4pnps4oguaobmid.onion:8333 -zliy5o4uqgpqj2nbgyadqnlomnjtmdlwoxcuduwcfavzsguj4z4iwzqd.onion:8333 -zlkwqytpxbhkg4umwpqiynz6niefzqjbiwzryg2zpwwmvmw6pmssngqd.onion:8333 -zlpztcqey4osd3omtpsm7micrh6jrxuqzeeendpngk25iyfhleieekqd.onion:8333 -zlx2jkuv2iuzffo35hc264rnvoimzccvtlljdbmut4es76qe5pnvs6yd.onion:8333 -zlzhg5hipy7nc4ulsaprgro53f63mjj7je7m5xptgkksibgvbc6r2fyd.onion:8333 -zm2j2k2nl7pug2amadjkrcgs5omdnxctyl7b6kmlywsphcfl6c22gtad.onion:8333 -zmfmdmzlsyy7owe6vpgugvdq664vjhluqura3skjlm6fzpgqe6udm7ad.onion:8333 -zmfmmn72dg5jjkovy4jt56c6btg7pgp7wmeh547zlvavwmlbrbsl5yyd.onion:8333 -zmjncrrwtui476nyn6sqbp67bvgdhotllq33vzwygasumv6d2us64iad.onion:8333 -zmmtddrew2mjtghs7zjiyi2eelmyss7miyj2axzwfgnmvzthx7phevad.onion:8333 -zmn3jyv5a2rod2udnreygi6uan4zq5ul4mhewyfyrf7a3ury72bycuid.onion:8333 -zmqvv2cdxjj3vbclq7l6rfdmjegmixwkxsnzzd6qezwp32vxkr2cbiad.onion:8333 -zmt7psgtnnqxk6tibhvwkdfuhtgtjatz6bpoyyl4ptuv3u6ko2b5o5yd.onion:8333 -zmtd72b4nsa22ocez2hbjsxxrdfuxxyghg3zjtqjob5sgnjpustat4qd.onion:8333 -zmuuhwxhoa6h53jijpb6mczcvtxhw6zyjymm53dwzsbmkc3kkv5v64yd.onion:8333 -zmvriguathsanquofxml7kgcda4tkihm5qked7a6ntbqk7rmz7qadkad.onion:8333 -zmvritlexdmgatfqjlexl7wsx3lmf7y3qxe2kqeergb7ntkfu4nky5ad.onion:8333 -zmyavuyz774c2fo3eb55yokivpr7qfxdpjy2t5wpeygunhulck7yxzid.onion:8333 -zmzjx42yxlpepdgya34rvwb3wc2peggturiedmn4sfjltgy6gjtspsid.onion:8333 -zn3gjkpqkajav76kaem2espqt2bw6ggfvmn4u3gmkonds7pqd5heqkid.onion:8333 -zn3mj2tggwpbzzkvtsovkrbdshbsvac7n676hbi76r72de2b4gknpdyd.onion:8333 -zn5purhx3rnikkks5tx4scnjlhewwll3uzcs4pgde3qeqawof3jefhid.onion:8333 -znaiehv3qrtloxdi5rkbs4eqpmuveazuftob3sqzw3ta5pyakuwhx7qd.onion:8333 -znbv4cupk7rrdk4rqi6xncbouhscxnqdlbxtltp7564isfv5vtbyu7yd.onion:8333 -znc4xhwywjqejoioap3ssxvtsdilsc6i5o5s2rnp2ecmxqe6xe2nh5yd.onion:8333 -znea5ol7qgniizv3og2gfcbxw2wi4qhk7dfkdlt7bbxpy5aflljygbqd.onion:8333 -zngxgkdgkqpfyepa5cvxlaxvlyluzdryhzmviar4ojzaduxw37hhdmqd.onion:8333 -zni7kioacgsy5haqiftnexr74sv7rzvgy5o6lmz6dy26vvwg5lffioad.onion:8333 -znlvmmj4dvpju46kbb6mob4kufyf5a4qivyygmjj36kymbaa4nzi42ad.onion:8333 -znmgbi6qlwwwdlizjxsc6eujnfwgytufu6guo67b54av4y6inwgxllad.onion:8333 -znmwoazdkcffprail6h4p4opy7i4zqomhpdxe5l5nc6ejqagvt4i7yyd.onion:8333 -znt2jb6nivjgl47s2gdcgac3merqjfq5h2n6x6mbjegx6fumtl2ownid.onion:8333 -znvkqu376ienu62x5hprstn36jfqxospcnfhpc3kq5quwcd6436pzuid.onion:8333 -znwekshd4os5a2n222xrllgjuyvsw7hsb2y6br7pkwjatywk5lerbtid.onion:8333 -znxkxyd564sfftgjscsmi3a73jsazxwhsneix3bgto4suyjx356xewid.onion:8333 -zo4fczw4drgcbsumtgmigjkiso4miz34ltauajaawqmqoa6oxmzy4nad.onion:8333 -zo5jasvz5qo7pkgrgn4r45twdic4zake6zpjfemj6x2ioxcwvs7yzlid.onion:8333 -zobj27bempyxsigdvawc7foivyyuek73hemep7zf2tajof54353ok2yd.onion:8333 -zodjfmegrevmjbppq2t46iluruefbgh3b46tbrl2s5qkprvbetk3euyd.onion:8333 -zofseltpp23n2xb6fsmfgkwgqggwhrelxmt7zq7toazybgehbs7d5fad.onion:8333 -zohxazkomcr5ggqlj2edu23zs6xiay7wfsrxuetrn2k2s5gwhwhcngad.onion:8333 -zokmgys3gsgs5oivjcqp3xiki25iexezy33ekzuratdz3j5unqpxrzad.onion:8333 -zosjvclhqzwklml43hvsdmupglajj5lfdb5h5frgym7hsqo25rwrbdad.onion:8333 -zosk6fx2a3mxkfaeayziiuizq3y3j3azzp4ylwyh76wq2sqtaenuwdad.onion:8333 -zovm6wkattzmxc755cgqqd4sxugn3jaxw44izlm4yfpot2ucfeqnukqd.onion:8333 -zowc7rklhd6xhje724xomkftwimuihacwcnxkt7vhbjpvpkdahvlhxid.onion:8333 -zp3vpkpcfdx5lxvnuellqaf5qdvhu4luf4zqfx5xjo2dge7cqsxhsxyd.onion:8333 -zpgobpk2j2suauhuzfmh4iiz3y2zhj3xvb3g2t4a775t72stt3majryd.onion:8333 -zpgybnbaxfvzjeus7qna45zchxdkekjpk5webdkeqtxfwcglgogm2vad.onion:8333 -zphjbml3fqtbez63bjvd4s552yc2xebitadkpw2jon2qkbapbiltijyd.onion:8333 -zpnoo3qordv4xj5hjynkssu6wechvup6to7pamrgbi4ljmfugjyzwwad.onion:8333 -zppmhj76a6dyjch5qtubosxcyvtwjnb6zndsfywxci7dy3vc6lbfusyd.onion:8333 -zpq2nzcnlasmy3rmwtmaybav6t7xfrvorqqdwntnbgbxqujyy3dkwlid.onion:8333 -zpqvo25bxu4n2u3mh2pdzax7wmpsitd3qsszgw2ye3mpfdpjbg52kgid.onion:8333 -zpx2tq27yviwzbpc4nyjfqtlhigoa5k7cwl676nft7bkajo6jq224hid.onion:8333 -zqlwzzfzdoacgngtsnofmyqetag6o44f5r72opj733y434b7npnb4oyd.onion:8333 -zqq4g2eikcfgls64ffstsylfbqrfstm6n2otvrsbtvvjpqwgyqdnmbyd.onion:8333 -zqrj4fhhp4mq5eh5xptzcxjzpae37brkdn3voz32qsohl6noijygdkad.onion:8333 -zqrwah6dn3t5fuj7ohlyka27zzopduhxy4wyknfrtqpx4sykece65fqd.onion:8333 -zqtyvr7h277x5rxin6rhsrsbhwcfsyyiqgghpk6jlbewej2v3tn27yad.onion:8333 -zqv5nepyrwezkym2ba5s2sskmi2qck22snw2rygeke45bxg2o4vckuid.onion:8333 -zqvbnqwwhtoux2sxicng2blfiowk5mvty7c5xnssxwtlsjzalhg3zqqd.onion:8333 -zr222c3ybuqxn6a6piydvfos4zjnaklfgh6kofmujmolpiprfw4z6vqd.onion:8333 -zr6ffisxxo4gelmkoyb7izfm7ehjrbqbnzuguw34to34bqhxeeqzzjad.onion:8333 -zr7sqclimv46jdnmmeazqrhflhiqkhhrz5i3ed7yvyue63swk3qkjnad.onion:8333 -zrrfr5sr5wrgdt6rn44cxnotlvwe7cl67rgssw5dwsax42evokdaw6id.onion:8333 -zrrhgs52ftlylshuwp5e2uesgqnwct7h6cqhzofdduwoi4sz3shmxxad.onion:8333 -zrt3rg4paxmo24ucd56eehl7apindhbubq3ej3q5nhr6i72jv2eznryd.onion:8333 -zrvsjjrb3lgvmeftz2vfjva4pl63htmv5qyviq7zhnfmlk42evrxdpid.onion:8333 -zry2rqlcqf5p5e46wc6nmtcbt5vd45mf4hyf4nxlqogckoniufdjklid.onion:8333 -zs47b66pljpz4ahompanciv73xtztnnzkx4wjklt6hh4drsge4m26iad.onion:8333 -zsalwutefh6m6x6yxccbhulzrz2bmo7dzu2ggu4hxp5zv3xx2j642dyd.onion:8333 -zsbzferezmnyxhpktxtccn2xxuggmdzdnrza7pqjlnwjorgx57y2acyd.onion:8333 -zsgtoyy2svehhfba345dx3dazp7tfdio6o34zxlcgylq6pi67gjq7nqd.onion:8333 -zsi55x2nvjc4oqrpzzopkneukb5fudnm4e6drao4x73lf4zshhcvllqd.onion:8333 -zsipwsjpm4f3p6ueczh7lqei5rp3cusl6t4d6nntnwxq72hori5f7jqd.onion:8333 -zsisadra7jlxp5nhec2vsjwspvvnk6jemjxk7zn7arypl6cm6dy7mwqd.onion:8333 -zsr43xqj6nsrqh6qgxghadctltwytnaw4zmlvx6exqybt2qdt72f5yad.onion:8333 -zsxgefpkofjc3nti4qusk3pdqcfinkljajlwcb2cee2tduxltxbmrpad.onion:8333 -zszufrszpweaoysubpdnqparmyotjnev6nhhcnejhjjftu5sb55kesid.onion:8333 -zt6gkop3n6aggrxucnaqp4yrjeu6htwvuy2nyn3vadjjrodwxfhfv3id.onion:8333 -zt6hvzyoalzm4a576drn7yfvdetdvzwwouvfz435wzrf5pcnxqxplaad.onion:8333 -zt6v7eqh7vvlwy5kjzbdfgkw3syj3nnhckyghlzgmwwfccxvyfusuzqd.onion:8333 -ztcmlrstdkp7coheeolpwj75gp3imzgiw26xnoiucquwhxxcofao63ad.onion:8333 -zthmey4ueoutf7q36nwgujxu7hq76s5ifbtanvze4mxq2s2xq2cmjwad.onion:8333 -ztmwsyo35zkogpftujm2o7oilhucjxe3w6bjagsaiwtb2bu62vgjptid.onion:8333 -ztou4ytvgvpcakjaje2c6l5j53rxcxes7qhkerszi4haffxfpj3kdnyd.onion:8333 -ztwryklhcnfoeck4qntt2aitoilit2cmmr2geyqo6cjc4nwr7jlludid.onion:8333 -zu3ekh3vtqjfnxqjqlmnq3jbqlg2zum4ehgirz5cggwe2thjmgkz4cqd.onion:8333 -zu3yh7mvqw342e7qt5amwtwe2btjubi6t75k7wgcpsyoicsnpgbgj5ad.onion:8333 -zu76ecbahyc6ofjiiutna6myxmfdcsuhcrhtgpifbw3vfo7njd4b5tyd.onion:8333 -zuaotutv2ngbf5ot5kvz75uehbh5e2j726fglhqw7omk3b7xnaastpad.onion:8333 -zubmiztmnfy2vqowqmpyzbqtf2a43jgazsex6zlxokhfmnzmi3rht6yd.onion:8333 -zuc7sobx6ttj7lswk32raexasfbxc5kd6a3l6td35srqzkj3emsv4uid.onion:8333 -zunmnr7czrxvfjgxtvkwk6ziti5kskx4fi3j4dzahhdljfsqtz7yeqyd.onion:8333 -zuoml3m3jdkoh5bdrwfecnew5f4mrlcwhmhkn456qsa72cp274pbgtqd.onion:8333 -zutyd7pzkyejctriyr2lqlrex3arkunntsdjo3kgw2qj5u3fj5uyusyd.onion:8333 -zuzdl7nnjhy6inyqwsc5i7fae2nregm7wnyrtolaxhi6oiufyc7l26qd.onion:8333 -zv2nusexbcrncbutlcprevwhvbtqlyri3stjwmgl23x7fdqkmae6owqd.onion:8333 -zv63heoa7jstwhq3wg2nibip36bw4icd7jphccy3li3nut7gp2gojqqd.onion:8333 -zvbhycudpglrdi3sk7yixe64eknydwzzisc4n6xmxwhb7xyyzevc4nqd.onion:8333 -zvgutw2u7tu4dx7t25leghdp6j5n44u464mmoypafwstayp6ggabtkad.onion:8333 -zvjn5jscn7jncqss44uh53gvi6b4eycjqp42t6pv46bsr7gine5cbrqd.onion:8333 -zvmxfy5z7nxeknglvpbh7rveoppkyvvzvnpwxon2kgkepafnq4igheyd.onion:8333 -zvpcm7eemfvlklgqio3fgzcwa2vukg3n7caov5itik36kdua6mvm43qd.onion:8333 -zvzirfk3h4hk52j4u254y2np6ve2xttd2nugiccsqw2liiw7aqmglkyd.onion:8333 -zw4olgpxujj6iydkmhuxbx37b52syl5bm6embyebesysep2ignp2dgid.onion:8333 -zwbnovgpo4qxidylubpdrhxm34t23iwaniawfshiqrilttwqjnnlohid.onion:8333 -zwbqgh5le73aurfmbwf5ivjb7ycemwnjiq2jnq4sqz6epl7rdtd6rtid.onion:8333 -zweiy44ngrkfzhnaoqov3fopwqd3uhwsen4v6sdyf3ynmhlpuluvzeyd.onion:8333 -zwg2cvvkm37u2hicwbjasqzdqdhcblwvtzsulmz4kpbebf77jheiaaid.onion:8333 -zwrp2kb2covbrr3xdz2pxr6gg6ndnhpcgfvjkjr43eudnl5aswxgvbqd.onion:8333 -zwsapfrsxzsomsoty652jifwii56st6fg7bs2crr6boveh5o6npl7vyd.onion:8333 -zwtjkx5blzs4i6e7hwfeekcwufdl2lba4j65243tvkajder5iodkavad.onion:8333 -zwu3ep3zqki62b7ldjbsxk4dm4rlppkxpzzqfwsfvkoihxltm3y4qaid.onion:8333 -zwwpbfpymszcmkwlfozzl26m66r6n7xzgnw6bs4nf3pypqh36ya2w6yd.onion:8333 -zx37fw5b4eatt3dekaefun3ln67agpt7oqobeacvyq4keurbj26azwid.onion:8333 -zxaujdps5ce6wvk6ykbfquygtbli4ecvpokj7oyfxjqiionn3u3fdsid.onion:8333 -zxbq3k7hwswo2f374ahsmlgkpdj7ju7pyygurkvzqaoh35vmxleewsad.onion:8333 -zxc2bzuqdkippxthxbg7n7e3lznbcnx7zyitlhwvjusbwr5v32oxueid.onion:8333 -zxcnzlo2eigfig66vxyx43znm66a5i4ieuiosycgddgzdff4vhn6zhqd.onion:8333 -zxk4bqrede3tnlb7ymjlsoyupc37r2vqe647otr3nczqmgfeoyiu75id.onion:8333 -zxqdpu4gmvn5vz2kdld6c2swqdzknwh2czwsw55vx323orvtk6a6igyd.onion:8333 -zxqe6efq4odzd2mvyeglqto2cfggagoicgcvlvca4mxycg47jei4uxad.onion:8333 -zxzfz3z4nbb7u3ifcv2p5xenzpbnzuuezelbbjcfrmupxtqyoh7uhyqd.onion:8333 -zxzqhfwi3gdheuxmzagp4aw4aks6cii2llljapcvqhtqrxlksxddo5id.onion:8333 -zy4jeshnpx3i3wjcqrb27qcea4qetpez65wpocat5sqncz24xeo6sxyd.onion:8333 -zyccgvzokepone36ulu74l54ad4dtqv7a2bjzcvopj6rg5xhbc7ihjad.onion:8333 -zydziohabauwybhbqkegn4d5r4257bmfain36fatcxdbj2nw5zoa5vid.onion:8333 -zyetfkanxicfp6tt5tegkxlkoz5rl2i3zsc6hyyqizahywbktezfuwid.onion:8333 -zyjfoui3hrpsw3fo4owxrztclffqhr26wdedizvz5xvlgurgixit2mad.onion:8333 -zyku4bk6pdifla26hympigytlwsx4htajcn43hhobdbrv4tfojv3snqd.onion:8333 -zyl4kfejs3t4vefsvuqrqopboxrmztuun62jick4uh3wpu4mw7dpqlyd.onion:8333 -zyphknlr4ogrknj5t64qya246kdaasgirn4iercvesggqplzzxsisbid.onion:8333 -zyrodumrgvgpinhygbi5molpbhl6ndfs3lwtt55pumd6wy5k7nb3esqd.onion:8333 -zyvgumk5pcanh4zk3z72glefxgbd4dpyhsbzvqlsp2gspaw37lrhjyad.onion:8333 -zyyefl5unnw7lnrjlgfyvnytw4iy4n4cy5bbs2nudjh7wp7psvefmfid.onion:8333 -zznngqwcp6g55wkjg52rzeogk3fcdpopyl3zprh2fz266nykv4sqveyd.onion:8333 -zzntdfpcb3spf5pb3g2gczw2njmhwwksgxt3twbzjhbaisihg7h2ywqd.onion:8333 -zzsi7brufwylb52w3bcbqvp5jx6vribh6geiqfy5jhxpihqjjaox7vad.onion:8333 -zzthz644hdjxn3d54xrfe7snnuyhsx2cguy4kqb6dpc5u7aun5lflbad.onion:8333 -zzuipjogcfvs7uyfhfgesehon6viegga3sc6c6265n235pqmkwyqfmyd.onion:8333 -zzul2xvyhqvajnd6zfs2dzljoppx5lsp2xt4qad7256kpxrv3wzyiuyd.onion:8333 -zzx4r2yrkxul2kg2ojoeijwce3skll4wbkkjw5xprstn2o2xw6n74wid.onion:8333 -zzyp22x6ryzyin43pltkup6jki5ynboh6cwpucscx5a3md2tooqn52yd.onion:8333 -zzzzzzzz5bs2qnoijxlhxd3ibxipajesgprqlrxtpfbygw4zcaf6oaad.onion:8333 - -# manually updated 2023-04 for minimal cjdns bootstrap support -[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333 -[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333 -[fcdc:73ae:b1a9:1bf8:d4c2:811:a4c7:c34e]:8333 diff --git a/contrib/seeds/nodes_test.txt b/contrib/seeds/nodes_test.txt index 2def8ae644..5339f33f86 100644 --- a/contrib/seeds/nodes_test.txt +++ b/contrib/seeds/nodes_test.txt @@ -1,29 +1,311 @@ -2yq4xcwzvb2ktyci5lpmb2q3nl6qqywb7nrf6fkcthha7l3tle2q.b32.i2p:0 -4g5uvbkvi5fvyditekvzajldtzgurorqjupuwtmymrjloq6cjm5q.b32.i2p:0 -f3w7soepsy7jqwf7dlo4ro2qkyapg2lrb2dkkvwfwuymgaqvljqa.b32.i2p:0 -nr7nozlb54xv3ozg4ksvcr3ofzfwfeud2n7xijywvt22ixzal7qa.b32.i2p:0 -o6j3b33bv26vthoqzjy3h7a3qsuqbtbe3ulajmjzsl43vaqyieyq.b32.i2p:0 -ocqipbbxx4paopgkkbnj234ie7opzrtca5gtiwr6oda3h32rzgsa.b32.i2p:0 -r2zdpkcslf7e4t2fmglu45xhfw5zgupthdh5pcewdo6jajumveda.b32.i2p:0 -xgctj4seo3ofstiymoyeuzq74bvddrbr6jtia6erodlf5va3cz5a.b32.i2p:0 -y5e6aqz4jkjjoeipoxwurzc2jrfv6ilvfbdqmjqk574maba5uara.b32.i2p:0 -ye3ajv2tgpq7jvvzzn5wxbtmd3txev3axsdla5bkpobeiwccyjjq.b32.i2p:0 +[fccb:248:11a6:1042:bca:1218:f7ce:7d3d]:18333 +2.87.72.235:18333 # AS6799 +3.253.163.14:18333 # AS16509 +5.182.4.106:18333 # AS49505 +5.188.119.196:18333 # AS49505 +5.189.175.92:18333 # AS51167 +5.252.21.232:18333 # AS50673 +5.255.97.91:18333 # AS60404 +5.255.99.130:18333 # AS60404 +8.222.228.217:18333 # AS45102 +18.143.108.213:18333 # AS16509 +23.93.89.199:18333 # AS46375 +23.94.96.134:18333 # AS23352 +23.137.57.100:18333 # AS16904 +31.220.99.65:18333 # AS12430 +35.192.191.229:18333 # AS396982 +35.200.201.79:18333 # AS15169 +35.233.152.219:18333 # AS15169 +37.27.58.134:18333 # AS3209 +37.27.116.87:18333 # AS3209 +40.118.228.187:18333 # AS8075 +43.247.184.50:18333 # AS4134 +45.77.25.14:18333 # AS20473 +45.129.182.59:18333 # AS47147 +47.254.127.252:18333 # AS45102 +51.77.42.234:18333 # AS16276 +51.79.82.75:18333 # AS16276 +51.250.75.48:18333 # AS200350 +52.174.187.17:18333 # AS8075 +62.72.27.212:18333 # AS32641 +62.168.65.42:18333 # AS5578 +62.210.207.63:18333 # AS12876 +62.210.222.73:18333 # AS12876 +65.108.39.171:18333 # AS24940 +66.85.145.134:18333 # AS12189 +66.135.29.243:18333 # AS20473 +66.183.0.205:18333 # AS395570 +67.4.82.9:18333 # AS209 +68.197.203.181:18333 # AS6128 +69.59.18.23:18333 # AS397444 +69.61.32.242:18333 # AS141518 +69.197.185.106:18333 # AS32097 +71.8.29.12:18333 # AS20115 +71.13.92.62:18333 # AS20115 +71.171.123.161:18333 # AS701 +72.46.129.50:18333 # AS53340 +73.22.9.231:18333 # AS7922 +73.53.42.105:18333 # AS7922 +74.213.175.99:18333 # AS21949 +77.163.221.171:18333 # AS1136 +79.192.39.105:18333 # AS3320 +80.79.4.249:18333 # AS49981 +80.93.179.252:18333 # AS50340 +80.241.194.147:18333 # AS12964 +81.17.102.136:18333 # AS15598 +83.231.240.3:18333 # AS2914 +84.24.77.191:18333 # AS6830 +84.155.113.177:18333 # AS3320 +84.247.164.103:18333 # AS49788 +85.203.53.89:18333 # AS39351 +85.203.53.149:18333 # AS39351 +85.208.69.12:18333 # AS25091 +85.208.69.13:18333 # AS25091 +88.80.148.215:18333 # AS44901 +89.117.19.191:18333 # AS7029 +89.153.161.16:18333 # AS2860 +89.155.239.107:18333 # AS2860 +91.123.182.164:18333 # AS51648 +91.148.141.210:18333 # AS203380 +101.100.139.249:18333 # AS133579 +104.237.131.138:18333 # AS63949 +109.233.109.26:18333 # AS41798 +122.208.117.197:18333 # AS2519 +124.236.16.91:18333 # AS4134 +129.226.198.211:18333 # AS132203 +129.226.198.246:18333 # AS132203 +131.188.40.47:18333 # AS680 +132.226.61.215:18333 # AS31898 +135.84.136.157:18333 # AS174 +137.184.2.124:18333 # AS14061 +138.2.100.114:18333 # AS31898 +141.98.219.142:18333 # AS20326 +141.98.219.199:18333 # AS20326 +149.50.101.27:18333 # AS174 +149.154.176.47:18333 # AS3257 +152.53.17.53:18333 # AS81 +152.53.18.109:18333 # AS81 +158.178.228.41:18333 # AS39550 +160.80.11.66:18333 # AS137 +162.0.208.90:18333 # AS22612 +162.244.80.218:18333 # AS19624 +164.92.140.21:18333 # AS14061 +169.155.45.180:18333 # AS3356 +169.155.171.252:18333 # AS3356 +172.172.62.86:18333 # AS7018 +175.209.228.141:18333 # AS4766 +176.108.193.97:18333 # AS47914 +178.21.118.82:18333 # AS49544 +178.21.118.96:18333 # AS49544 +178.63.87.163:18333 # AS24940 +184.74.240.157:18333 # AS7843 +185.28.96.16:18333 # AS8220 +185.70.43.192:18333 # AS19905 +185.107.68.135:18333 # AS43350 +185.132.177.104:18333 # AS49981 +185.186.208.124:18333 # AS206428 +185.190.24.72:18333 # AS9002 +185.209.223.195:18333 # AS51167 +185.210.125.33:18333 # AS205671 +185.232.70.226:18333 # AS47147 +186.154.207.228:18333 # AS19429 +188.117.132.82:18333 # AS31242 +188.213.90.149:18333 # AS43414 +188.246.168.144:18333 # AS8595 +192.198.81.243:18333 # AS31863 +193.198.34.24:18333 # AS2108 +194.95.66.129:18333 # AS680 +194.110.169.133:18333 # AS9121 +194.233.91.153:18333 # AS141995 +195.123.244.121:18333 # AS24971 +195.179.230.180:18333 # AS12874 +198.58.102.18:18333 # AS63949 +203.132.94.196:18333 # AS38195 +205.209.119.150:18333 # AS19318 +206.204.104.7:18333 # AS6939 +[2001:19f0:4400:63c7:5400:4ff:fecc:fc1e]:18333 # AS20473 +[2001:41d0:303:2dbe::]:18333 # AS16276 +[2001:41d0:303:87b9::]:18333 # AS16276 +[2001:41d0:601:2000::1f70]:18333 # AS16276 +[2001:41d0:602:2dea::]:18333 # AS16276 +[2001:41d0:700:544c::]:18333 # AS16276 +[2001:41d0:800:1d55::]:18333 # AS16276 +[2001:41d0:800:3d4c::]:18333 # AS16276 +[2001:470:1f05:4e5::2020]:18333 # AS6939 +[2001:470:1f07:6f2:1671:5a1c:2433:b517]:18333 # AS6939 +[2001:470:1f07:6f2:2e58:b9ff:fe18:e093]:18333 # AS6939 +[2001:470:1f07:6f2:4dfe:d8fe:3dc7:63f]:18333 # AS6939 +[2001:470:1f07:6f2:6a34:c61d:97b1:c98c]:18333 # AS6939 +[2001:638:a000:4140::ffff:47]:18333 # AS680 +[2001:728:1000:402:546e:98ff:fe16:68c6]:18333 # AS2914 +[2001:bc8:1201:409:1618:77ff:fe5f:b12]:18333 # AS12876 +[2401:c080:1000:4cb2:3eec:efff:feb9:8604]:18333 # AS20473 +[2401:d002:3902:700:8708:37c4:e231:d3d8]:18333 # AS38195 +[2402:1f00:8101:713::]:18333 # AS16276 +[2600:3c00::f03c:91ff:fe5b:4cf3]:18333 # AS63949 +[2600:3c00::f03c:91ff:fe9e:7f03]:18333 # AS63949 +[2601:603:5300:83b7:0:ff:fe00:420a]:18333 # AS7922 +[2604:1380:4531:1700::5]:18333 # AS54825 +[2604:a880:2:d0::65:c001]:18333 # AS14061 +[2605:a143:2162:7067::1]:18333 # AS174 +[2607:5300:203:540a::]:18333 # AS16276 +[2607:5300:60:85a9::]:18333 # AS16276 +[2620:6e:a000:1:43:43:43:43]:18333 # AS397444 +[2804:431:e038:cd01:aaa1:59ff:fe0d:44b8]:18333 # AS27699 +[2806:2f0:90a0:45fe:dd25:f6df:4741:4a3f]:18333 # AS3356 +[2a00:1298:8001::6542]:18333 # AS5578 +[2a01:4f8:173:230a::2]:18333 # AS24940 +[2a01:4f8:190:4026::2]:18333 # AS24940 +[2a01:4f8:231:1eaa::2]:18333 # AS24940 +[2a01:4f8:242:4c1b::2]:18333 # AS24940 +[2a01:4f9:1a:97e8::2]:18333 # AS24940 +[2a01:4f9:1a:9a57::2]:18333 # AS24940 +[2a01:4f9:2a:2ddd::2]:18333 # AS24940 +[2a01:4f9:3070:266e::2]:18333 # AS24940 +[2a01:4f9:3071:219d::2]:18333 # AS24940 +[2a01:4f9:3080:358c::2]:18333 # AS24940 +[2a01:e0a:3b3:1420:7ca0:3a9a:5cc3:b644]:18333 # AS12322 +[2a02:4780:10:402f::1]:18333 # AS47583 +[2a02:c202:2189:3702::1]:18333 # AS51167 +[2a02:c206:2075:3352::1]:18333 # AS51167 +[2a02:c206:2196:799::1]:18333 # AS51167 +[2a03:4000:2a:514::]:18333 # AS47147 +[2a03:cfc0:8000:2a::9532:651b]:18333 # AS201814 +[2a04:52c0:102:2219::1]:18333 # AS60404 +[2a04:52c0:102:49af::1]:18333 # AS60404 +[2a04:52c0:104:160c::1]:18333 # AS60404 +[2a05:d01c:392:c900:78ea:ba95:334c:1d7c]:18333 # AS16509 +2lsncqdflwk272dhydrxf7ikfy23ppnmm54dnynyxiym6lqf3wowrmqd.onion:18333 +36fwktckggarkclbpu2pumsdpck46ahe6cwpozd2gm6q7kgdqljclmad.onion:18333 +3rlrfxaj4sphzedozs27qrefuw6u3v2cqu2ctbrbvhsc3wn34iezxjad.onion:18333 +3tao6wnydihsqndjw5pqbko25rxk23wb53gtyv7vmbmc2j7vw74cr2ad.onion:18333 +44sgcv5dvpplt32enlneddyl4gd4z3tbezl2scedwccndyzrrp6lcgyd.onion:18333 +4w3f2mxe4ftodocermsazs3qlpo37igkdgne6ka2p6wnnrgwpzqw65yd.onion:18333 +67l6l2k7mqbl2btyvo5h5lki3kxcrgbunlk7brcloyaoaftbs5mnsuad.onion:18333 +6m7khktveimc35yjusgeprndw43grjexs5bpruwkogbh5lovv47drlid.onion:18333 +6rnqpqqcpllqhjoa4gwrtq5yi6fdch6uqzapdee2gq67gxgsl73v4uqd.onion:18333 7ph7mrc24te57mvppajfkfj4mk7zuz4teukymt3wgpdpw6vpndeivtyd.onion:18333 +7poqajl6svz4vr3aqi7vdtar2t56crbrtj6yi75ydrt3ighyx7q6qvyd.onion:18333 +7zlqrihb5do5ebbmjwgspxigqfdmkfslkqtg2ngdc6ypsunzb4iootqd.onion:18333 +adjnsxivlsb5m4e4bfthvvccjfv7zkpyjyebvatlhyqycykd7ibjyoqd.onion:18333 +adstabjz7ec2y3jt4w2dvummowzv7g6m2f3kajeejffuaz7ojwj6epqd.onion:18333 +aesy6tfufadkut6flu2bsqgnw2422ur2ynjalguxlzuzuktg3zehttqd.onion:18333 +ailib3qk4brh4z2nvmmadoi6gbsw7fihfxtr7rnm4z5d6qcspr7ky2qd.onion:18333 +ayx35r2mhwydczzoqu7b6dl3sup4oht74sgnlrjkxybzh2hmfnaix3qd.onion:18333 +bek652lfs7mje46zauhfxtdh2zohe2jpbsmlhulusuzao27uwpwd76ad.onion:18333 bkzo7mpxuar7rhsbiwdaxqcymixarcbdmb3sdaqtv6yb2svqttz2s6ad.onion:18333 +bwyudvl3if3r7ese2caymfnbxqztc3mgr2i5hurjttlabhl3dfgyzead.onion:18333 +bzn63lsmsuvzlg4uqadyylxaggdcrzkb56muw2b43ft5qkynvzfopbyd.onion:18333 +c7zrq2yqt6rtn5dxkczp5bv62k2jncv3mscoo24c24rljbplr2dvhsid.onion:18333 +cqhut2deas6savhop2yue7vebu77fd3einx36tlgxr7bb6vlef3lb2yd.onion:18333 +cv5z3izcu7fmtby4hyjliphp6bh2a3zmm27tfendycu34tw2tka72syd.onion:18333 +cyl7eujkxl3s3cbuhmouhkxt4cdfplpbha2z6j5adacdaq2rjj2dlzyd.onion:18333 d63vf45ta4chrewnruyvypm7ybfxtut327crtq6qfyrvcwx434rli5qd.onion:18333 -efqfw6vjq7gpgyhosu3qf24hsshxpbhay426ccsgz54key4cvwund6yd.onion:18333 +ddsxs3zdkspqkcszmx74rkw7gqjgpz2ufb4qqh4dz5iaysoe3fvtpdyd.onion:18333 +duuwdfnlrudonwgdvvaud3i52zdxg2bjey7jmzskgcauiyejyffrh5qd.onion:18333 +dwb47cmqa2tjpmvjaear7gdcars2lez6niefhi4qf22qehtyta6577qd.onion:18333 +e27nbjkou2mkquoytjil27g5h34wkgjtrwupn3muc2c2b76dfdkvkiyd.onion:18333 +e7tkrf54ng3q5vcn5gn77zwjwm74lkfav4mwdux3pvon6yvqg3tf46qd.onion:18333 +eev3vuh55dymhn3z4lmhargcy2xzm6l4yyd5b4bgfstx2sf75ms6mdid.onion:18333 +eyjahrgj7qadzcotanxfbhshsjm7yj3p6tssiupiub7k5s55nxc5xwad.onion:18333 +f6awicobzr3x4fz3dnxbroarbuleq26jzltnl6wknkph2luxruwijiqd.onion:18333 +fbimesnyhzubbzqc3uaufzkbyfmnkxvypoxaveaub7rzpzh2foxrn2yd.onion:18333 +fjcr55gg3vv7qik64sxnihheuvkfytpvzm5jmgz55cp6427yvyjsotid.onion:18333 +fpzycmcz4drh46fhcfdkgibnp7qgioo3upquxyjwk6zegirbcd4xqcid.onion:18333 +fqls7cvum7lpawad7n5zrvmrqwrd76quc5r7pblndaod3wqjlpfzxgid.onion:18333 +fwswqt2rbdbstx5kza4gb7aok3gezazfgtokadqeiwgkgdkwwdmmidyd.onion:18333 +fx7erwmkuhj7p2eiuisjwg3g3a3aw6uglepa47gwc76dlrwpc3nn5uid.onion:18333 +ghqbqp3dirya7espnj3m3kh6mhalqxjv75muum4seukopedtwysxc2qd.onion:18333 +gpvbbdsv673zfg2mpbzxexnmv3oqakgqooyvyzrlhu6mucylfob4whid.onion:18333 +gri2j4tudvoxaz26jbzmn4kloo5z7qsi3vfi3c5ok5tunm3yzmfgwyqd.onion:18333 +gsw6sn27quwf6u3swgra6o7lrp5qau6kt3ymuyoxgkth6wntzm2bjwyd.onion:18333 gy6nih4pmp5esyvvnhlj6qvk7zkbjuoswkxffyiip3dbkvsfxwz5zcqd.onion:18333 -hwipziotclxg3ledn5yj5j6n6pkrgnmlksozzlrtlnlpguvixox7naqd.onion:18333 +h4xr7yovy3kgrohdlb5zljtyweelyctfgf5q24nlhyoxbmjmbl7bfjyd.onion:18333 +h4yusgljraifanij4pxkw4qks4iilqbq35absi24cinuvuym56ge55ad.onion:18333 +hba3mphxhpuy4x5gjqyq64bwtlzlfuscxc7n5lh4k4oiwrgcz5ujwtid.onion:18333 +hj2txlxajdlh7jsfwqxtp3cltlptsr33ctjkbxhbzbyirkmcpfhsnyad.onion:18333 +hmtbnymouaimhnxazujw7i5b7hqdixrlibdyn3td4bdw4sj7sbnb7fqd.onion:18333 +htkiqaqoql7pjstenmw6v4blm6l57d6hl6mewxkmfi3qumozflx3gzyd.onion:18333 +hvbmmzvqrpgps2x5u4ip4ksf3e5m2fneac754gtnhjn2rsevni6cz3ad.onion:18333 +hvtxymvdb55u7lhdw6775akqy46inunl3uup27gnsxm2bqmv55wbacqd.onion:18333 +i5fjp7ggx62zlfkibzn7s6glpjp3h2ypfom3lmqixig7qbdgej35wfyd.onion:18333 i5gphw2d224tniqkjebxdwz5ygbbo5gcushoyevv7x7o454b6qlrzeid.onion:18333 +ihalgm3hs54h7aq37hbryaxcdlowmlms54i4cz6hqbz4n2qjjiw5uwid.onion:18333 ipbzs2lbe7lab2xaikvkdkwxian6t3nakaoltwbshpevbszdvoyyjiad.onion:18333 +iysx2dl4tpojiclh32iyhel6z7h227c7o7buzk5wuqw6qhuytvsu66yd.onion:18333 +jbgve7zi4vx5l7654ih4nzutspu36dvs66xlegciur2cpym4gdjigbyd.onion:18333 jjfuyj7krgzkmpxvn3b2j2hwlzkmze3ezy3ifwk7dnswwawgmzqhjrqd.onion:18333 jnphftehkfstwbko34idxlpo5fdw6lromkmeukxh3xclthlstehpg4ad.onion:18333 -jrhpwqahjrj75gtb7gt23eve65x7bbawy7j4edhmgbo5nj2mkaeghbyd.onion:18333 +jpujgmcr2ftklxrr7uwxh3jg43uqatys7wgosfbpfbx5txw2nz7wgnid.onion:18333 +jsc4frvvnl2d3bhzyofsc72xpztgm23nl4fnb4dwkzsxr6fhij2q5iyd.onion:18333 jun6gdmbgasr57bhr4zs3dfhc6pzpaw27nqb4dadbai7yrbq55zskeid.onion:18333 -o52y7fadtubr4tuqhix6ymrin3qzn7ubh5tewuuehw5wxcbnfj6yaoad.onion:18333 -rigfm3joif5lsl7b7yr6d6cvddukawykm7kgguzfwi6dplckyz6x7gad.onion:18333 -t6d6epb5ccbo4e66iaanukraxpjmqiqsz6poj5uvxu2ownnhcguygdyd.onion:18333 -test2vozlxfznmfyxzkulf3l6qe6dti5hqfjsxar5lml45cjnyeusmyd.onion:18333 -uxtmtmpkfaxc6zcxaxgydrukyd5jdrcp2m5oubpimijy44rnjuywijad.onion:18333 +kamanho5clcpn5l3sc6ih3vb4skmfhgxw3h2mgs7e5idfezu5dw5oxyd.onion:18333 +kejyzttreyd7nj2sxx25nk4qwgxtuqybylxuqrjroe5mbhlr532dplad.onion:18333 +knkkqbxhdit4xilksb5ys3qnqv63tah5uvu3n2imu4bycipu354ambyd.onion:18333 +kpsy7bbqxiotk55aacjt2hiaj6h5pxjjvsb63hgos4ayfzwrmnsqgsad.onion:18333 +kwjxlauwjtecjfsiwopbl5pvn5n6z5rz76uk6osmlurd3uyuymcw7aid.onion:18333 +m27hd27n7dmnygddnp5bnf6vl5uks77jrq2uhtxxvgewclzjwsixz3ad.onion:18333 +m33zm5qtzgaf65ahaxbom75zoehyzr3lbqf2obtpzzzjebv7yd73fsyd.onion:18333 +mjs6pdnd5h4ycmsgruww4crsesqzdw3femdinsi6oghmjld7loycomid.onion:18333 +n23anw4zb7f3paroac626oc2sqy3yn5kjfpcqvb3lvdyx7dzzpovd3id.onion:18333 +n4e6fp6xoyo2glsafjwbaq3wirhldpjw4mskn5lzkm4o5lhh5n5k7uqd.onion:18333 +noyzwtpfqybyhemrmxzd7nf4il5mhsolupp7xtmrjosat7qdmq4xgrad.onion:18333 +oln7ybci53wk4g5n42nipyixvyjxbludsbrfsmhnirb6tk7ovlikd5id.onion:18333 +oobwtn5csi4auevb2ns2b5rrjnxmhlzdmay4zxtzvkj7tayrgwfddiqd.onion:18333 +oond3qmndkbdg76ryyjztbmsmvoj43u64gjhr2nvqriujyteeu43irqd.onion:18333 +oqxivxpit74wsoptsb6kr3k2xeqpzfdozvw4m2wvvujrflxo4ykmzmqd.onion:18333 +oxkyujnjbl6k7kcxactyf4akp3ejtftnbmztk6utxt4zy4fhhtk3x5qd.onion:18333 +p2oitystyas5pxeo262mox6aof4tukybnl7cj7fcwoshqesvfk2yzhad.onion:18333 +pj2rxq2sfbwtsqqcbnfnwkg36d72yce56qmp2sjjmb7hvzpzai3ndead.onion:18333 +pu3zcecujzbsdaogf4qgo3ue67livoza62awlffjnqnribgmvyqfoxad.onion:18333 +q5qox756id5nfdu6ht4dghc35jezls4bgjcdnrds3pwndvdx32zmwlad.onion:18333 +qe2jbe447he6panfvpyqhyntf7346gmuf55bxrmdzggmgwyjsyknhxyd.onion:18333 +qf2taqwtz3pstt73hgbrfvtilgecsc556lizkzk2cisdqi7lrnst5byd.onion:18333 +qiep4hvuovedbbc36hl7nwslwi6ah6uw4nnseyjdtc73cc5rfdauvnad.onion:18333 +qqzemertqrw5qdfakjoay35weu6qshr2l5h4smlnqafi3zqfztx2mhyd.onion:18333 +qzx5f2ig2rk2ssrbopz2zlljq5mkeh3izhhx3t3cepse5qnhvpo2tzid.onion:18333 +r2bdfkchj2z6nrb56alubzmb4twzdncckbcxsvkszjc6mrinibakj3ad.onion:18333 +rfi2hdpjhhknalltbwdvyuhskh5yjs66rqzpy6ley7xtu4kvbeob6fqd.onion:18333 +rra7q7x3euc3ozyealiv3tsywrz34l466faxohmttwtf5dts73musjid.onion:18333 +sf2fkr6hgfezefxaqfqqn5rengrlkvwytrzepsavwotehp2lkvuys6id.onion:18333 +shph2uqcvbe2hc25q3ln73qsche5ddqb4u5tkmgqv73aicrmmkkj4kid.onion:18333 +slpigm5ep4zan3a65bybne67phjiyesbuk5s3bodefuhnx2cfdtit6qd.onion:18333 +sxm6kwrdp6f2ggaozhrl47xuy3es3sgm3ivppmh4xm3hfmetvwbyrcad.onion:18333 +t3z7sscjdbnsydohxcs5nmoxfi35p6zv4jv5jsltsl4datztkefumbid.onion:18333 +tdnctk4lx7jnklojisdczp6h4b4ejtuetyh5cbemzmcno7vvo7whvaad.onion:18333 +trxouvgcwrc3rkewpzvkxbfvpltfwmgl37woiujj4vn63zwhvk4xwbid.onion:18333 +tyo6jvqjh34r2b7i477xlcrwt7rq2fwuwpax5s3nw3tfbtwbox7aakyd.onion:18333 +u3znfxh6yjvclu3l646zzmgclqkmmrrrwtb5urtr4wd6svhrhdgrdxid.onion:18333 +uc25t5mdmnpxn52qib3cps4qyc4ghbntitetzia2vkqaawivyqzdhkad.onion:18333 +ud55gevhzhhcjsaghfzqq7wywxmw7n6syhwsds2uw4j7oj2oh5zxb6qd.onion:18333 +ueyykmnyqk2bnmbgvmqrb4jfbjvpgeew6cuq4gaqe7v2oiyxaubkx4qd.onion:18333 +uw7if6wybpzzwrawp6rdtkcript7vmuo4bptlg4den7t2o733j4hwrid.onion:18333 +vctlwaqgmu53eutz2hewuakcipfgtyljsd7czut4dd62xr3rp6fqezad.onion:18333 +vqnkdmpmecc5kondj32jwbemmruhmd5gkmfngkscetibzozryp4elkad.onion:18333 +w2nnsjp3o5ndh4reorwsudmkjvy3bou5gt7fmusvp3ne2fojgypapmyd.onion:18333 +wnxgjgjgplv5iu4mssyuunycvku4qnqr5t4q6cfdt47k7uwrfifuirad.onion:18333 +wou7tjvuqmql27mqmxbtsrrdxn4dqbti3jbpnklkruqjrztty2jmj4qd.onion:18333 +wpsahjbejxehpz772kzxonj777pejol2akcicduqov2r7ktm2b6l5pid.onion:18333 +wui5m2y5b7cms36ai6shzyqsg6qteejwmxsf26nyms6vcykxbvmh4uad.onion:18333 +wve6wksecq6eeu62phkkrjo5vydreenazzp5c6gttto5ynuyqjevddad.onion:18333 +x4wvxqotarjnii6ue4tfvqt5rxlc27p2c5imkipsu27oprfxstmdjgyd.onion:18333 +xafcyh6mxwebvcsgw4wcbuw7n4v7vbqhcznhwqcpqcu6dww2mjuw4nad.onion:18333 +xmzegggz4kmjmyip2dogvhj3a2m3s4mkimdjdqkwql5n3crqetddabid.onion:18333 +xr4vm6rxolszjw7m73mii35ppnyt7aqp7w53yyg7smcpbo2mg3fazpqd.onion:18333 +xr6damsupgddwwziixaeaogj67hnjdpjtey5bcnhs5ydppul4w5hnjyd.onion:18333 xuhmq42du7dckfophyr2rmf75aqkp3bk6y3wyyc6jxw7jmpp66zlm3id.onion:18333 -zcep44k7unwjm2wxty4ijh2e4fv5zgbrvwlctzyaqnrqhltjfzrtodad.onion:18333 +y4eud6iabao4666vcq3qch6kvg6lg5q5hazzetk4jnwr6vcdyjdv2yyd.onion:18333 +y5h652jz6sgmb4bkcfnfxnj24gnczqf7lhd5lqbvdhf5mpll4gye5kid.onion:18333 +ya6s7ov7myixz3ql23u45hty7moxo3r4d26qainw55z656vtau676xid.onion:18333 +yda7kwpii33j2qpq32ftf6lp22znknswipjwaccvsqj7l337jvfesnid.onion:18333 +ykaknq35wnwbobp4hgsxdd3ve575bsflst6xppo5b4wc44fp3xpqavad.onion:18333 +yqlk3ooxjpjd6u7b4kabe3gidclf25yuqbcpbkwnedmljrmxm3smqrid.onion:18333 +zcsn3j6aswnrf56xj2n5jn4tlwmyoq4benjn5ujcgz46co2y5tm642id.onion:18333 +zefnna2a3ga4ez2nutvypma7my35prw3ycinbqwva7v4pf3aurqhjcyd.onion:18333 +zevf5zwmkq2mvwuwyfavq62hjapkcdfslewiyi7mlrbx7vzidtij3xad.onion:18333 +zhiju2obxifqpjbcm6xtlgjdbof7jhoctvw3x57vhiftstb5hi3gmsqd.onion:18333 +zii3p3plpqt34xxd4mr7ofvvixnipt7ikohgvi3gtjlnzofjj37byiid.onion:18333 +zkqddzui5pkrqvjj2zwsf5kln7stlbmw5pmn6ut46fobvzyv2sn2ryid.onion:18333 +zmvizz7fd5hdue6wt3lwqumd6qwt4ijymmmotfzh75curq3mzjm53hyd.onion:18333 +zmxlrzoxg4fmso6l2xuq5tdxmlyakdqellzujh3a23iuzg4zlatnogqd.onion:18333 +zv5egkfmdpunhdm3whdaxgzpiapbkerfqd24juq647hmzhec7q7uxlid.onion:18333 diff --git a/contrib/seeds/nodes_testnet4.txt b/contrib/seeds/nodes_testnet4.txt new file mode 100644 index 0000000000..0be4b9ee3d --- /dev/null +++ b/contrib/seeds/nodes_testnet4.txt @@ -0,0 +1,9 @@ +18.189.156.102:48333 # AS16509 +18.201.207.55:48333 # AS16509 +51.158.248.8:48333 # AS12876 +57.128.176.163:48333 # AS8220 +82.67.102.15:48333 # AS12322 +88.99.248.50:48333 # AS24940 +95.217.73.162:48333 # AS24940 +103.99.171.212:48333 # AS54415 +103.165.192.210:48333 # AS54415 diff --git a/contrib/signet/README.md b/contrib/signet/README.md index 706b296c54..5fcd8944e6 100644 --- a/contrib/signet/README.md +++ b/contrib/signet/README.md @@ -23,9 +23,8 @@ miner You will first need to pick a difficulty target. Since signet chains are primarily protected by a signature rather than proof of work, there is no need to spend as much energy as possible mining, however you may wish to choose to spend more time than the absolute minimum. The calibrate subcommand can be used to pick a target appropriate for your hardware, eg: - cd src/ - MINER="../contrib/signet/miner" - GRIND="./bitcoin-util grind" + MINER="./contrib/signet/miner" + GRIND="./build/src/bitcoin-util grind" $MINER calibrate --grind-cmd="$GRIND" nbits=1e00f403 for 25s average mining time @@ -33,7 +32,7 @@ It defaults to estimating an nbits value resulting in 25s average time to find a To mine the first block in your custom chain, you can run: - CLI="./bitcoin-cli -conf=mysignet.conf" + CLI="./build/src/bitcoin-cli -conf=mysignet.conf" ADDR=$($CLI -signet getnewaddress) NBITS=1e00f403 $MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=$NBITS diff --git a/contrib/signet/miner b/contrib/signet/miner index 7b7b3feb39..3c90fe96a1 100755 --- a/contrib/signet/miner +++ b/contrib/signet/miner @@ -21,7 +21,7 @@ sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL) from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402 from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex # noqa: E402 from test_framework.psbt import PSBT, PSBTMap, PSBT_GLOBAL_UNSIGNED_TX, PSBT_IN_FINAL_SCRIPTSIG, PSBT_IN_FINAL_SCRIPTWITNESS, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_SIGHASH_TYPE # noqa: E402 -from test_framework.script import CScriptOp # noqa: E402 +from test_framework.script import CScript, CScriptOp # noqa: E402 logging.basicConfig( format='%(asctime)s %(levelname)s %(message)s', @@ -32,12 +32,6 @@ SIGNET_HEADER = b"\xec\xc7\xda\xa2" PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed RE_MULTIMINER = re.compile(r"^(\d+)(-(\d+))?/(\d+)$") -def create_coinbase(height, value, spk): - cb = CTransaction() - cb.vin = [CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff)] - cb.vout = [CTxOut(value, spk)] - return cb - def signet_txs(block, challenge): # assumes signet solution has not been added yet so does not need # to be removed @@ -58,32 +52,21 @@ def signet_txs(block, challenge): sd += block.nTime.to_bytes(4, "little") to_spend = CTransaction() - to_spend.nVersion = 0 + to_spend.version = 0 to_spend.nLockTime = 0 to_spend.vin = [CTxIn(COutPoint(0, 0xFFFFFFFF), b"\x00" + CScriptOp.encode_op_pushdata(sd), 0)] to_spend.vout = [CTxOut(0, challenge)] to_spend.rehash() spend = CTransaction() - spend.nVersion = 0 + spend.version = 0 spend.nLockTime = 0 spend.vin = [CTxIn(COutPoint(to_spend.sha256, 0), b"", 0)] spend.vout = [CTxOut(0, b"\x6a")] return spend, to_spend -def do_createpsbt(block, signme, spendme): - psbt = PSBT() - psbt.g = PSBTMap( {PSBT_GLOBAL_UNSIGNED_TX: signme.serialize(), - PSBT_SIGNET_BLOCK: block.serialize() - } ) - psbt.i = [ PSBTMap( {PSBT_IN_NON_WITNESS_UTXO: spendme.serialize(), - PSBT_IN_SIGHASH_TYPE: bytes([1,0,0,0])}) - ] - psbt.o = [ PSBTMap() ] - return psbt.to_base64() - -def do_decode_psbt(b64psbt): +def decode_psbt(b64psbt): psbt = PSBT.from_base64(b64psbt) assert len(psbt.tx.vin) == 1 @@ -110,11 +93,17 @@ def finish_block(block, signet_solution, grind_cmd): block.rehash() return block -def generate_psbt(tmpl, reward_spk, *, blocktime=None): +def generate_psbt(tmpl, reward_spk, *, blocktime=None, poolid=None): signet_spk = tmpl["signet_challenge"] signet_spk_bin = bytes.fromhex(signet_spk) - cbtx = create_coinbase(height=tmpl["height"], value=tmpl["coinbasevalue"], spk=reward_spk) + scriptSig = script_BIP34_coinbase_height(tmpl["height"]) + if poolid is not None: + scriptSig = CScript(b"" + scriptSig + CScriptOp.encode_op_pushdata(poolid)) + + cbtx = CTransaction() + cbtx.vin = [CTxIn(COutPoint(0, 0xffffffff), scriptSig, 0xffffffff)] + cbtx.vout = [CTxOut(tmpl["coinbasevalue"], reward_spk)] cbtx.vin[0].nSequence = 2**32-2 cbtx.rehash() @@ -137,29 +126,23 @@ def generate_psbt(tmpl, reward_spk, *, blocktime=None): signme, spendme = signet_txs(block, signet_spk_bin) - return do_createpsbt(block, signme, spendme) - -def get_reward_address(args, height): - if args.address is not None: - return args.address - - if '*' not in args.descriptor: - addr = json.loads(args.bcli("deriveaddresses", args.descriptor))[0] - args.address = addr - return addr - - remove = [k for k in args.derived_addresses.keys() if k+20 <= height] - for k in remove: - del args.derived_addresses[k] - - addr = args.derived_addresses.get(height, None) - if addr is None: - addrs = json.loads(args.bcli("deriveaddresses", args.descriptor, "[%d,%d]" % (height, height+20))) - addr = addrs[0] - for k, a in enumerate(addrs): - args.derived_addresses[height+k] = a + psbt = PSBT() + psbt.g = PSBTMap( {PSBT_GLOBAL_UNSIGNED_TX: signme.serialize(), + PSBT_SIGNET_BLOCK: block.serialize() + } ) + psbt.i = [ PSBTMap( {PSBT_IN_NON_WITNESS_UTXO: spendme.serialize(), + PSBT_IN_SIGHASH_TYPE: bytes([1,0,0,0])}) + ] + psbt.o = [ PSBTMap() ] + return psbt.to_base64() - return addr +def get_poolid(args): + if args.poolid is not None: + return args.poolid.encode('utf8') + elif args.poolnum is not None: + return b"/signet:%d/" % (args.poolnum) + else: + return None def get_reward_addr_spk(args, height): assert args.address is not None or args.descriptor is not None @@ -167,7 +150,20 @@ def get_reward_addr_spk(args, height): if hasattr(args, "reward_spk"): return args.address, args.reward_spk - reward_addr = get_reward_address(args, height) + if args.address is not None: + reward_addr = args.address + elif '*' not in args.descriptor: + reward_addr = args.address = json.loads(args.bcli("deriveaddresses", args.descriptor))[0] + else: + remove = [k for k in args.derived_addresses.keys() if k+20 <= height] + for k in remove: + del args.derived_addresses[k] + if height not in args.derived_addresses: + addrs = json.loads(args.bcli("deriveaddresses", args.descriptor, "[%d,%d]" % (height, height+20))) + for k, a in enumerate(addrs): + args.derived_addresses[height+k] = a + reward_addr = args.derived_addresses[height] + reward_spk = bytes.fromhex(json.loads(args.bcli("getaddressinfo", reward_addr))["scriptPubKey"]) if args.address is not None: # will always be the same, so cache @@ -176,13 +172,14 @@ def get_reward_addr_spk(args, height): return reward_addr, reward_spk def do_genpsbt(args): + poolid = get_poolid(args) tmpl = json.load(sys.stdin) _, reward_spk = get_reward_addr_spk(args, tmpl["height"]) - psbt = generate_psbt(tmpl, reward_spk) + psbt = generate_psbt(tmpl, reward_spk, poolid=poolid) print(psbt) def do_solvepsbt(args): - block, signet_solution = do_decode_psbt(sys.stdin.read()) + block, signet_solution = decode_psbt(sys.stdin.read()) block = finish_block(block, signet_solution, args.grind_cmd) print(block.serialize().hex()) @@ -225,44 +222,122 @@ def seconds_to_hms(s): out = "-" + out return out -def next_block_delta(last_nbits, last_hash, ultimate_target, do_poisson, max_interval): - # strategy: - # 1) work out how far off our desired target we are - # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period - # 3) use that to work out the desired average interval in this retarget period - # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by - # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes - +class Generate: INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug - current_target = nbits_to_target(last_nbits) - retarget_factor = ultimate_target / current_target - retarget_factor = max(0.25, min(retarget_factor, 4.0)) - avg_interval = INTERVAL * retarget_factor + def __init__(self, multiminer=None, ultimate_target=None, poisson=False, max_interval=1800, + standby_delay=0, backup_delay=0, set_block_time=None, + poolid=None): + if multiminer is None: + multiminer = (0, 1, 1) + (self.multi_low, self.multi_high, self.multi_period) = multiminer + self.ultimate_target = ultimate_target + self.poisson = poisson + self.max_interval = max_interval + self.standby_delay = standby_delay + self.backup_delay = backup_delay + self.set_block_time = set_block_time + self.poolid = poolid + + def next_block_delta(self, last_nbits, last_hash): + # strategy: + # 1) work out how far off our desired target we are + # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period + # 3) use that to work out the desired average interval in this retarget period + # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by + # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes + + current_target = nbits_to_target(last_nbits) + retarget_factor = self.ultimate_target / current_target + retarget_factor = max(0.25, min(retarget_factor, 4.0)) + + avg_interval = self.INTERVAL * retarget_factor + + if self.poisson: + det_rand = int(last_hash[-8:], 16) * 2**-32 + this_interval_variance = -math.log1p(-det_rand) + else: + this_interval_variance = 1 - if do_poisson: - det_rand = int(last_hash[-8:], 16) * 2**-32 - this_interval_variance = -math.log1p(-det_rand) - else: - this_interval_variance = 1 + this_interval = avg_interval * this_interval_variance + this_interval = max(1, min(this_interval, self.max_interval)) + + return this_interval + + def next_block_is_mine(self, last_hash): + det_rand = int(last_hash[-16:-8], 16) + return self.multi_low <= (det_rand % self.multi_period) < self.multi_high + + def next_block_time(self, now, bestheader, is_first_block): + if self.set_block_time is not None: + logging.debug("Setting start time to %d", self.set_block_time) + self.mine_time = self.set_block_time + self.action_time = now + self.is_mine = True + elif bestheader["height"] == 0: + time_delta = self.INTERVAL * 100 # plenty of time to mine 100 blocks + logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60)) + self.mine_time = now - time_delta + self.action_time = now + self.is_mine = True + else: + time_delta = self.next_block_delta(int(bestheader["bits"], 16), bestheader["hash"]) + self.mine_time = bestheader["time"] + time_delta + + self.is_mine = self.next_block_is_mine(bestheader["hash"]) + + self.action_time = self.mine_time + if not self.is_mine: + self.action_time += self.backup_delay - this_interval = avg_interval * this_interval_variance - this_interval = max(1, min(this_interval, max_interval)) + if self.standby_delay > 0: + self.action_time += self.standby_delay + elif is_first_block: + # for non-standby, always mine immediately on startup, + # even if the next block shouldn't be ours + self.action_time = now - return this_interval + # don't want fractional times so round down + self.mine_time = int(self.mine_time) + self.action_time = int(self.action_time) -def next_block_is_mine(last_hash, my_blocks): - det_rand = int(last_hash[-16:-8], 16) - return my_blocks[0] <= (det_rand % my_blocks[2]) < my_blocks[1] + # can't mine a block 2h in the future; 1h55m for some safety + self.action_time = max(self.action_time, self.mine_time - 6900) + + def gbt(self, bcli, bestblockhash, now): + tmpl = json.loads(bcli("getblocktemplate", '{"rules":["signet","segwit"]}')) + if tmpl["previousblockhash"] != bestblockhash: + logging.warning("GBT based off unexpected block (%s not %s), retrying", tmpl["previousblockhash"], bci["bestblockhash"]) + time.sleep(1) + return None + + if tmpl["mintime"] > self.mine_time: + logging.info("Updating block time from %d to %d", self.mine_time, tmpl["mintime"]) + self.mine_time = tmpl["mintime"] + if self.mine_time > now: + logging.error("GBT mintime is in the future: %d is %d seconds later than %d", self.mine_time, (self.mine_time-now), now) + return None + + return tmpl + + def mine(self, bcli, grind_cmd, tmpl, reward_spk): + psbt = generate_psbt(tmpl, reward_spk, blocktime=self.mine_time, poolid=self.poolid) + input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8') + psbt_signed = json.loads(bcli("-stdin", "walletprocesspsbt", input=input_stream)) + if not psbt_signed.get("complete",False): + logging.debug("Generated PSBT: %s" % (psbt,)) + sys.stderr.write("PSBT signing failed\n") + return None + block, signet_solution = decode_psbt(psbt_signed["psbt"]) + return finish_block(block, signet_solution, grind_cmd) def do_generate(args): - if args.max_blocks is not None: - if args.ongoing: - logging.error("Cannot specify both --ongoing and --max-blocks") - return 1 + if args.set_block_time is not None: + max_blocks = 1 + elif args.max_blocks is not None: if args.max_blocks < 1: - logging.error("N must be a positive integer") + logging.error("--max_blocks must specify a positive integer") return 1 max_blocks = args.max_blocks elif args.ongoing: @@ -270,17 +345,11 @@ def do_generate(args): else: max_blocks = 1 - if args.set_block_time is not None and max_blocks != 1: - logging.error("Cannot specify --ongoing or --max-blocks > 1 when using --set-block-time") - return 1 if args.set_block_time is not None and args.set_block_time < 0: args.set_block_time = time.time() logging.info("Treating negative block time as current time (%d)" % (args.set_block_time)) if args.min_nbits: - if args.nbits is not None: - logging.error("Cannot specify --nbits and --min-nbits") - return 1 args.nbits = "1e0377ae" logging.info("Using nbits=%s" % (args.nbits)) @@ -312,8 +381,13 @@ def do_generate(args): logging.error("--max-interval must be at least 960 (16 minutes)") return 1 + poolid = get_poolid(args) + ultimate_target = nbits_to_target(int(args.nbits,16)) + gen = Generate(multiminer=my_blocks, ultimate_target=ultimate_target, poisson=args.poisson, max_interval=args.max_interval, + standby_delay=args.standby_delay, backup_delay=args.backup_delay, set_block_time=args.set_block_time, poolid=poolid) + mined_blocks = 0 bestheader = {"hash": None} lastheader = None @@ -328,104 +402,55 @@ def do_generate(args): if lastheader is None: lastheader = bestheader["hash"] elif bestheader["hash"] != lastheader: - next_delta = next_block_delta(int(bestheader["bits"], 16), bestheader["hash"], ultimate_target, args.poisson, args.max_interval) + next_delta = gen.next_block_delta(int(bestheader["bits"], 16), bestheader["hash"]) next_delta += bestheader["time"] - time.time() - next_is_mine = next_block_is_mine(bestheader["hash"], my_blocks) + next_is_mine = gen.next_block_is_mine(bestheader["hash"]) logging.info("Received new block at height %d; next in %s (%s)", bestheader["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup")) lastheader = bestheader["hash"] # when is the next block due to be mined? now = time.time() - if args.set_block_time is not None: - logging.debug("Setting start time to %d", args.set_block_time) - mine_time = args.set_block_time - action_time = now - is_mine = True - elif bestheader["height"] == 0: - time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson, args.max_interval) - time_delta *= 100 # 100 blocks - logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60)) - mine_time = now - time_delta - action_time = now - is_mine = True - else: - time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson, args.max_interval) - mine_time = bestheader["time"] + time_delta - - is_mine = next_block_is_mine(bci["bestblockhash"], my_blocks) - - action_time = mine_time - if not is_mine: - action_time += args.backup_delay - - if args.standby_delay > 0: - action_time += args.standby_delay - elif mined_blocks == 0: - # for non-standby, always mine immediately on startup, - # even if the next block shouldn't be ours - action_time = now - - # don't want fractional times so round down - mine_time = int(mine_time) - action_time = int(action_time) - - # can't mine a block 2h in the future; 1h55m for some safety - action_time = max(action_time, mine_time - 6900) + gen.next_block_time(now, bestheader, (mined_blocks == 0)) # ready to go? otherwise sleep and check for new block - if now < action_time: - sleep_for = min(action_time - now, 60) - if mine_time < now: + if now < gen.action_time: + sleep_for = min(gen.action_time - now, 60) + if gen.mine_time < now: # someone else might have mined the block, # so check frequently, so we don't end up late # mining the next block if it's ours sleep_for = min(20, sleep_for) - minestr = "mine" if is_mine else "backup" - logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(mine_time - now), minestr)) + minestr = "mine" if gen.is_mine else "backup" + logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(gen.mine_time - now), minestr)) time.sleep(sleep_for) continue # gbt - tmpl = json.loads(args.bcli("getblocktemplate", '{"rules":["signet","segwit"]}')) - if tmpl["previousblockhash"] != bci["bestblockhash"]: - logging.warning("GBT based off unexpected block (%s not %s), retrying", tmpl["previousblockhash"], bci["bestblockhash"]) - time.sleep(1) + tmpl = gen.gbt(args.bcli, bci["bestblockhash"], now) + if tmpl is None: continue logging.debug("GBT template: %s", tmpl) - if tmpl["mintime"] > mine_time: - logging.info("Updating block time from %d to %d", mine_time, tmpl["mintime"]) - mine_time = tmpl["mintime"] - if mine_time > now: - logging.error("GBT mintime is in the future: %d is %d seconds later than %d", mine_time, (mine_time-now), now) - return 1 - # address for reward reward_addr, reward_spk = get_reward_addr_spk(args, tmpl["height"]) # mine block - logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(mine_time-bestheader["time"]), mine_time, is_mine) + logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(gen.mine_time-bestheader["time"]), gen.mine_time, gen.is_mine) mined_blocks += 1 - psbt = generate_psbt(tmpl, reward_spk, blocktime=mine_time) - input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8') - psbt_signed = json.loads(args.bcli("-stdin", "walletprocesspsbt", input=input_stream)) - if not psbt_signed.get("complete",False): - logging.debug("Generated PSBT: %s" % (psbt,)) - sys.stderr.write("PSBT signing failed\n") + block = gen.mine(args.bcli, args.grind_cmd, tmpl, reward_spk) + if block is None: return 1 - block, signet_solution = do_decode_psbt(psbt_signed["psbt"]) - block = finish_block(block, signet_solution, args.grind_cmd) # submit block r = args.bcli("-stdin", "submitblock", input=block.serialize().hex().encode('utf8')) # report - bstr = "block" if is_mine else "backup block" + bstr = "block" if gen.is_mine else "backup block" - next_delta = next_block_delta(block.nBits, block.hash, ultimate_target, args.poisson, args.max_interval) + next_delta = gen.next_block_delta(block.nBits, block.hash) next_delta += block.nTime - time.time() - next_is_mine = next_block_is_mine(block.hash, my_blocks) + next_is_mine = gen.next_block_is_mine(block.hash) logging.debug("Block hash %s payout to %s", block.hash, reward_addr) logging.info("Mined %s at height %d; next in %s (%s)", bstr, tmpl["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup")) @@ -492,11 +517,13 @@ def main(): generate = cmds.add_parser("generate", help="Mine blocks") generate.set_defaults(fn=do_generate) - generate.add_argument("--ongoing", action="store_true", help="Keep mining blocks") - generate.add_argument("--max-blocks", default=None, type=int, help="Max blocks to mine (default=1)") - generate.add_argument("--set-block-time", default=None, type=int, help="Set block time (unix timestamp)") - generate.add_argument("--nbits", default=None, type=str, help="Target nBits (specify difficulty)") - generate.add_argument("--min-nbits", action="store_true", help="Target minimum nBits (use min difficulty)") + howmany = generate.add_mutually_exclusive_group() + howmany.add_argument("--ongoing", action="store_true", help="Keep mining blocks") + howmany.add_argument("--max-blocks", default=None, type=int, help="Max blocks to mine (default=1)") + howmany.add_argument("--set-block-time", default=None, type=int, help="Set block time (unix timestamp); implies --max-blocks=1") + nbit_target = generate.add_mutually_exclusive_group() + nbit_target.add_argument("--nbits", default=None, type=str, help="Target nBits (specify difficulty)") + nbit_target.add_argument("--min-nbits", action="store_true", help="Target minimum nBits (use min difficulty)") generate.add_argument("--poisson", action="store_true", help="Simulate randomised block times") generate.add_argument("--multiminer", default=None, type=str, help="Specify which set of blocks to mine (eg: 1-40/100 for the first 40%%, 2/3 for the second 3rd)") generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)") @@ -505,12 +532,17 @@ def main(): calibrate = cmds.add_parser("calibrate", help="Calibrate difficulty") calibrate.set_defaults(fn=do_calibrate) - calibrate.add_argument("--nbits", type=str, default=None) - calibrate.add_argument("--seconds", type=int, default=None) + calibrate_by = calibrate.add_mutually_exclusive_group() + calibrate_by.add_argument("--nbits", type=str, default=None) + calibrate_by.add_argument("--seconds", type=int, default=None) for sp in [genpsbt, generate]: - sp.add_argument("--address", default=None, type=str, help="Address for block reward payment") - sp.add_argument("--descriptor", default=None, type=str, help="Descriptor for block reward payment") + payto = sp.add_mutually_exclusive_group(required=True) + payto.add_argument("--address", default=None, type=str, help="Address for block reward payment") + payto.add_argument("--descriptor", default=None, type=str, help="Descriptor for block reward payment") + pool = sp.add_mutually_exclusive_group() + pool.add_argument("--poolnum", default=None, type=int, help="Identify blocks that you mine") + pool.add_argument("--poolid", default=None, type=str, help="Identify blocks that you mine (eg: /signet:1/)") for sp in [solvepsbt, generate, calibrate]: sp.add_argument("--grind-cmd", default=None, type=str, required=(sp==calibrate), help="Command to grind a block header for proof-of-work") @@ -520,12 +552,6 @@ def main(): args.bcli = lambda *a, input=b"", **kwargs: bitcoin_cli(args.cli.split(" "), list(a), input=input, **kwargs) if hasattr(args, "address") and hasattr(args, "descriptor"): - if args.address is None and args.descriptor is None: - sys.stderr.write("Must specify --address or --descriptor\n") - return 1 - elif args.address is not None and args.descriptor is not None: - sys.stderr.write("Only specify one of --address or --descriptor\n") - return 1 args.derived_addresses = {} if args.debug: diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md index 206bec1647..c471770a7d 100644 --- a/contrib/tracing/README.md +++ b/contrib/tracing/README.md @@ -82,7 +82,7 @@ about the connection. Peers can be selected individually to view recent P2P messages. ``` -$ python3 contrib/tracing/p2p_monitor.py ./src/bitcoind +$ python3 contrib/tracing/p2p_monitor.py ./build/src/bitcoind ``` Lists selectable peers and traffic and connection information. @@ -150,7 +150,7 @@ lost. BCC prints: `Possibly lost 2 samples` on lost messages. ``` -$ python3 contrib/tracing/log_raw_p2p_msgs.py ./src/bitcoind +$ python3 contrib/tracing/log_raw_p2p_msgs.py ./build/src/bitcoind ``` ``` @@ -188,7 +188,7 @@ In a different terminal, starting Bitcoin Core in SigNet mode and with re-indexing enabled. ``` -$ ./src/bitcoind -signet -reindex +$ ./build/src/bitcoind -signet -reindex ``` This produces the following output. @@ -241,7 +241,7 @@ A BCC Python script to log the UTXO cache flushes. Based on the `utxocache:flush` tracepoint. ```bash -$ python3 contrib/tracing/log_utxocache_flush.py ./src/bitcoind +$ python3 contrib/tracing/log_utxocache_flush.py ./build/src/bitcoind ``` ``` @@ -300,7 +300,7 @@ comprising a timestamp along with all event data available via the event's tracepoint. ```console -$ python3 contrib/tracing/mempool_monitor.py ./src/bitcoind +$ python3 contrib/tracing/mempool_monitor.py ./build/src/bitcoind ``` ``` diff --git a/contrib/tracing/connectblock_benchmark.bt b/contrib/tracing/connectblock_benchmark.bt index 6e7a98ef07..de112af639 100755 --- a/contrib/tracing/connectblock_benchmark.bt +++ b/contrib/tracing/connectblock_benchmark.bt @@ -16,7 +16,7 @@ This script requires a 'bitcoind' binary compiled with eBPF support and the 'validation:block_connected' USDT. By default, it's assumed that 'bitcoind' is - located in './src/bitcoind'. This can be modified in the script below. + located in './build/src/bitcoind'. This can be modified in the script below. EXAMPLES: @@ -67,7 +67,7 @@ BEGIN connected block is between the start and end height (or the end height is unset). */ -usdt:./src/bitcoind:validation:block_connected /arg1 >= $1 && (arg1 <= $2 || $2 == 0 )/ +usdt:./build/src/bitcoind:validation:block_connected /arg1 >= $1 && (arg1 <= $2 || $2 == 0 )/ { $height = arg1; $transactions = arg2; @@ -82,7 +82,7 @@ usdt:./src/bitcoind:validation:block_connected /arg1 >= $1 && (arg1 <= $2 || $2 @inputs = @inputs + $inputs; @sigops = @sigops + $sigops; - @durations = hist($duration / 1000); + @durations = hist($duration / 1e6); if ($height == $1 && $height != 0) { @start = nsecs; @@ -92,7 +92,7 @@ usdt:./src/bitcoind:validation:block_connected /arg1 >= $1 && (arg1 <= $2 || $2 if ($2 > 0 && $height >= $2) { @end = nsecs; $duration = @end - @start; - printf("\nTook %d ms to connect the blocks between height %d and %d.\n", $duration / 1000000, $1, $2); + printf("\nTook %d ms to connect the blocks between height %d and %d.\n", $duration / 1e9, $1, $2); exit(); } } @@ -102,7 +102,7 @@ usdt:./src/bitcoind:validation:block_connected /arg1 >= $1 && (arg1 <= $2 || $2 blocks where the time it took to connect the block is above the <logging threshold in ms>. */ -usdt:./src/bitcoind:validation:block_connected / (uint64) arg5 / 1000> $3 / +usdt:./build/src/bitcoind:validation:block_connected / (uint64) arg5 / 1e6 > $3 / { $hash = arg0; $height = (int32) arg1; @@ -120,7 +120,7 @@ usdt:./src/bitcoind:validation:block_connected / (uint64) arg5 / 1000> $3 / printf("%02x", $b); $p -= 1; } - printf(") %4d tx %5d ins %5d sigops took %4d ms\n", $transactions, $inputs, $sigops, (uint64) $duration / 1000); + printf(") %4d tx %5d ins %5d sigops took %4d ms\n", $transactions, $inputs, $sigops, (uint64) $duration / 1e6); } diff --git a/contrib/tracing/log_p2p_traffic.bt b/contrib/tracing/log_p2p_traffic.bt index f62956aa5e..89e5b777be 100755 --- a/contrib/tracing/log_p2p_traffic.bt +++ b/contrib/tracing/log_p2p_traffic.bt @@ -5,7 +5,7 @@ BEGIN printf("Logging P2P traffic\n") } -usdt:./src/bitcoind:net:inbound_message +usdt:./build/src/bitcoind:net:inbound_message { $peer_id = (int64) arg0; $peer_addr = str(arg1); @@ -15,7 +15,7 @@ usdt:./src/bitcoind:net:inbound_message printf("inbound '%s' msg from peer %d (%s, %s) with %d bytes\n", $msg_type, $peer_id, $peer_type, $peer_addr, $msg_len); } -usdt:./src/bitcoind:net:outbound_message +usdt:./build/src/bitcoind:net:outbound_message { $peer_id = (int64) arg0; $peer_addr = str(arg1); diff --git a/contrib/tracing/log_utxos.bt b/contrib/tracing/log_utxos.bt index 54d5010f82..a04f221157 100755 --- a/contrib/tracing/log_utxos.bt +++ b/contrib/tracing/log_utxos.bt @@ -8,7 +8,7 @@ This script requires a 'bitcoind' binary compiled with eBPF support and the 'utxocache' tracepoints. By default, it's assumed that 'bitcoind' is - located in './src/bitcoind'. This can be modified in the script below. + located in './build/src/bitcoind'. This can be modified in the script below. NOTE: requires bpftrace v0.12.0 or above. */ @@ -22,7 +22,7 @@ BEGIN /* Attaches to the 'utxocache:add' tracepoint and prints additions to the UTXO set cache. */ -usdt:./src/bitcoind:utxocache:add +usdt:./build/src/bitcoind:utxocache:add { $txid = arg0; $index = (uint32)arg1; @@ -44,7 +44,7 @@ usdt:./src/bitcoind:utxocache:add /* Attaches to the 'utxocache:spent' tracepoint and prints spents from the UTXO set cache. */ -usdt:./src/bitcoind:utxocache:spent +usdt:./build/src/bitcoind:utxocache:spent { $txid = arg0; $index = (uint32)arg1; @@ -66,7 +66,7 @@ usdt:./src/bitcoind:utxocache:spent /* Attaches to the 'utxocache:uncache' tracepoint and uncache UTXOs from the UTXO set cache. */ -usdt:./src/bitcoind:utxocache:uncache +usdt:./build/src/bitcoind:utxocache:uncache { $txid = arg0; $index = (uint32)arg1; diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp index c537f9e7ec..1ec5b8d20d 100644 --- a/contrib/valgrind.supp +++ b/contrib/valgrind.supp @@ -2,14 +2,14 @@ # dependencies that cannot be fixed in-tree. # # Example use: -# $ valgrind --suppressions=contrib/valgrind.supp src/test/test_bitcoin +# $ valgrind --suppressions=contrib/valgrind.supp build/src/test/test_bitcoin # $ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \ -# --show-leak-kinds=all src/test/test_bitcoin +# --show-leak-kinds=all build/src/test/test_bitcoin # # To create suppressions for found issues, use the --gen-suppressions=all option: # $ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \ # --show-leak-kinds=all --gen-suppressions=all --show-reachable=yes \ -# --error-limit=no src/test/test_bitcoin +# --error-limit=no build/src/test/test_bitcoin # # Note that suppressions may depend on OS and/or library versions. # Tested on: diff --git a/contrib/verify-binaries/README.md b/contrib/verify-binaries/README.md index 04d683e69b..0f3e16a5bc 100644 --- a/contrib/verify-binaries/README.md +++ b/contrib/verify-binaries/README.md @@ -50,6 +50,7 @@ Get JSON output and don't prompt for user input (no auto key import): ```sh ./contrib/verify-binaries/verify.py --json pub 22.0-x86 +./contrib/verify-binaries/verify.py --json pub 23.0-rc5-linux-gnu ``` Rely only on local GPG state and manually specified keys, while requiring a @@ -57,14 +58,15 @@ threshold of at least 10 trusted signatures: ```sh ./contrib/verify-binaries/verify.py \ --trusted-keys 74E2DEF5D77260B98BC19438099BAD163C70FBFA,9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C \ - --min-good-sigs 10 pub 22.0-x86 + --min-good-sigs 10 pub 22.0-linux ``` -If you only want to download the binaries for a certain platform, add the corresponding suffix, e.g.: +If you only want to download the binaries for a certain architecture and/or platform, add the corresponding suffix, e.g.: ```sh -./contrib/verify-binaries/verify.py pub 24.0.1-darwin -./contrib/verify-binaries/verify.py pub 23.1-rc1-win64 +./contrib/verify-binaries/verify.py pub 25.2-x86_64-linux +./contrib/verify-binaries/verify.py pub 24.1-rc1-darwin +./contrib/verify-binaries/verify.py pub 27.0-win64-setup.exe ``` If you do not want to keep the downloaded binaries, specify the cleanup option. diff --git a/contrib/verify-binaries/test.py b/contrib/verify-binaries/test.py index 22d718ece3..875606ec22 100755 --- a/contrib/verify-binaries/test.py +++ b/contrib/verify-binaries/test.py @@ -12,6 +12,21 @@ def main(): expect_code(run_verify("", "pub", '0.32.awefa.12f9h'), 11, "Malformed version should fail") expect_code(run_verify('--min-good-sigs 20', "pub", "22.0"), 9, "--min-good-sigs 20 should fail") + print("- testing verification (22.0-x86_64-linux-gnu.tar.gz)", flush=True) + _220_x86_64_linux_gnu = run_verify("--json", "pub", "22.0-x86_64-linux-gnu.tar.gz") + try: + result = json.loads(_220_x86_64_linux_gnu.stdout.decode()) + except Exception: + print("failed on 22.0-x86_64-linux-gnu.tar.gz --json:") + print_process_failure(_220_x86_64_linux_gnu) + raise + + expect_code(_220_x86_64_linux_gnu, 0, "22.0-x86_64-linux-gnu.tar.gz should succeed") + v = result['verified_binaries'] + assert result['good_trusted_sigs'] + assert len(v) == 1 + assert v['bitcoin-22.0-x86_64-linux-gnu.tar.gz'] == '59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16' + print("- testing verification (22.0)", flush=True) _220 = run_verify("--json", "pub", "22.0") try: diff --git a/contrib/verify-binaries/verify.py b/contrib/verify-binaries/verify.py index 12e6e10d8a..6c07b36c9d 100755 --- a/contrib/verify-binaries/verify.py +++ b/contrib/verify-binaries/verify.py @@ -97,23 +97,17 @@ def bool_from_env(key, default=False) -> bool: VERSION_FORMAT = "<major>.<minor>[.<patch>][-rc[0-9]][-platform]" -VERSION_EXAMPLE = "22.0-x86_64 or 23.1-rc1-darwin" +VERSION_EXAMPLE = "22.0 or 23.1-rc1-darwin.dmg or 27.0-x86_64-linux-gnu" def parse_version_string(version_str): - parts = version_str.split('-') - version_base = parts[0] - version_rc = "" - version_os = "" - if len(parts) == 2: # "<version>-rcN" or "version-platform" - if "rc" in parts[1]: - version_rc = parts[1] - else: - version_os = parts[1] - elif len(parts) == 3: # "<version>-rcN-platform" - version_rc = parts[1] - version_os = parts[2] + # "<version>[-rcN][-platform]" + version_base, _, platform = version_str.partition('-') + rc = "" + if platform.startswith("rc"): # "<version>-rcN[-platform]" + rc, _, platform = platform.partition('-') + # else "<version>" or "<version>-platform" - return version_base, version_rc, version_os + return version_base, rc, platform def download_with_wget(remote_file, local_file): @@ -514,7 +508,9 @@ def verify_published_handler(args: argparse.Namespace) -> ReturnCode: # Extract hashes and filenames hashes_to_verify = parse_sums_file(SUMS_FILENAME, [os_filter]) if not hashes_to_verify: - log.error("no files matched the platform specified") + available_versions = ["-".join(line[1].split("-")[2:]) for line in parse_sums_file(SUMS_FILENAME, [])] + closest_match = difflib.get_close_matches(os_filter, available_versions, cutoff=0, n=1)[0] + log.error(f"No files matched the platform specified. Did you mean: {closest_match}") return ReturnCode.NO_BINARIES_MATCH # remove binaries that are known not to be hosted by bitcoincore.org diff --git a/depends/.gitignore b/depends/.gitignore index 19c506ce54..be6280f599 100644 --- a/depends/.gitignore +++ b/depends/.gitignore @@ -2,7 +2,6 @@ SDKs/ work/ built/ sources/ -config.site x86_64* i686* mips* diff --git a/depends/Makefile b/depends/Makefile index fee426d8db..f1dc300b7a 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -42,7 +42,6 @@ NO_WALLET ?= NO_ZMQ ?= NO_UPNP ?= NO_USDT ?= -NO_NATPMP ?= MULTIPROCESS ?= LTO ?= NO_HARDEN ?= @@ -159,13 +158,12 @@ sqlite_packages_$(NO_SQLITE) = $(sqlite_packages) wallet_packages_$(NO_WALLET) = $(bdb_packages_) $(sqlite_packages_) upnp_packages_$(NO_UPNP) = $(upnp_packages) -natpmp_packages_$(NO_NATPMP) = $(natpmp_packages) zmq_packages_$(NO_ZMQ) = $(zmq_packages) multiprocess_packages_$(MULTIPROCESS) = $(multiprocess_packages) usdt_packages_$(NO_USDT) = $(usdt_$(host_os)_packages) -packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(boost_packages_) $(libevent_packages_) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_) $(usdt_packages_) +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(boost_packages_) $(libevent_packages_) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(usdt_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) ifneq ($(zmq_packages_),) @@ -181,11 +179,9 @@ all_packages = $(packages) $(native_packages) meta_depends = Makefile config.guess config.sub funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk -$(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain) - include funcs.mk -final_build_id_long+=$(shell $(build_SHA256SUM) config.site.in) +final_build_id_long+=$(shell $(build_SHA256SUM) toolchain.cmake.in) final_build_id+=$(shell echo -n "$(final_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)) $(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages) rm -rf $(@D) @@ -193,65 +189,55 @@ $(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages) echo copying packages: $^ echo to: $(@D) cd $(@D); $(foreach package,$^, $(build_TAR) xf $($(package)_cached); ) + echo To build Bitcoin Core with these packages, pass \'--toolchain $(@D)/toolchain.cmake\' to the first CMake invocation. touch $@ -# $PATH is not preserved between ./configure and make by convention. Its -# modification and overriding at ./configure time is (as I understand it) -# supposed to be captured by the AC_{PROG_{,OBJ}CXX,PATH_{PROG,TOOL}} macros, -# which will expand the program names to their full absolute paths. The notable -# exception is command line overriding: ./configure CC=clang, which skips the -# program name expansion step, and works because the user implicitly indicates -# with CC=clang that clang will be available in $PATH at all times, and is most -# likely part of the user's system. -# -# Therefore, when we "seed the autoconf cache"/"override well-known program -# vars" by setting AR=<blah> in our config.site, either one of two things needs -# to be true for the build system to work correctly: -# -# 1. If we refer to the program by name (e.g. AR=riscv64-gnu-linux-ar), the -# tool needs to be available in $PATH at all times. -# -# 2. If the tool is _**not**_ expected to be available in $PATH at all times -# it needs to be referred to by its absolute path, such as would be output -# by the AC_PATH_{PROG,TOOL} macros. -# -# Minor note: it is also okay to refer to tools by their absolute path even if -# we expect them to be available in $PATH at all times, more specificity does -# not hurt. -$(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_build_id) +ifeq ($(host),$(build)) + crosscompiling=FALSE +else + crosscompiling=TRUE +endif + +$(host_prefix)/toolchain.cmake : toolchain.cmake.in $(host_prefix)/.stamp_$(final_build_id) @mkdir -p $(@D) - sed -e 's|@HOST@|$(host)|' \ + sed -e 's|@depends_crosscompiling@|$(crosscompiling)|' \ + -e 's|@host_system_name@|$($(host_os)_cmake_system_name)|' \ + -e 's|@host_system_version@|$($(host_os)_cmake_system_version)|' \ + -e 's|@host_arch@|$(host_arch)|' \ -e 's|@CC@|$(host_CC)|' \ -e 's|@CXX@|$(host_CXX)|' \ + -e 's|@OSX_SDK@|$(OSX_SDK)|' \ -e 's|@AR@|$(host_AR)|' \ -e 's|@RANLIB@|$(host_RANLIB)|' \ - -e 's|@NM@|$(host_NM)|' \ -e 's|@STRIP@|$(host_STRIP)|' \ + -e 's|@OBJCOPY@|$(host_OBJCOPY)|' \ -e 's|@OBJDUMP@|$(host_OBJDUMP)|' \ - -e 's|@DSYMUTIL@|$(host_DSYMUTIL)|' \ - -e 's|@build_os@|$(build_os)|' \ - -e 's|@host_os@|$(host_os)|' \ - -e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \ - -e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS) $(host_$(release_type)_CXXFLAGS))|' \ - -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \ - -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ - -e 's|@no_qt@|$(NO_QT)|' \ - -e 's|@no_qr@|$(NO_QR)|' \ - -e 's|@no_zmq@|$(NO_ZMQ)|' \ - -e 's|@no_wallet@|$(NO_WALLET)|' \ - -e 's|@no_bdb@|$(NO_BDB)|' \ - -e 's|@no_sqlite@|$(NO_SQLITE)|' \ - -e 's|@no_upnp@|$(NO_UPNP)|' \ - -e 's|@no_usdt@|$(NO_USDT)|' \ - -e 's|@no_natpmp@|$(NO_NATPMP)|' \ - -e 's|@multiprocess@|$(MULTIPROCESS)|' \ - -e 's|@lto@|$(LTO)|' \ + -e 's|@depends_prefix@|$(host_prefix)|' \ + -e 's|@CFLAGS@|$(strip $(host_CFLAGS))|' \ + -e 's|@CFLAGS_RELEASE@|$(strip $(host_release_CFLAGS))|' \ + -e 's|@CFLAGS_DEBUG@|$(strip $(host_debug_CFLAGS))|' \ + -e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS))|' \ + -e 's|@CXXFLAGS_RELEASE@|$(strip $(host_release_CXXFLAGS))|' \ + -e 's|@CXXFLAGS_DEBUG@|$(strip $(host_debug_CXXFLAGS))|' \ + -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS))|' \ + -e 's|@CPPFLAGS_RELEASE@|$(strip $(host_release_CPPFLAGS))|' \ + -e 's|@CPPFLAGS_DEBUG@|$(strip $(host_debug_CPPFLAGS))|' \ + -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS))|' \ + -e 's|@LDFLAGS_RELEASE@|$(strip $(host_release_LDFLAGS))|' \ + -e 's|@LDFLAGS_DEBUG@|$(strip $(host_debug_LDFLAGS))|' \ + -e 's|@qt_packages@|$(qt_packages_)|' \ + -e 's|@qrencode_packages@|$(qrencode_packages_)|' \ + -e 's|@zmq_packages@|$(zmq_packages_)|' \ + -e 's|@wallet_packages@|$(wallet_packages_)|' \ + -e 's|@bdb_packages@|$(bdb_packages_)|' \ + -e 's|@sqlite_packages@|$(sqlite_packages_)|' \ + -e 's|@upnp_packages@|$(upnp_packages_)|' \ + -e 's|@usdt_packages@|$(usdt_packages_)|' \ -e 's|@no_harden@|$(NO_HARDEN)|' \ - -e 's|@debug@|$(DEBUG)|' \ + -e 's|@multiprocess@|$(MULTIPROCESS)|' \ $< > $@ touch $@ - define check_or_remove_cached mkdir -p $(BASE_CACHE)/$(host)/$(package) && cd $(BASE_CACHE)/$(host)/$(package); \ $(build_SHA256SUM) -c $($(package)_cached_checksum) >/dev/null 2>/dev/null || \ @@ -271,7 +257,7 @@ check-packages: check-sources: @$(foreach package,$(all_packages),$(call check_or_remove_sources,$(package));) -$(host_prefix)/share/config.site: check-packages +$(host_prefix)/toolchain.cmake: check-packages check-packages: check-sources @@ -281,7 +267,7 @@ clean-all: clean clean: @rm -rf $(WORK_PATH) $(BASE_CACHE) $(BUILD) *.log -install: check-packages $(host_prefix)/share/config.site +install: check-packages $(host_prefix)/toolchain.cmake download-one: check-sources $(all_sources) diff --git a/depends/README.md b/depends/README.md index 7ac075f4ba..4ef7247ea4 100644 --- a/depends/README.md +++ b/depends/README.md @@ -12,17 +12,13 @@ For example: make HOST=x86_64-w64-mingw32 -j4 -**Bitcoin Core's `configure` script by default will ignore the depends output.** In +**When configuring Bitcoin Core, CMake by default will ignore the depends output.** In order for it to pick up libraries, tools, and settings from the depends build, -you must set the `CONFIG_SITE` environment variable to point to a `config.site` settings file. -Make sure that `CONFIG_SITE` is an absolute path. -In the above example, a file named `depends/x86_64-w64-mingw32/share/config.site` will be -created. To use it during compilation: +you must specify the toolchain file. +In the above example, a file named `depends/x86_64-w64-mingw32/toolchain.cmake` will be +created. To use it during configuring Bitcoin Core: - CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure - -The default install prefix when using `config.site` is `--prefix=depends/<host-platform-triplet>`, -so depends build outputs will be installed in that location. + cmake -B build --toolchain depends/x86_64-w64-mingw32/toolchain.cmake Common `host-platform-triplet`s for cross compilation are: @@ -45,20 +41,20 @@ The paths are automatically configured and no other options are needed. #### Common - apt install automake bison cmake curl libtool make patch pkg-config python3 xz-utils + apt install bison cmake curl make patch pkg-config python3 xz-utils #### For macOS cross compilation - sudo apt-get install g++ zip + apt install clang lld llvm g++ zip -Note: You must obtain the macOS SDK before proceeding with a cross-compile. -Under the depends directory, create a subdirectory named `SDKs`. -Then, place the extracted SDK under this new directory. +Clang 18 or later is required. You must also obtain the macOS SDK before +proceeding with a cross-compile. Under the depends directory, create a +subdirectory named `SDKs`. Then, place the extracted SDK under this new directory. For more information, see [SDK Extraction](../contrib/macdeploy/README.md#sdk-extraction). #### For Win64 cross compilation -- see [build-windows.md](../doc/build-windows.md#cross-compilation-for-ubuntu-and-windows-subsystem-for-linux) + apt install g++-mingw-w64-x86-64-posix #### For linux (including i386, ARM) cross compilation @@ -90,9 +86,13 @@ For linux S390X cross compilation: pkg install bash +### Install the required dependencies: NetBSD + + pkgin install bash gmake + ### Install the required dependencies: OpenBSD - pkg_add bash gtar + pkg_add bash gmake gtar ### Dependency Options @@ -113,23 +113,19 @@ The following can be set when running make: `make FOO=bar` - `NO_BDB`: Don't download/build/cache BerkeleyDB - `NO_SQLITE`: Don't download/build/cache SQLite - `NO_UPNP`: Don't download/build/cache packages needed for enabling UPnP -- `NO_NATPMP`: Don't download/build/cache packages needed for enabling NAT-PMP - `NO_USDT`: Don't download/build/cache packages needed for enabling USDT tracepoints -- `MULTIPROCESS`: Build libmultiprocess (experimental, requires CMake) +- `MULTIPROCESS`: Build libmultiprocess (experimental) - `DEBUG`: Disable some optimizations and enable more runtime checking - `HOST_ID_SALT`: Optional salt to use when generating host package ids - `BUILD_ID_SALT`: Optional salt to use when generating build package ids -- `FORCE_USE_SYSTEM_CLANG`: (EXPERTS ONLY) When cross-compiling for macOS, use Clang found in the - system's `$PATH` rather than the default prebuilt release of Clang - from llvm.org. Clang 8 or later is required - `LOG`: Use file-based logging for individual packages. During a package build its log file resides in the `depends` directory, and the log file is printed out automatically in case of build error. After successful build log files are moved along with package archives - `LTO`: Enable options needed for LTO. Does not add `-flto` related options to *FLAGS. - `NO_HARDEN=1`: Don't use hardening options when building packages -If some packages are not built, for example `make NO_WALLET=1`, the appropriate -options will be passed to bitcoin's configure. In this case, `--disable-wallet`. +If some packages are not built, for example `make NO_WALLET=1`, the appropriate CMake cache +variables will be set when generating the Bitcoin Core buildsystem. In this case, `-DENABLE_WALLET=OFF`. ### Additional targets diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index d84c23ed44..2b59353e84 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -18,7 +18,6 @@ darwin_STRIP:=$(shell xcrun -f strip) darwin_OBJDUMP:=$(shell xcrun -f objdump) darwin_NM:=$(shell xcrun -f nm) darwin_DSYMUTIL:=$(shell xcrun -f dsymutil) -darwin_native_toolchain= x86_64_darwin_CFLAGS += -arch x86_64 x86_64_darwin_CXXFLAGS += -arch x86_64 diff --git a/depends/config.site.in b/depends/config.site.in deleted file mode 100644 index f6bed6a9d4..0000000000 --- a/depends/config.site.in +++ /dev/null @@ -1,147 +0,0 @@ -# shellcheck shell=sh disable=SC2034 # Many variables set will be used in - # ./configure but shellcheck doesn't know - # that, hence: disable=SC2034 - -true # Dummy command because shellcheck treats all directives before first - # command as file-wide, and we only want to disable for one line. - # - # See: https://github.com/koalaman/shellcheck/wiki/Directive - -# shellcheck disable=SC2154 -depends_prefix="$(cd "$(dirname "$ac_site_file")/.." && pwd)" - -cross_compiling=maybe -host_alias="@HOST@" -ac_tool_prefix="${host_alias}-" - -if test -z "$with_boost"; then - with_boost="$depends_prefix" -fi -if test -z "$with_qt_plugindir"; then - with_qt_plugindir="${depends_prefix}/plugins" -fi -if test -z "$with_qt_translationdir"; then - with_qt_translationdir="${depends_prefix}/translations" -fi -if test -z "$with_qt_bindir" && test -z "@no_qt@"; then - with_qt_bindir="${depends_prefix}/native/bin" -fi -if test -z "$with_mpgen" && test -n "@multiprocess@"; then - with_mpgen="${depends_prefix}/native" -fi - -if test -z "$with_qrencode" && test -n "@no_qr@"; then - with_qrencode=no -fi - -if test -z "$enable_wallet" && test -n "@no_wallet@"; then - enable_wallet=no -fi - -if test -z "$with_bdb" && test -n "@no_bdb@"; then - with_bdb=no -fi - -if test -z "$with_sqlite" && test -n "@no_sqlite@"; then - with_sqlite=no -fi - -if test -z "$enable_multiprocess" && test -n "@multiprocess@"; then - enable_multiprocess=yes -fi - -if test -z "$with_miniupnpc" && test -n "@no_upnp@"; then - with_miniupnpc=no -fi - -if test -z "$with_natpmp" && test -n "@no_natpmp@"; then - with_natpmp=no -fi - -if test -z "$with_gui" && test -n "@no_qt@"; then - with_gui=no -fi - -if test -n "@debug@" && test -z "@no_qt@" && test "$with_gui" != "no"; then - with_gui=qt5_debug -fi - -if test -z "$enable_zmq" && test -n "@no_zmq@"; then - enable_zmq=no -fi - -if test -z "$enable_usdt" && test -n "@no_usdt@"; then - enable_usdt=no -fi - -if test "@host_os@" = darwin; then - BREW=no -fi - -if test -z "$enable_hardening" && test -n "@no_harden@"; then - enable_hardening=no -fi - -PKG_CONFIG="$(which pkg-config) --static" - -PKG_CONFIG_PATH="${depends_prefix}/share/pkgconfig:${depends_prefix}/lib/pkgconfig" -PKG_CONFIG_LIBDIR="${depends_prefix}/lib/pkgconfig" - -CPPFLAGS="-I${depends_prefix}/include/ ${CPPFLAGS}" -LDFLAGS="-L${depends_prefix}/lib ${LDFLAGS}" - -if test -n "@CC@" -a -z "${CC}"; then - CC="@CC@" -fi -if test -n "@CXX@" -a -z "${CXX}"; then - CXX="@CXX@" -fi - -if test -n "@AR@"; then - AR="@AR@" - ac_cv_path_AR="${AR}" -fi - -if test -n "@RANLIB@"; then - RANLIB="@RANLIB@" - ac_cv_path_ac_pt_RANLIB="${RANLIB}" -fi - -if test -n "@NM@"; then - NM="@NM@" - ac_cv_path_ac_pt_NM="${NM}" -fi - -if test -n "@STRIP@"; then - STRIP="@STRIP@" - ac_cv_path_ac_pt_STRIP="${STRIP}" -fi - -if test "@host_os@" = darwin; then - if test -n "@OBJDUMP@"; then - OBJDUMP="@OBJDUMP@" - ac_cv_path_OBJDUMP="${OBJDUMP}" - fi - - if test -n "@DSYMUTIL@"; then - DSYMUTIL="@DSYMUTIL@" - ac_cv_path_DSYMUTIL="${DSYMUTIL}" - fi -fi - -if test -n "@debug@"; then - enable_reduce_exports=no -fi - -if test -n "@CFLAGS@"; then - CFLAGS="@CFLAGS@ ${CFLAGS}" -fi -if test -n "@CXXFLAGS@"; then - CXXFLAGS="@CXXFLAGS@ ${CXXFLAGS}" -fi -if test -n "@CPPFLAGS@"; then - CPPFLAGS="@CPPFLAGS@ ${CPPFLAGS}" -fi -if test -n "@LDFLAGS@"; then - LDFLAGS="@LDFLAGS@ ${LDFLAGS}" -fi diff --git a/depends/funcs.mk b/depends/funcs.mk index 537051c030..a2f760bd0e 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -46,7 +46,7 @@ endef define int_get_build_id $(eval $(1)_dependencies += $($(1)_$(host_arch)_$(host_os)_dependencies) $($(1)_$(host_os)_dependencies)) -$(eval $(1)_all_dependencies:=$(call int_get_all_dependencies,$(1),$($($(1)_type)_native_toolchain) $($(1)_dependencies))) +$(eval $(1)_all_dependencies:=$(call int_get_all_dependencies,$(1),$($(1)_dependencies))) $(foreach dep,$($(1)_all_dependencies),$(eval $(1)_build_id_deps+=$(dep)-$($(dep)_version)-$($(dep)_recipe_hash))) $(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_type) $($(1)_build_id_deps) $($($(1)_type)_id)) $(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH))) @@ -171,7 +171,7 @@ $(1)_autoconf += LDFLAGS="$$($(1)_ldflags)" endif # We hardcode the library install path to "lib" to match the PKG_CONFIG_PATH -# setting in depends/config.site.in, which also hardcodes "lib". +# setting in depends/toolchain.cmake.in, which also hardcodes "lib". # Without this setting, CMake by default would use the OS library # directory, which might be "lib64" or something else, not "lib", on multiarch systems. $(1)_cmake=env CC="$$($(1)_cc)" \ @@ -191,7 +191,7 @@ ifeq ($($(1)_type),build) $(1)_cmake += -DCMAKE_INSTALL_RPATH:PATH="$$($($(1)_type)_prefix)/lib" else ifneq ($(host),$(build)) -$(1)_cmake += -DCMAKE_SYSTEM_NAME=$($(host_os)_cmake_system) +$(1)_cmake += -DCMAKE_SYSTEM_NAME=$($(host_os)_cmake_system_name) $(1)_cmake += -DCMAKE_C_COMPILER_TARGET=$(host) $(1)_cmake += -DCMAKE_CXX_COMPILER_TARGET=$(host) endif @@ -297,6 +297,3 @@ $(foreach package,$(all_packages),$(eval $(call int_config_attach_build_config,$ #create build targets $(foreach package,$(all_packages),$(eval $(call int_add_cmds,$(package)))) - -#special exception: if a toolchain package exists, all non-native packages depend on it -$(foreach package,$(packages),$(eval $($(package)_extracted): |$($($(host_arch)_$(host_os)_native_toolchain)_cached) )) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index a64008d6aa..4659d52912 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,40 +1,11 @@ -OSX_MIN_VERSION=11.0 +OSX_MIN_VERSION=13.0 OSX_SDK_VERSION=14.0 XCODE_VERSION=15.0 XCODE_BUILD_ID=15A240d -LD64_VERSION=711 +LLD_VERSION=711 OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-libcxx-headers -ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),) -# FORCE_USE_SYSTEM_CLANG is empty, so we use our depends-managed, pinned LLVM -# from llvm.org - -darwin_native_toolchain=native_llvm - -clang_prog=$(build_prefix)/bin/clang -clangxx_prog=$(clang_prog)++ -llvm_config_prog=$(build_prefix)/bin/llvm-config - -llvm_TOOLS=AR NM OBJDUMP RANLIB STRIP - -# Make-only lowercase function -lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1)))))))))))))))))))))))))) - -# For well-known tools provided by LLVM, make sure that their well-known -# variable is set to the full path of the tool, just like how AC_PATH_{TOO,PROG} -# would. -$(foreach TOOL,$(llvm_TOOLS),$(eval darwin_$(TOOL) = $$(build_prefix)/bin/llvm-$(call lc,$(TOOL)))) - -# Clang expects dsymutil to be called dsymutil -darwin_DSYMUTIL=$(build_prefix)/bin/dsymutil - -else -# FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's -# system - -darwin_native_toolchain= - # We can't just use $(shell command -v clang) because GNU Make handles builtins # in a special way and doesn't know that `command` is a POSIX-standard builtin # prior to 1af314465e5dfe3e8baa839a32a72e83c04f26ef, first released in v4.2.90. @@ -44,9 +15,6 @@ darwin_native_toolchain= # Source: https://lists.gnu.org/archive/html/bug-make/2017-11/msg00017.html clang_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang") clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++") -llvm_config_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-config") - -llvm_lib_dir=$(shell $(llvm_config_prog) --libdir) darwin_AR=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-ar") darwin_DSYMUTIL=$(shell $(SHELL) $(.SHELLFLAGS) "command -v dsymutil") @@ -54,7 +22,6 @@ darwin_NM=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-nm") darwin_OBJDUMP=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-objdump") darwin_RANLIB=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-ranlib") darwin_STRIP=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-strip") -endif # Flag explanations: # @@ -63,11 +30,6 @@ endif # Ensures that modern linker features are enabled. See here for more # details: https://github.com/bitcoin/bitcoin/pull/19407. # -# -B$(build_prefix)/bin -# -# Explicitly point to our binaries so that they are -# ensured to be found and preferred over other possibilities. -# # -isysroot$(OSX_SDK) -nostdlibinc # # Disable default include paths built into the compiler as well as @@ -88,30 +50,22 @@ endif # 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) \ - -B$(build_prefix)/bin \ +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) \ - -B$(build_prefix)/bin \ +darwin_CXX=$(clangxx_prog) --target=$(host) \ -isysroot$(OSX_SDK) -nostdlibinc \ -iwithsysroot/usr/include/c++/v1 \ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks -darwin_CFLAGS=-pipe -std=$(C_STANDARD) -mmacosx-version-min=$(OSX_MIN_VERSION) -darwin_CXXFLAGS=-pipe -std=$(CXX_STANDARD) -mmacosx-version-min=$(OSX_MIN_VERSION) +darwin_CFLAGS=-pipe -std=$(C_STANDARD) -mmacos-version-min=$(OSX_MIN_VERSION) +darwin_CXXFLAGS=-pipe -std=$(CXX_STANDARD) -mmacos-version-min=$(OSX_MIN_VERSION) darwin_LDFLAGS=-Wl,-platform_version,macos,$(OSX_MIN_VERSION),$(OSX_SDK_VERSION) ifneq ($(build_os),darwin) -darwin_CFLAGS += -mlinker-version=$(LD64_VERSION) -darwin_CXXFLAGS += -mlinker-version=$(LD64_VERSION) +darwin_CFLAGS += -mlinker-version=$(LLD_VERSION) +darwin_CXXFLAGS += -mlinker-version=$(LLD_VERSION) darwin_LDFLAGS += -Wl,-no_adhoc_codesign -fuse-ld=lld endif @@ -121,4 +75,7 @@ darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) darwin_debug_CFLAGS=-O1 -g darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS) -darwin_cmake_system=Darwin +darwin_cmake_system_name=Darwin +# Darwin version, which corresponds to OSX_MIN_VERSION. +# See https://en.wikipedia.org/wiki/Darwin_(operating_system) +darwin_cmake_system_version=20.1 diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk index d82c33f29c..24689da45b 100644 --- a/depends/hosts/default.mk +++ b/depends/hosts/default.mk @@ -28,8 +28,8 @@ endef define add_host_flags_func ifeq ($(filter $(origin $1),undefined default),) -$(host_arch)_$(host_os)_$1 = -$(host_arch)_$(host_os)_$(release_type)_$1 = $($1) +$(host_arch)_$(host_os)_$1 = $($1) +$(host_arch)_$(host_os)_$(release_type)_$1 = else $(host_arch)_$(host_os)_$1 += $($(host_os)_$1) $(host_arch)_$(host_os)_$(release_type)_$1 += $($(host_os)_$(release_type)_$1) diff --git a/depends/hosts/freebsd.mk b/depends/hosts/freebsd.mk index 055097b03d..8cef32e231 100644 --- a/depends/hosts/freebsd.mk +++ b/depends/hosts/freebsd.mk @@ -28,4 +28,4 @@ x86_64_freebsd_CC=$(default_host_CC) -m64 x86_64_freebsd_CXX=$(default_host_CXX) -m64 endif -freebsd_cmake_system=FreeBSD +freebsd_cmake_system_name=FreeBSD diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk index f5ce2bb0b8..e2f34265d1 100644 --- a/depends/hosts/linux.mk +++ b/depends/hosts/linux.mk @@ -39,4 +39,7 @@ i686_linux_CXX=$(default_host_CXX) -m32 x86_64_linux_CC=$(default_host_CC) -m64 x86_64_linux_CXX=$(default_host_CXX) -m64 endif -linux_cmake_system=Linux + +linux_cmake_system_name=Linux +# Refer to doc/dependencies.md for the minimum required kernel. +linux_cmake_system_version=3.17.0 diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk index 4c657358f6..755d7aebe4 100644 --- a/depends/hosts/mingw32.mk +++ b/depends/hosts/mingw32.mk @@ -1,3 +1,6 @@ +ifneq ($(shell $(SHELL) $(.SHELLFLAGS) "command -v $(host)-gcc-posix"),) +mingw32_CC := $(host)-gcc-posix +endif ifneq ($(shell $(SHELL) $(.SHELLFLAGS) "command -v $(host)-g++-posix"),) mingw32_CXX := $(host)-g++-posix endif @@ -19,4 +22,6 @@ mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS) mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -mingw32_cmake_system=Windows +mingw32_cmake_system_name=Windows +# Windows 7 (NT 6.1). +mingw32_cmake_system_version=6.1 diff --git a/depends/hosts/netbsd.mk b/depends/hosts/netbsd.mk index f33b2d2889..16dff92d42 100644 --- a/depends/hosts/netbsd.mk +++ b/depends/hosts/netbsd.mk @@ -36,4 +36,4 @@ x86_64_netbsd_CC=$(default_host_CC) -m64 x86_64_netbsd_CXX=$(default_host_CXX) -m64 endif -netbsd_cmake_system=NetBSD +netbsd_cmake_system_name=NetBSD diff --git a/depends/hosts/openbsd.mk b/depends/hosts/openbsd.mk index bdd36dc9b3..63f6d73d55 100644 --- a/depends/hosts/openbsd.mk +++ b/depends/hosts/openbsd.mk @@ -28,4 +28,4 @@ x86_64_openbsd_CC=$(default_host_CC) -m64 x86_64_openbsd_CXX=$(default_host_CXX) -m64 endif -openbsd_cmake_system=OpenBSD +openbsd_cmake_system_name=OpenBSD diff --git a/depends/packages/capnp.mk b/depends/packages/capnp.mk index 6d792db711..0c211cbc45 100644 --- a/depends/packages/capnp.mk +++ b/depends/packages/capnp.mk @@ -9,6 +9,7 @@ define $(package)_set_vars := $(package)_config_opts := -DBUILD_TESTING=OFF $(package)_config_opts += -DWITH_OPENSSL=OFF $(package)_config_opts += -DWITH_ZLIB=OFF + $(package)_cxxflags += -ffile-prefix-map=$$($(package)_extract_dir)=/usr endef define $(package)_config_cmds 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..4c05e8a0a7 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -3,14 +3,18 @@ $(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 += -D_GNU_SOURCE $(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601 ifeq ($(NO_HARDEN),) @@ -19,11 +23,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 +40,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/libmultiprocess.mk b/depends/packages/libmultiprocess.mk index c292c49bfb..a181e05100 100644 --- a/depends/packages/libmultiprocess.mk +++ b/depends/packages/libmultiprocess.mk @@ -13,6 +13,7 @@ ifneq ($(host),$(build)) $(package)_config_opts := -DCAPNP_EXECUTABLE="$$(native_capnp_prefixbin)/capnp" $(package)_config_opts += -DCAPNPC_CXX_EXECUTABLE="$$(native_capnp_prefixbin)/capnpc-c++" endif +$(package)_cxxflags += -ffile-prefix-map=$$($(package)_extract_dir)=/usr endef define $(package)_config_cmds diff --git a/depends/packages/libnatpmp.mk b/depends/packages/libnatpmp.mk deleted file mode 100644 index 5a573a18e7..0000000000 --- a/depends/packages/libnatpmp.mk +++ /dev/null @@ -1,20 +0,0 @@ -package=libnatpmp -$(package)_version=f2433bec24ca3d3f22a8a7840728a3ac177f94ba -$(package)_download_path=https://github.com/miniupnp/libnatpmp/archive -$(package)_file_name=$($(package)_version).tar.gz -$(package)_sha256_hash=ef84979950dfb3556705b63c9cd6c95501b75e887fba466234b187f3c9029669 -$(package)_build_subdir=build - -define $(package)_config_cmds - $($(package)_cmake) -S .. -B . -endef - -define $(package)_build_cmds - $(MAKE) natpmp -endef - -define $(package)_stage_cmds - mkdir -p $($(package)_staging_prefix_dir)/include $($(package)_staging_prefix_dir)/lib && \ - install ../natpmp.h ../natpmp_declspec.h $($(package)_staging_prefix_dir)/include && \ - install libnatpmp.a $($(package)_staging_prefix_dir)/lib -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..7c69e0f0c6 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=abe254b9734f2e2b220d1456de195532d6e6ac1e $(package)_download_path=https://github.com/chaincodelabs/libmultiprocess/archive $(package)_file_name=$($(package)_version).tar.gz -$(package)_sha256_hash=030f4d393d2ac9deba98d2e1973e22fc439ffc009d5f8ae3225c90639f86beb0 +$(package)_sha256_hash=85777073259fdc75d24ac5777a19991ec1156c5f12db50b252b861c95dcb4f46 $(package)_dependencies=native_capnp define $(package)_config_cmds diff --git a/depends/packages/native_llvm.mk b/depends/packages/native_llvm.mk deleted file mode 100644 index c701147edc..0000000000 --- a/depends/packages/native_llvm.mk +++ /dev/null @@ -1,31 +0,0 @@ -package=native_llvm -$(package)_version=17.0.6 -$(package)_major_version=$(firstword $(subst ., ,$($(package)_version))) -$(package)_download_path=https://github.com/llvm/llvm-project/releases/download/llvmorg-$($(package)_version) -ifneq (,$(findstring aarch64,$(BUILD))) -$(package)_file_name=clang+llvm-$($(package)_version)-aarch64-linux-gnu.tar.xz -$(package)_sha256_hash=6dd62762285326f223f40b8e4f2864b5c372de3f7de0731cb7cd55ca5287b75a -else -$(package)_file_name=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-22.04.tar.xz -$(package)_sha256_hash=884ee67d647d77e58740c1e645649e29ae9e8a6fe87c1376be0f3a30f3cc9ab3 -endif - -define $(package)_stage_cmds - mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_major_version)/include && \ - mkdir -p $($(package)_staging_prefix_dir)/bin && \ - mkdir -p $($(package)_staging_prefix_dir)/include/llvm-c && \ - cp bin/clang $($(package)_staging_prefix_dir)/bin/ && \ - cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ && \ - cp bin/dsymutil $($(package)_staging_prefix_dir)/bin/dsymutil && \ - cp bin/ld64.lld $($(package)_staging_prefix_dir)/bin/ld64.lld && \ - cp bin/llvm-ar $($(package)_staging_prefix_dir)/bin/llvm-ar && \ - cp bin/llvm-config $($(package)_staging_prefix_dir)/bin/ && \ - cp bin/llvm-nm $($(package)_staging_prefix_dir)/bin/llvm-nm && \ - cp bin/llvm-objdump $($(package)_staging_prefix_dir)/bin/llvm-objdump && \ - cp bin/llvm-ranlib $($(package)_staging_prefix_dir)/bin/llvm-ranlib && \ - cp bin/llvm-strip $($(package)_staging_prefix_dir)/bin/llvm-strip && \ - cp include/llvm-c/ExternC.h $($(package)_staging_prefix_dir)/include/llvm-c && \ - cp include/llvm-c/lto.h $($(package)_staging_prefix_dir)/include/llvm-c && \ - cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \ - cp -r lib/clang/$($(package)_major_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_major_version)/include/ -endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index ca54093339..08a91cbcbd 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -18,19 +18,8 @@ sqlite_packages=sqlite zmq_packages=zeromq upnp_packages=miniupnpc -natpmp_packages=libnatpmp multiprocess_packages = libmultiprocess capnp multiprocess_native_packages = native_libmultiprocess native_capnp usdt_linux_packages=systemtap - -darwin_native_packages = - -ifneq ($(build_os),darwin) - -ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),) -darwin_native_packages+= native_llvm -endif - -endif 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..917e179932 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/ &&\ @@ -263,13 +265,14 @@ define $(package)_build_cmds $(MAKE) endef +# TODO: Investigate whether specific targets can be used here to minimize the amount of files/components installed. define $(package)_stage_cmds - $(MAKE) -C qtbase/src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && \ - $(MAKE) -C qttools/src/linguist INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_linguist_tools))) && \ + $(MAKE) -C qtbase INSTALL_ROOT=$($(package)_staging_dir) install && \ + $(MAKE) -C qttools INSTALL_ROOT=$($(package)_staging_dir) install && \ $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets endef define $(package)_postprocess_cmds - rm -rf native/mkspecs/ native/lib/ lib/cmake/ && \ + rm -rf doc/ native/lib/ && \ rm -f lib/lib*.la endef diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index bfa5e97c60..67a0dd88e5 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -3,34 +3,50 @@ $(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 +$(package)_patches += fix_mingw_link.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 && \ + patch -p1 < $($(package)_patch_dir)/fix_mingw_link.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/qt/qt.pro b/depends/patches/qt/qt.pro index 8f2e900a84..6d8b7fdb6a 100644 --- a/depends/patches/qt/qt.pro +++ b/depends/patches/qt/qt.pro @@ -3,10 +3,6 @@ cache(, super) !QTDIR_build: cache(CONFIG, add, $$list(QTDIR_build)) -prl = no_install_prl -CONFIG += $$prl -cache(CONFIG, add stash, prl) - TEMPLATE = subdirs SUBDIRS = qtbase qttools qttranslations 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/fix_mingw_link.patch b/depends/patches/zeromq/fix_mingw_link.patch new file mode 100644 index 0000000000..1434557dc7 --- /dev/null +++ b/depends/patches/zeromq/fix_mingw_link.patch @@ -0,0 +1,31 @@ +Fix CMake-generated `libzmq.pc` file + +This change mirrors the Autotools-based build system behavior for +cross-compiling for Windows with static linking. + +See https://github.com/zeromq/libzmq/pull/4706. + + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 03462271..0315e606 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -546,12 +546,18 @@ if(ZMQ_HAVE_WINDOWS) + # Cannot use check_library_exists because the symbol is always declared as char(*)(void) + set(CMAKE_REQUIRED_LIBRARIES "ws2_32.lib") + check_cxx_symbol_exists(WSAStartup "winsock2.h" HAVE_WS2_32) ++ if(HAVE_WS2_32) ++ set(pkg_config_libs_private "${pkg_config_libs_private} -lws2_32") ++ endif() + + set(CMAKE_REQUIRED_LIBRARIES "rpcrt4.lib") + check_cxx_symbol_exists(UuidCreateSequential "rpc.h" HAVE_RPCRT4) + + set(CMAKE_REQUIRED_LIBRARIES "iphlpapi.lib") + check_cxx_symbol_exists(GetAdaptersAddresses "winsock2.h;iphlpapi.h" HAVE_IPHLAPI) ++ if(HAVE_IPHLAPI) ++ set(pkg_config_libs_private "${pkg_config_libs_private} -liphlpapi") ++ endif() + check_cxx_symbol_exists(if_nametoindex "iphlpapi.h" HAVE_IF_NAMETOINDEX) + + set(CMAKE_REQUIRED_LIBRARIES "") 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/depends/toolchain.cmake.in b/depends/toolchain.cmake.in new file mode 100644 index 0000000000..735ebc8ea4 --- /dev/null +++ b/depends/toolchain.cmake.in @@ -0,0 +1,168 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# This file is expected to be highly volatile and may still change substantially. + +# If CMAKE_SYSTEM_NAME is set within a toolchain file, CMake will also +# set CMAKE_CROSSCOMPILING to TRUE, even if CMAKE_SYSTEM_NAME matches +# CMAKE_HOST_SYSTEM_NAME. To avoid potential misconfiguration of CMake, +# it is best not to touch CMAKE_SYSTEM_NAME unless cross-compiling is +# intended. +if(@depends_crosscompiling@) + set(CMAKE_SYSTEM_NAME @host_system_name@) + set(CMAKE_SYSTEM_VERSION @host_system_version@) + set(CMAKE_SYSTEM_PROCESSOR @host_arch@) +endif() + +if(NOT DEFINED CMAKE_C_FLAGS_INIT) + set(CMAKE_C_FLAGS_INIT "@CFLAGS@") +endif() +if(NOT DEFINED CMAKE_C_FLAGS_RELWITHDEBINFO_INIT) + set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "@CFLAGS_RELEASE@") +endif() +if(NOT DEFINED CMAKE_C_FLAGS_DEBUG_INIT) + set(CMAKE_C_FLAGS_DEBUG_INIT "@CFLAGS_DEBUG@") +endif() + +if(NOT DEFINED CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER @CC@) +endif() + +if(NOT DEFINED CMAKE_CXX_FLAGS_INIT) + set(CMAKE_CXX_FLAGS_INIT "@CXXFLAGS@") + set(CMAKE_OBJCXX_FLAGS_INIT "@CXXFLAGS@") +endif() +if(NOT DEFINED CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "@CXXFLAGS_RELEASE@") + set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO_INIT "@CXXFLAGS_RELEASE@") +endif() +if(NOT DEFINED CMAKE_CXX_FLAGS_DEBUG_INIT) + set(CMAKE_CXX_FLAGS_DEBUG_INIT "@CXXFLAGS_DEBUG@") + set(CMAKE_OBJCXX_FLAGS_DEBUG_INIT "@CXXFLAGS_DEBUG@") +endif() + +if(NOT DEFINED CMAKE_CXX_COMPILER) + set(CMAKE_CXX_COMPILER @CXX@) + set(CMAKE_OBJCXX_COMPILER ${CMAKE_CXX_COMPILER}) +endif() + +# The DEPENDS_COMPILE_DEFINITIONS* variables are to be treated as lists. +set(DEPENDS_COMPILE_DEFINITIONS @CPPFLAGS@) +set(DEPENDS_COMPILE_DEFINITIONS_RELWITHDEBINFO @CPPFLAGS_RELEASE@) +set(DEPENDS_COMPILE_DEFINITIONS_DEBUG @CPPFLAGS_DEBUG@) + +if(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT) + set(CMAKE_EXE_LINKER_FLAGS_INIT "@LDFLAGS@") +endif() +if(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO_INIT) + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO_INIT "@LDFLAGS_RELEASE@") +endif() +if(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_DEBUG_INIT) + set(CMAKE_EXE_LINKER_FLAGS_DEBUG_INIT "@LDFLAGS_DEBUG@") +endif() + +set(CMAKE_AR "@AR@") +set(CMAKE_RANLIB "@RANLIB@") +set(CMAKE_STRIP "@STRIP@") +set(CMAKE_OBJCOPY "@OBJCOPY@") +set(CMAKE_OBJDUMP "@OBJDUMP@") + +# Using our own built dependencies should not be +# affected by a potentially random environment. +set(CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH OFF) + +set(CMAKE_FIND_ROOT_PATH "@depends_prefix@") +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(QT_TRANSLATIONS_DIR "@depends_prefix@/translations") + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_HOST_APPLE) + # The find_package(Qt ...) function internally uses find_library() + # calls for all dependencies to ensure their availability. + # In turn, the find_library() inspects the well-known locations + # on the file system; therefore, a hint is required. + set(CMAKE_FRAMEWORK_PATH "@OSX_SDK@/System/Library/Frameworks") +endif() + + +# Customize pkg-config behaviour. +cmake_path(APPEND CMAKE_FIND_ROOT_PATH "lib" "pkgconfig" OUTPUT_VARIABLE pkg_config_path) +set(ENV{PKG_CONFIG_PATH} ${pkg_config_path}) +set(ENV{PKG_CONFIG_LIBDIR} ${pkg_config_path}) +unset(pkg_config_path) +set(PKG_CONFIG_ARGN --static) + + +# Set configuration options for the main build system. +set(qt_packages @qt_packages@) +if("${qt_packages}" STREQUAL "") + set(BUILD_GUI OFF CACHE BOOL "") +else() + set(BUILD_GUI ON CACHE BOOL "") +endif() + +set(qrencode_packages @qrencode_packages@) +if("${qrencode_packages}" STREQUAL "") + set(WITH_QRENCODE OFF CACHE BOOL "") +else() + set(WITH_QRENCODE ON CACHE BOOL "") +endif() + +set(zmq_packages @zmq_packages@) +if("${zmq_packages}" STREQUAL "") + set(WITH_ZMQ OFF CACHE BOOL "") +else() + set(WITH_ZMQ ON CACHE BOOL "") +endif() + +set(wallet_packages @wallet_packages@) +if("${wallet_packages}" STREQUAL "") + set(ENABLE_WALLET OFF CACHE BOOL "") +else() + set(ENABLE_WALLET ON CACHE BOOL "") +endif() + +set(bdb_packages @bdb_packages@) +if("${wallet_packages}" STREQUAL "" OR "${bdb_packages}" STREQUAL "") + set(WITH_BDB OFF CACHE BOOL "") +else() + set(WITH_BDB ON CACHE BOOL "") +endif() + +set(sqlite_packages @sqlite_packages@) +if("${wallet_packages}" STREQUAL "" OR "${sqlite_packages}" STREQUAL "") + set(WITH_SQLITE OFF CACHE BOOL "") +else() + set(WITH_SQLITE ON CACHE BOOL "") +endif() + +set(upnp_packages @upnp_packages@) +if("${upnp_packages}" STREQUAL "") + set(WITH_MINIUPNPC OFF CACHE BOOL "") +else() + set(WITH_MINIUPNPC ON CACHE BOOL "") +endif() + +set(usdt_packages @usdt_packages@) +if("${usdt_packages}" STREQUAL "") + set(WITH_USDT OFF CACHE BOOL "") +else() + set(WITH_USDT ON CACHE BOOL "") +endif() + +if("@no_harden@") + set(ENABLE_HARDENING OFF CACHE BOOL "") +else() + set(ENABLE_HARDENING ON CACHE BOOL "") +endif() + +if("@multiprocess@" STREQUAL "1") + set(WITH_MULTIPROCESS ON CACHE BOOL "") + set(Libmultiprocess_ROOT "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "") + set(LibmultiprocessNative_ROOT "${CMAKE_CURRENT_LIST_DIR}/native" CACHE PATH "") +else() + set(WITH_MULTIPROCESS OFF CACHE BOOL "") +endif() diff --git a/doc/.gitignore b/doc/.gitignore deleted file mode 100644 index 38498103bb..0000000000 --- a/doc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Doxyfile diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 0000000000..310a90612b --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +find_package(Doxygen COMPONENTS dot) + +if(DOXYGEN_FOUND) + set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + configure_file(Doxyfile.in ${doxyfile} USE_SOURCE_PERMISSIONS) + + # In CMake 3.27, The FindDoxygen module's doxygen_add_docs() + # command gained a CONFIG_FILE option to specify a custom doxygen + # configuration file. + # TODO: Consider using it. + add_custom_target(docs + COMMAND Doxygen::doxygen ${doxyfile} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Generating developer documentation" + VERBATIM USES_TERMINAL + ) +else() + add_custom_target(docs + COMMAND ${CMAKE_COMMAND} -E echo "Error: Doxygen not found" + ) +endif() diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index d8fd46d1c7..ccaf31170a 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -58,7 +58,7 @@ PROJECT_LOGO = doc/bitcoin_logo_doxygen.png # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doc/doxygen +OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/doc/doxygen # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md index 2a97aa351d..10d8ee52eb 100644 --- a/doc/JSON-RPC-interface.md +++ b/doc/JSON-RPC-interface.md @@ -33,10 +33,10 @@ requests when multiple wallets are in use. ```sh # Get block count from the / endpoint when rpcuser=alice and rpcport=38332 -$ curl --user alice --data-binary '{"jsonrpc": "1.0", "id": "0", "method": "getblockcount", "params": []}' -H 'content-type: application/json;' localhost:38332/ +$ curl --user alice --data-binary '{"jsonrpc": "2.0", "id": "0", "method": "getblockcount", "params": []}' -H 'content-type: application/json' localhost:38332/ # Get balance from the /wallet/walletname endpoint when rpcuser=alice, rpcport=38332 and rpcwallet=desc-wallet -$ curl --user alice --data-binary '{"jsonrpc": "1.0", "id": "0", "method": "getbalance", "params": []}' -H 'content-type: application/json;' localhost:38332/wallet/desc-wallet +$ curl --user alice --data-binary '{"jsonrpc": "2.0", "id": "0", "method": "getbalance", "params": []}' -H 'content-type: application/json' localhost:38332/wallet/desc-wallet ``` @@ -80,7 +80,7 @@ The server recognizes [JSON-RPC v2.0](https://www.jsonrpc.org/specification) req and responds accordingly. A 2.0 request is identified by the presence of `"jsonrpc": "2.0"` in the request body. If that key + value is not present in a request, the legacy JSON-RPC v1.1 protocol is followed instead, which was the only available -protocol in previous releases. +protocol in v27.0 and prior releases. || 1.1 | 2.0 | |-|-|-| @@ -88,7 +88,7 @@ protocol in previous releases. | Response marker | (none) | `"jsonrpc": "2.0"` | | `"error"` and `"result"` fields in response | both present | only one is present | | HTTP codes in response | `200` unless there is any kind of RPC error (invalid parameters, method not found, etc) | Always `200` unless there is an actual HTTP server error (request parsing error, endpoint not found, etc) | -| Notifications: requests that get no reply | (not supported) | Supported for requests that exclude the "id" field | +| Notifications: requests that get no reply | (not supported) | Supported for requests that exclude the "id" field. Returns HTTP status `204` "No Content" | ## Security diff --git a/doc/README.md b/doc/README.md index 74a85b04e6..79ca53ce76 100644 --- a/doc/README.md +++ b/doc/README.md @@ -3,7 +3,7 @@ Bitcoin Core Setup --------------------- -Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. It downloads and, by default, stores the entire history of Bitcoin transactions, which requires a few hundred gigabytes of disk space. Depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. +Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. It downloads and, by default, stores the entire history of Bitcoin transactions, which requires several hundred gigabytes or more of disk space. Depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to several days or more. To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/download/). @@ -41,7 +41,7 @@ The following are developer notes on how to build Bitcoin Core on your native pl - [Dependencies](dependencies.md) - [macOS Build Notes](build-osx.md) - [Unix Build Notes](build-unix.md) -- [Windows Build Notes](build-windows.md) +- [Windows Build Notes](build-windows-msvc.md) - [FreeBSD Build Notes](build-freebsd.md) - [OpenBSD Build Notes](build-openbsd.md) - [NetBSD Build Notes](build-netbsd.md) 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/assumeutxo.md b/doc/assumeutxo.md new file mode 100644 index 0000000000..17858de540 --- /dev/null +++ b/doc/assumeutxo.md @@ -0,0 +1,85 @@ +# Assumeutxo Usage + +Assumeutxo is a feature that allows fast bootstrapping of a validating bitcoind +instance. + +For notes on the design of Assumeutxo, please refer to [the design doc](/doc/design/assumeutxo.md). + +## Loading a snapshot + +There is currently no canonical source for snapshots, but any downloaded snapshot +will be checked against a hash that's been hardcoded in source code. If there is +no source for the snapshot you need, you can generate it yourself using +`dumptxoutset` on another node that is already synced (see +[Generating a snapshot](#generating-a-snapshot)). + +Once you've obtained the snapshot, you can use the RPC command `loadtxoutset` to +load it. + +``` +$ bitcoin-cli -rpcclienttimeout=0 loadtxoutset /path/to/input +``` + +After the snapshot has loaded, the syncing process of both the snapshot chain +and the background IBD chain can be monitored with the `getchainstates` RPC. + +### Pruning + +A pruned node can load a snapshot. To save space, it's possible to delete the +snapshot file as soon as `loadtxoutset` finishes. + +The minimum `-prune` setting is 550 MiB, but this functionality ignores that +minimum and uses at least 1100 MiB. + +As the background sync continues there will be temporarily two chainstate +directories, each multiple gigabytes in size (likely growing larger than the +downloaded snapshot). + +### Indexes + +Indexes work but don't take advantage of this feature. They always start building +from the genesis block and can only apply blocks in order. Once the background +validation reaches the snapshot block, indexes will continue to build all the +way to the tip. + + +For indexes that support pruning, note that these indexes only allow blocks that +were already indexed to be pruned. Blocks that are not indexed yet will also +not be pruned. + +This means that, if the snapshot is old, then a lot of blocks after the snapshot +block will need to be downloaded, and these blocks can't be pruned until they +are indexed, so they could consume a lot of disk space until indexing catches up +to the snapshot block. + +## Generating a snapshot + +The RPC command `dumptxoutset` can be used to generate a snapshot for the current +tip (using type "latest") or a recent height (using type "rollback"). A generated +snapshot from one node can then be loaded +on any other node. However, keep in mind that the snapshot hash needs to be +listed in the chainparams to make it usable. If there is no snapshot hash for +the height you have chosen already, you will need to change the code there and +re-compile. + +Using the type parameter "rollback", `dumptxoutset` can also be used to verify the +hardcoded snapshot hash in the source code by regenerating the snapshot and +comparing the hash. + +Example usage: + +``` +$ bitcoin-cli -rpcclienttimeout=0 dumptxoutset /path/to/output rollback +``` + +For most of the duration of `dumptxoutset` running the node is in a temporary +state that does not actually reflect reality, i.e. blocks are marked invalid +although we know they are not invalid. Because of this it is discouraged to +interact with the node in any other way during this time to avoid inconsistent +results and race conditions, particularly RPCs that interact with blockstorage. +This inconsistent state is also why network activity is temporarily disabled, +causing us to disconnect from all peers. + +`dumptxoutset` takes some time to complete, independent of hardware and +what parameter is chosen. Because of that it is recommended to increase the RPC +client timeout value (use `-rpcclienttimeout=0` for no timeout). diff --git a/doc/benchmarking.md b/doc/benchmarking.md index 84d5f2c444..c6dc75dc5c 100644 --- a/doc/benchmarking.md +++ b/doc/benchmarking.md @@ -8,16 +8,17 @@ thread queue, wallet balance. Running --------------------- -For benchmarking, you only need to compile `bitcoin_bench`. The bench runner -warns if you configure with `--enable-debug`, but consider if building without +For benchmarking, you only need to compile `bench_bitcoin`. The bench runner +warns if you configure with `-DCMAKE_BUILD_TYPE=Debug`, but consider if building without it will impact the benchmark(s) you are interested in by unlatching log printers and lock analysis. - make -C src bitcoin_bench + cmake -B build -DBUILD_BENCH=ON + cmake --build build -t bench_bitcoin After compiling bitcoin-core, the benchmarks can be run with: - src/bench/bench_bitcoin + build/src/bench/bench_bitcoin The output will look similar to: ``` @@ -39,7 +40,7 @@ The output will look similar to: Help --------------------- - src/bench/bench_bitcoin -? + build/src/bench/bench_bitcoin -? To print the various options, like listing the benchmarks without running them or using a regex filter to only run certain benchmarks. diff --git a/doc/bips.md b/doc/bips.md index 8309ee7e92..d544ff822b 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)). @@ -61,6 +62,7 @@ BIPs that are implemented by Bitcoin Core: [PR 21686](https://github.com/bitcoin/bitcoin/pull/21686)). * [`BIP 350`](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki): Addresses for native v1+ segregated Witness outputs use Bech32m instead of Bech32 as of **v22.0** ([PR 20861](https://github.com/bitcoin/bitcoin/pull/20861)). * [`BIP 371`](https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki): Taproot fields for PSBT as of **v24.0** ([PR 22558](https://github.com/bitcoin/bitcoin/pull/22558)). +* [`BIP 379`](https://github.com/bitcoin/bips/blob/master/bip-0379.md): Miniscript was partially implemented in **v24.0** ([PR 24148](https://github.com/bitcoin/bitcoin/pull/24148)), and fully implemented as of **v26.0** ([PR 27255](https://github.com/bitcoin/bitcoin/pull/27255)). * [`BIP 380`](https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki) [`381`](https://github.com/bitcoin/bips/blob/master/bip-0381.mediawiki) [`382`](https://github.com/bitcoin/bips/blob/master/bip-0382.mediawiki) @@ -69,3 +71,5 @@ BIPs that are implemented by Bitcoin Core: [`385`](https://github.com/bitcoin/bips/blob/master/bip-0385.mediawiki): Output Script Descriptors, and most of Script Expressions are implemented as of **v0.17.0** ([PR 13697](https://github.com/bitcoin/bitcoin/pull/13697)). * [`BIP 386`](https://github.com/bitcoin/bips/blob/master/bip-0386.mediawiki): tr() Output Script Descriptors are implemented as of **v22.0** ([PR 22051](https://github.com/bitcoin/bitcoin/pull/22051)). +* [`BIP 387`](https://github.com/bitcoin/bips/blob/master/bip-0387.mediawiki): Tapscript Multisig Output Script Descriptors are implemented as of **v24.0** ([PR 24043](https://github.com/bitcoin/bitcoin/pull/24043)). +* [`BIP 431`](https://github.com/bitcoin/bips/blob/master/bip-0431.mediawiki): transactions with nVersion=3 are standard and treated as Topologically Restricted Until Confirmation as of **v28.0** ([PR 29496](https://github.com/bitcoin/bitcoin/pull/29496)). diff --git a/doc/bitcoin-conf.md b/doc/bitcoin-conf.md index 76711d0e7d..9b31879790 100644 --- a/doc/bitcoin-conf.md +++ b/doc/bitcoin-conf.md @@ -31,7 +31,7 @@ Comments may appear in two ways: ### Network specific options Network specific options can be: -- placed into sections with headers `[main]` (not `[mainnet]`), `[test]` (not `[testnet]`), `[signet]` or `[regtest]`; +- placed into sections with headers `[main]` (not `[mainnet]`), `[test]` (not `[testnet]`, for testnet3), `[testnet4]`, `[signet]` or `[regtest]`; - prefixed with a chain name; e.g., `regtest.maxmempool=100`. Network specific options take precedence over non-network specific options. diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index bf86a0ee4b..8b3b10ab85 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -10,15 +10,14 @@ This guide describes how to build bitcoind, command-line utilities, and GUI on F Run the following as root to install the base dependencies for building. ```bash -pkg install autoconf automake boost-libs git gmake libevent libtool pkgconf - +pkg install boost-libs cmake git libevent pkgconf ``` See [dependencies.md](dependencies.md) for a complete overview. ### 2. Clone Bitcoin Repo Now that `git` and all the required dependencies are installed, let's clone the Bitcoin Core repository to a directory. All build scripts and commands will run from this directory. -``` bash +```bash git clone https://github.com/bitcoin/bitcoin.git ``` @@ -31,7 +30,7 @@ It is not necessary to build wallet functionality to run either `bitcoind` or `b `sqlite3` is required to support [descriptor wallets](descriptors.md). Skip if you don't intend to use descriptor wallets. -``` bash +```bash pkg install sqlite3 ``` @@ -41,8 +40,9 @@ BerkeleyDB is only required if legacy wallet support is required. It is required to use Berkeley DB 4.8. You **cannot** use the BerkeleyDB library from ports. However, you can build DB 4.8 yourself [using depends](/depends). -``` -gmake -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 +```bash +pkg install gmake +gmake -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 ``` When the build is complete, the Berkeley DB installation location will be displayed: @@ -64,17 +64,23 @@ sh/bash: export BDB_PREFIX=[path displayed above] #### GUI Dependencies ###### Qt5 -Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install the necessary parts of Qt. Skip if you don't intend to use the GUI. +Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install +the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if you don't intend to use the GUI. + ```bash pkg install qt5-buildtools qt5-core qt5-gui qt5-linguisttools qt5-testlib qt5-widgets ``` ###### 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. +The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run: + ```bash pkg install libqrencode ``` + +Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` option to disable this feature in order to compile the GUI. + --- #### Notifications @@ -101,33 +107,28 @@ pkg install python3 databases/py-sqlite3 There are many ways to configure Bitcoin Core, here are a few common examples: ##### Descriptor Wallet and GUI: -This explicitly enables the GUI and disables legacy wallet support, assuming `sqlite` and `qt` are installed. +This disables legacy wallet support and enables the GUI, assuming `sqlite` and `qt` are installed. ```bash -./autogen.sh -./configure --without-bdb --with-gui=yes MAKE=gmake +cmake -B build -DWITH_BDB=OFF -DBUILD_GUI=ON ``` +Run `cmake -B build -LH` to see the full list of available options. + ##### Descriptor & Legacy Wallet. No GUI: -This enables support for both wallet types and disables the GUI, assuming +This enables support for both wallet types, assuming `sqlite3` and `db4` are both installed. ```bash -./autogen.sh -./configure --with-gui=no \ - BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ - BDB_CFLAGS="-I${BDB_PREFIX}/include" \ - MAKE=gmake +cmake -B build -DBerkeleyDB_INCLUDE_DIR:PATH="${BDB_PREFIX}/include" -DWITH_BDB=ON ``` ##### No Wallet or GUI -``` bash -./autogen.sh -./configure --without-wallet --with-gui=no MAKE=gmake +```bash +cmake -B build -DENABLE_WALLET=OFF ``` ### 2. Compile -**Important**: Use `gmake` (the non-GNU `make` will exit with an error). ```bash -gmake # use "-j N" for N parallel jobs -gmake check # Run tests if Python 3 is available +cmake --build build # Use "-j N" for N parallel jobs. +ctest --test-dir build # Use "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. ``` diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index 5f54fd6d9a..63bfbd61db 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -12,8 +12,7 @@ Install the required dependencies the usual way you [install software on NetBSD] The example commands below use `pkgin`. ```bash -pkgin install autoconf automake libtool pkg-config git gmake boost-headers libevent - +pkgin install git cmake pkg-config boost-headers libevent ``` NetBSD currently ships with an older version of `gcc` than is needed to build. You should upgrade your `gcc` and then pass this new version to the configure script. @@ -25,10 +24,10 @@ pkgin install gcc12 Then, when configuring, pass the following: ```bash -./configure +cmake -B build ... - CC="/usr/pkg/gcc12/bin/gcc" \ - CXX="/usr/pkg/gcc12/bin/g++" \ + -DCMAKE_C_COMPILER="/usr/pkg/gcc12/bin/gcc" \ + -DCMAKE_CXX_COMPILER="/usr/pkg/gcc12/bin/g++" \ ... ``` @@ -65,19 +64,26 @@ pkgin install db4 ``` #### GUI Dependencies +###### Qt5 -Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, Qt 5 is required. +Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install +the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if you don't intend to use the GUI. ```bash pkgin install qt5-qtbase qt5-qttools ``` -The GUI can encode addresses in a QR Code. To build in QR support for the GUI, install `qrencode`. +###### libqrencode + +The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run: ```bash pkgin install qrencode ``` +Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` option to disable this feature in order to compile the GUI. + + #### Test Suite Dependencies There is an included test suite that is useful for testing code changes when developing. @@ -89,28 +95,22 @@ pkgin install python39 ### Building Bitcoin Core -**Note**: Use `gmake` (the non-GNU `make` will exit with an error). - - ### 1. Configuration There are many ways to configure Bitcoin Core. Here is an example that explicitly disables the wallet and GUI: ```bash -./autogen.sh -./configure --without-wallet --with-gui=no \ - CPPFLAGS="-I/usr/pkg/include" \ - MAKE=gmake +cmake -B build -DENABLE_WALLET=OFF -DBUILD_GUI=OFF ``` -For a full list of configuration options, see the output of `./configure --help` +Run `cmake -B build -LH` to see the full list of available options. ### 2. Compile Build and run the tests: ```bash -gmake # use "-j N" here for N parallel jobs -gmake check # Run tests if Python 3 is available +cmake --build build # Use "-j N" for N parallel jobs. +ctest --test-dir build # Use "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. ``` diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index 264d5f2d08..908b750a8f 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -10,9 +10,7 @@ This guide describes how to build bitcoind, command-line utilities, and GUI on O Run the following as root to install the base dependencies for building. ```bash -pkg_add bash git gmake libevent libtool boost -# Select the newest version of the following packages: -pkg_add autoconf automake python +pkg_add git cmake boost libevent ``` See [dependencies.md](dependencies.md) for a complete overview. @@ -31,7 +29,7 @@ It is not necessary to build wallet functionality to run either `bitcoind` or `b ###### Descriptor Wallet Support -`sqlite3` is required to support [descriptor wallets](descriptors.md). +SQLite is required to support [descriptor wallets](descriptors.md). ``` bash pkg_add sqlite3 @@ -46,67 +44,82 @@ from ports. However you can build it yourself, [using depends](/depends). Refer to [depends/README.md](/depends/README.md) for detailed instructions. ```bash -gmake -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 +gmake -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 ... -to: /path/to/bitcoin/depends/x86_64-unknown-openbsd +to: /path/to/bitcoin/depends/*-unknown-openbsd* ``` Then set `BDB_PREFIX`: ```bash -export BDB_PREFIX="/path/to/bitcoin/depends/x86_64-unknown-openbsd" +export BDB_PREFIX="[path displayed above]" ``` #### GUI Dependencies ###### Qt5 -Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, Qt 5 is required. +Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install +the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if you don't intend to use the GUI. ```bash pkg_add qtbase qttools ``` -## Building Bitcoin Core +###### libqrencode + +The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run: + +```bash +pkg_add libqrencode +``` + +Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` option to disable this feature in order to compile the GUI. -**Important**: Use `gmake` (the non-GNU `make` will exit with an error). +--- -Preparation: +#### Notifications +###### ZeroMQ + +Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in. ```bash +pkg_add zeromq +``` -# Adapt the following for the version you installed (major.minor only): -export AUTOCONF_VERSION=2.71 -export AUTOMAKE_VERSION=1.16 +#### Test Suite Dependencies +There is an included test suite that is useful for testing code changes when developing. +To run the test suite (recommended), you will need to have Python 3 installed: -./autogen.sh +```bash +pkg_add python # Select the newest version of the package. ``` +## Building Bitcoin Core + ### 1. Configuration There are many ways to configure Bitcoin Core, here are a few common examples: ##### Descriptor Wallet and GUI: -This enables the GUI and descriptor wallet support, assuming `sqlite` and `qt5` are installed. +This enables descriptor wallet support and the GUI, assuming SQLite and Qt 5 are installed. ```bash -./configure MAKE=gmake +cmake -B build -DWITH_SQLITE=ON -DBUILD_GUI=ON ``` +Run `cmake -B build -LH` to see the full list of available options. + ##### Descriptor & Legacy Wallet. No GUI: -This enables support for both wallet types and disables the GUI: +This enables support for both wallet types: ```bash -./configure --with-gui=no \ - BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ - BDB_CFLAGS="-I${BDB_PREFIX}/include" \ - MAKE=gmake +cmake -B build -DBerkeleyDB_INCLUDE_DIR:PATH="${BDB_PREFIX}/include" -DWITH_BDB=ON ``` ### 2. Compile -**Important**: Use `gmake` (the non-GNU `make` will exit with an error). ```bash -gmake # use "-j N" for N parallel jobs -gmake check # Run tests if Python 3 is available +cmake --build build # Use "-j N" for N parallel jobs. +ctest --test-dir build # Use "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. ``` ## Resource limits diff --git a/doc/build-osx.md b/doc/build-osx.md index 20c92ab7a4..cb8e82dae8 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -1,15 +1,15 @@ # macOS Build Guide -**Updated for MacOS [11.2](https://www.apple.com/macos/big-sur/)** +**Updated for MacOS [15](https://www.apple.com/macos/macos-sequoia/)** -This guide describes how to build bitcoind, command-line utilities, and GUI on macOS +This guide describes how to build bitcoind, command-line utilities, and GUI on macOS. ## Preparation The commands in this guide should be executed in a Terminal application. macOS comes with a built-in Terminal located in: -``` +```bash /Applications/Utilities/Terminal.app ``` @@ -48,23 +48,9 @@ See [dependencies.md](dependencies.md) for a complete overview. To install, run the following from your terminal: ``` bash -brew install automake libtool boost pkg-config libevent -``` - -For macOS 11 (Big Sur) and 12 (Monterey) you need to install a more recent version of llvm. - -``` bash -brew install llvm +brew install cmake boost pkg-config libevent ``` -And append the following to the configure commands below: - -``` bash -CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ -``` - -Try `llvm@17` if compilation fails with the default version of llvm. - ### 4. Clone Bitcoin repository `git` should already be installed by default on your system. @@ -102,9 +88,8 @@ brew install berkeley-db@4 ###### Qt -Bitcoin Core includes a GUI built with the cross-platform Qt Framework. -To compile the GUI, we need to install `qt@5`. -Skip if you don't intend to use the GUI. +Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install +Qt, libqrencode and pass `-DBUILD_GUI=ON`. Skip if you don't intend to use the GUI. ``` bash brew install qt@5 @@ -113,14 +98,16 @@ brew install qt@5 Note: Building with Qt binaries downloaded from the Qt website is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714). -###### qrencode +###### libqrencode -The GUI can encode addresses in a QR Code. To build in QR support for the GUI, install `qrencode`. -Skip if not using the GUI or don't want QR code functionality. +The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run: ``` bash brew install qrencode ``` + +Otherwise, if you don't need QR encoding support, you can pass `-DWITH_QRENCODE=OFF` to disable this feature. + --- #### Port Mapping Dependencies @@ -134,18 +121,6 @@ Skip if you do not need this functionality. brew install miniupnpc ``` -###### libnatpmp - -libnatpmp may be used for NAT-PMP port mapping. -Skip if you do not need this functionality. - -``` bash -brew install libnatpmp -``` - -Note: UPnP and NAT-PMP support will be compiled in and disabled by default. -Check out the [further configuration](#further-configuration) section for more information. - --- #### ZMQ Dependencies @@ -157,7 +132,6 @@ Skip if you do not need ZMQ functionality. brew install zeromq ``` -ZMQ is automatically compiled in and enabled if the dependency is detected. Check out the [further configuration](#further-configuration) section for more information. For more information on ZMQ, see: [zmq.md](zmq.md) @@ -177,7 +151,7 @@ brew install python #### Deploy Dependencies -You can deploy a `.zip` containing the Bitcoin Core application using `make deploy`. +You can [deploy](#3-deploy-optional) a `.zip` containing the Bitcoin Core application. It is required that you have `python` installed. ## Building Bitcoin Core @@ -188,32 +162,25 @@ There are many ways to configure Bitcoin Core, here are a few common examples: ##### Wallet (BDB + SQlite) Support, No GUI: -If `berkeley-db@4` is installed, then legacy wallet support will be built. -If `sqlite` is installed, then descriptor wallet support will also be built. -Additionally, this explicitly disables the GUI. +If `berkeley-db@4` or `sqlite` are not installed, this will throw an error. ``` bash -./autogen.sh -./configure --with-gui=no +cmake -B build -DWITH_BDB=ON ``` ##### Wallet (only SQlite) and GUI Support: -This explicitly enables the GUI and disables legacy wallet support. -If `qt` is not installed, this will throw an error. -If `sqlite` is installed then descriptor wallet functionality will be built. -If `sqlite` is not installed, then wallet functionality will be disabled. +This enables the GUI. +If `sqlite` or `qt` are not installed, this will throw an error. ``` bash -./autogen.sh -./configure --without-bdb --with-gui=yes +cmake -B build -DBUILD_GUI=ON ``` ##### No Wallet or GUI ``` bash -./autogen.sh -./configure --without-wallet --with-gui=no +cmake -B build -DENABLE_WALLET=OFF ``` ##### Further Configuration @@ -222,7 +189,7 @@ You may want to dig deeper into the configuration options to achieve your desire Examine the output of the following command for a full list of configuration options: ``` bash -./configure -help +cmake -B build -LH ``` ### 2. Compile @@ -231,8 +198,8 @@ After configuration, you are ready to compile. Run the following in your terminal to compile Bitcoin Core: ``` bash -make # use "-j N" here for N parallel jobs -make check # Run tests if Python 3 is available +cmake --build build # Use "-j N" here for N parallel jobs. +ctest --test-dir build # Use "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. ``` ### 3. Deploy (optional) @@ -240,13 +207,13 @@ make check # Run tests if Python 3 is available You can also create a `.zip` containing the `.app` bundle by running the following command: ``` bash -make deploy +cmake --build build --target deploy ``` ## Running Bitcoin Core -Bitcoin Core should now be available at `./src/bitcoind`. -If you compiled support for the GUI, it should be available at `./src/qt/bitcoin-qt`. +Bitcoin Core should now be available at `./build/src/bitcoind`. +If you compiled support for the GUI, it should be available at `./build/src/qt/bitcoin-qt`. The first time you run `bitcoind` or `bitcoin-qt`, it will start downloading the blockchain. This process could take many hours, or even days on slower than average systems. @@ -276,8 +243,8 @@ tail -f $HOME/Library/Application\ Support/Bitcoin/debug.log ## Other commands: ```shell -./src/bitcoind -daemon # Starts the bitcoin daemon. -./src/bitcoin-cli --help # Outputs a list of command-line options. -./src/bitcoin-cli help # Outputs a list of RPC commands when the daemon is running. -./src/qt/bitcoin-qt -server # Starts the bitcoin-qt server mode, allows bitcoin-cli control +./build/src/bitcoind -daemon # Starts the bitcoin daemon. +./build/src/bitcoin-cli --help # Outputs a list of command-line options. +./build/src/bitcoin-cli help # Outputs a list of RPC commands when the daemon is running. +./build/src/qt/bitcoin-qt -server # Starts the bitcoin-qt server mode, allows bitcoin-cli control ``` diff --git a/doc/build-unix.md b/doc/build-unix.md index de54fb4eeb..086731be5a 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -8,10 +8,9 @@ To Build --------------------- ```bash -./autogen.sh -./configure -make # use "-j N" for N parallel jobs -make install # optional +cmake -B build +cmake --build build # use "-j N" for N parallel jobs +cmake --install build # optional ``` See below for instructions on how to [install the dependencies on popular Linux @@ -22,19 +21,20 @@ distributions](#linux-distribution-specific-instructions), or the C++ compilers are memory-hungry. It is recommended to have at least 1.5 GB of memory available when compiling Bitcoin Core. On systems with less, gcc can be -tuned to conserve memory with additional CXXFLAGS: +tuned to conserve memory with additional `CMAKE_CXX_FLAGS`: - ./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" + cmake -B build -DCMAKE_CXX_FLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" -Alternatively, or in addition, debugging information can be skipped for compilation. The default compile flags are -`-g -O2`, and can be changed with: +Alternatively, or in addition, debugging information can be skipped for compilation. +For the default build type `RelWithDebInfo`, the default compile flags are +`-O2 -g`, and can be changed with: - ./configure CXXFLAGS="-g0" + cmake -B build -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O2 -g0" Finally, clang (often less resource hungry) can be used instead of gcc, which is used by default: - ./configure CXX=clang++ CC=clang + cmake -B build -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang ## Linux Distribution Specific Instructions @@ -44,7 +44,7 @@ Finally, clang (often less resource hungry) can be used instead of gcc, which is Build requirements: - sudo apt-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 + sudo apt-get install build-essential cmake pkg-config python3 Now, you can either build from self-compiled [depends](#dependencies) or install the required dependencies: @@ -56,14 +56,13 @@ SQLite is required for the descriptor wallet: Berkeley DB is only required for the legacy wallet. Ubuntu and Debian have their own `libdb-dev` and `libdb++-dev` packages, but these will install Berkeley DB 5.3 or later. This will break binary wallet compatibility with the distributed -executables, which are based on BerkeleyDB 4.8. If you do not care about wallet compatibility, pass -`--with-incompatible-bdb` to configure. Otherwise, you can build Berkeley DB [yourself](#berkeley-db). +executables, which are based on BerkeleyDB 4.8. Otherwise, you can build Berkeley DB [yourself](#berkeley-db). To build Bitcoin Core without wallet, see [*Disable-wallet mode*](#disable-wallet-mode) -Optional port mapping libraries (see: `--with-miniupnpc` and `--with-natpmp`): +Optional port mapping library (see: `-DWITH_MINIUPNPC=ON`): - sudo apt install libminiupnpc-dev libnatpmp-dev + sudo apt install libminiupnpc-dev ZMQ dependencies (provides ZMQ API): @@ -75,11 +74,8 @@ User-Space, Statically Defined Tracing (USDT) dependencies: GUI dependencies: -If you want to build bitcoin-qt, make sure that the required packages for Qt development -are installed. Qt 5 is necessary to build the GUI. -To build without GUI pass `--without-gui`. - -To build with Qt 5 you need the following: +Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install +the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if you don't intend to use the GUI. sudo apt-get install qtbase5-dev qttools5-dev qttools5-dev-tools @@ -87,12 +83,11 @@ Additionally, to support Wayland protocol for modern desktop environments: sudo apt install qtwayland5 -libqrencode (optional) can be installed with: +The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run: sudo apt-get install libqrencode-dev -Once these are installed, they will be found by configure and a bitcoin-qt executable will be -built by default. +Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` option to disable this feature in order to compile the GUI. ### Fedora @@ -101,7 +96,7 @@ built by default. Build requirements: - sudo dnf install gcc-c++ libtool make autoconf automake python3 + sudo dnf install gcc-c++ cmake make python3 Now, you can either build from self-compiled [depends](#dependencies) or install the required dependencies: @@ -113,14 +108,13 @@ SQLite is required for the descriptor wallet: Berkeley DB is only required for the legacy wallet. Fedora releases have only `libdb-devel` and `libdb-cxx-devel` packages, but these will install Berkeley DB 5.3 or later. This will break binary wallet compatibility with the distributed executables, which -are based on Berkeley DB 4.8. If you do not care about wallet compatibility, -pass `--with-incompatible-bdb` to configure. Otherwise, you can build Berkeley DB [yourself](#berkeley-db). +are based on Berkeley DB 4.8. Otherwise, you can build Berkeley DB [yourself](#berkeley-db). To build Bitcoin Core without wallet, see [*Disable-wallet mode*](#disable-wallet-mode) -Optional port mapping libraries (see: `--with-miniupnpc` and `--with-natpmp`): +Optional port mapping library (see: `-DWITH_MINIUPNPC=ON`): - sudo dnf install miniupnpc-devel libnatpmp-devel + sudo dnf install miniupnpc-devel ZMQ dependencies (provides ZMQ API): @@ -132,11 +126,8 @@ User-Space, Statically Defined Tracing (USDT) dependencies: GUI dependencies: -If you want to build bitcoin-qt, make sure that the required packages for Qt development -are installed. Qt 5 is necessary to build the GUI. -To build without GUI pass `--without-gui`. - -To build with Qt 5 you need the following: +Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install +the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if you don't intend to use the GUI. sudo dnf install qt5-qttools-devel qt5-qtbase-devel @@ -144,12 +135,11 @@ Additionally, to support Wayland protocol for modern desktop environments: sudo dnf install qt5-qtwayland -libqrencode (optional) can be installed with: +The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run: sudo dnf install qrencode-devel -Once these are installed, they will be found by configure and a bitcoin-qt executable will be -built by default. +Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` option to disable this feature in order to compile the GUI. ## Dependencies @@ -163,7 +153,7 @@ The legacy wallet uses Berkeley DB. To ensure backwards compatibility it is recommended to use Berkeley DB 4.8. If you have to build it yourself, and don't want to use any other libraries built in depends, you can do: ```bash -make -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 +make -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 ... to: /path/to/bitcoin/depends/x86_64-pc-linux-gnu ``` @@ -171,9 +161,7 @@ and configure using the following: ```bash export BDB_PREFIX="/path/to/bitcoin/depends/x86_64-pc-linux-gnu" -./configure \ - BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ - BDB_CFLAGS="-I${BDB_PREFIX}/include" +cmake -B build -DBerkeleyDB_INCLUDE_DIR:PATH="${BDB_PREFIX}/include" -DWITH_BDB=ON ``` **Note**: Make sure that `BDB_PREFIX` is an absolute path. @@ -185,7 +173,7 @@ Disable-wallet mode When the intention is to only run a P2P node, without a wallet, Bitcoin Core can be compiled in disable-wallet mode with: - ./configure --disable-wallet + cmake -B build -DENABLE_WALLET=OFF In this case there is no dependency on SQLite or Berkeley DB. @@ -195,19 +183,19 @@ Additional Configure Flags -------------------------- A list of additional configure flags can be displayed with: - ./configure --help + cmake -B build -LH Setup and Build Example: Arch Linux ----------------------------------- This example lists the steps necessary to setup and build a command line only distribution of the latest changes on Arch Linux: - pacman --sync --needed autoconf automake boost gcc git libevent libtool make pkgconf python sqlite + pacman --sync --needed cmake boost gcc git libevent make pkgconf python sqlite git clone https://github.com/bitcoin/bitcoin.git cd bitcoin/ - ./autogen.sh - ./configure - make check - ./src/bitcoind + cmake -B build + cmake --build build + ctest --test-dir build + ./build/src/bitcoind If you intend to work with legacy Berkeley DB wallets, see [Berkeley DB](#berkeley-db) section. diff --git a/doc/build-windows-msvc.md b/doc/build-windows-msvc.md new file mode 100644 index 0000000000..80c2b77f1e --- /dev/null +++ b/doc/build-windows-msvc.md @@ -0,0 +1,86 @@ +# Windows / MSVC Build Guide + +This guide describes how to build bitcoind, command-line utilities, and GUI on Windows using Microsoft Visual Studio. + +For cross-compiling options, please see [`build-windows.md`](./build-windows.md). + +## Preparation + +### 1. Visual Studio + +This guide relies on using CMake and vcpkg package manager provided with the Visual Studio installation. +Here are requirements for the Visual Studio installation: +1. Minimum required version: Visual Studio 2022 version 17.6. +2. Installed components: +- The "Desktop development with C++" workload. + +The commands in this guide should be executed in "Developer PowerShell for VS 2022" or "Developer Command Prompt for VS 2022". +The former is assumed hereinafter. + +### 2. Git + +Download and install [Git for Windows](https://git-scm.com/download/win). Once installed, Git is available from PowerShell or the Command Prompt. + +### 3. Clone Bitcoin Repository + +Clone the Bitcoin Core repository to a directory. All build scripts and commands will run from this directory. +``` +git clone https://github.com/bitcoin/bitcoin.git +``` + + +## Triplets and Presets + +The Bitcoin Core project supports the following vcpkg triplets: +- `x64-windows` (both CRT and library linkage is dynamic) +- `x64-windows-static` (both CRT and library linkage is static) + +To facilitate build process, the Bitcoin Core project provides presets, which are used in this guide. + +Available presets can be listed as follows: +``` +cmake --list-presets +``` + +By default, all presets: +- Set `BUILD_GUI` to `ON`. +- Set `WITH_QRENCODE` to `OFF`, due to known build issues when using vcpkg's `libqrencode` package. + +## Building + +CMake will put the resulting object files, libraries, and executables into a dedicated build directory. + +In the following instructions, the "Debug" configuration can be specified instead of the "Release" one. + +### 4. Building with Static Linking with GUI + +``` +cmake -B build --preset vs2022-static # It might take a while if the vcpkg binary cache is unpopulated or invalidated. +cmake --build build --config Release # Use "-j N" for N parallel jobs. +ctest --test-dir build --build-config Release # Use "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +cmake --install build --config Release # Optional. +``` + +### 5. Building with Dynamic Linking without GUI + +``` +cmake -B build --preset vs2022 -DBUILD_GUI=OFF # It might take a while if the vcpkg binary cache is unpopulated or invalidated. +cmake --build build --config Release # Use "-j N" for N parallel jobs. +ctest --test-dir build --build-config Release # Use "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +``` + +## Performance Notes + +### 6. vcpkg Manifest Default Features + +One can skip vcpkg manifest default features to speedup the configuration step. +For example, the following invocation will skip all features except for "wallet" and "tests" and their dependencies: +``` +cmake -B build --preset vs2022 -DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON -DVCPKG_MANIFEST_FEATURES="wallet;tests" -DBUILD_GUI=OFF +``` + +Available features are listed in the [`vcpkg.json`](/vcpkg.json) file. + +### 7. Antivirus Software + +To improve the build process performance, one might add the Bitcoin repository directory to the Microsoft Defender Antivirus exclusions. diff --git a/doc/build-windows.md b/doc/build-windows.md index 841693c77b..0c1418bff9 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -7,12 +7,15 @@ The options known to work for building Bitcoin Core on Windows are: * On Linux, using the [Mingw-w64](https://www.mingw-w64.org/) cross compiler tool chain. * On Windows, using [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/about) and Mingw-w64. -* On Windows, using [Microsoft Visual Studio](https://visualstudio.microsoft.com). See [README.md](/build_msvc/README.md). +* On Windows, using [Microsoft Visual Studio](https://visualstudio.microsoft.com). See [`build-windows-msvc.md`](./build-windows-msvc.md). Other options which may work, but which have not been extensively tested are (please contribute instructions): * 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 --------------------------------------- @@ -25,56 +28,27 @@ The steps below can be performed on Ubuntu or WSL. The depends system will also work on other Linux distributions, however the commands for installing the toolchain will be different. -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 - -A host toolchain (`build-essential`) is necessary because some dependency -packages need to build host utilities that are used in the build process. +See [README.md](../depends/README.md) in the depends directory for which +dependencies to install and [dependencies.md](dependencies.md) for a complete overview. -See [dependencies.md](dependencies.md) for a complete overview. +If you want to build the Windows installer using the `deploy` build target, you will need [NSIS](https://nsis.sourceforge.io/Main_Page): -If you want to build the windows installer with `make deploy` you need [NSIS](https://nsis.sourceforge.io/Main_Page): - - sudo apt install nsis + apt install nsis Acquire the source in the usual way: git clone https://github.com/bitcoin/bitcoin.git cd bitcoin -## Building for 64-bit Windows - -The first step is to install the mingw-w64 cross-compilation tool chain: - -```sh -sudo apt install g++-mingw-w64-x86-64-posix -``` - -Once the toolchain is installed the build steps are common: - Note that for WSL the Bitcoin Core source path MUST be somewhere in the default mount file system, for example /usr/src/bitcoin, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail. This means you cannot use a directory that is located directly on the host Windows file system to perform the build. -Additional WSL Note: WSL support for [launching Win32 applications](https://learn.microsoft.com/en-us/archive/blogs/wsl/windows-and-ubuntu-interoperability#launching-win32-applications-from-within-wsl) -results in `Autoconf` configure scripts being able to execute Windows Portable Executable files. This can cause -unexpected behaviour during the build, such as Win32 error dialogs for missing libraries. The recommended approach -is to temporarily disable WSL support for Win32 applications. - 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 - cd .. - ./autogen.sh - CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/ - make # use "-j N" for N parallel jobs - sudo bash -c "echo 1 > /proc/sys/fs/binfmt_misc/status" # Enable WSL support for Win32 applications. + gmake -C depends HOST=x86_64-w64-mingw32 # Use "-j N" for N parallel jobs. + cmake -B build --toolchain depends/x86_64-w64-mingw32/toolchain.cmake + cmake --build build # Use "-j N" for N parallel jobs. ## Depends system @@ -88,8 +62,8 @@ executables to a directory on the Windows drive in the same directory structure as they appear in the release `.zip` archive. This can be done in the following way. This will install to `c:\workspace\bitcoin`, for example: - make install DESTDIR=/mnt/c/workspace/bitcoin + cmake --install build --prefix /mnt/c/workspace/bitcoin You can also create an installer using: - make deploy + cmake --build build --target deploy diff --git a/doc/dependencies.md b/doc/dependencies.md index 2b9d9128d3..a3d42fc281 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -6,11 +6,10 @@ You can find installation instructions in the `build-*.md` file for your platfor | Dependency | Minimum required | | --- | --- | -| [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) | +| [CMake](https://cmake.org/) | [3.22](https://github.com/bitcoin/bitcoin/pull/30454) | | [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) | +| [Python](https://www.python.org) (scripts, tests) | [3.10](https://github.com/bitcoin/bitcoin/pull/30527) | | [systemtap](https://sourceware.org/systemtap/) ([tracing](tracing.md))| N/A | ## Required @@ -19,7 +18,7 @@ You can find installation instructions in the `build-*.md` file for your platfor | --- | --- | --- | --- | --- | | [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.81.0](https://github.com/bitcoin/bitcoin/pull/26557) | [1.73.0](https://github.com/bitcoin/bitcoin/pull/29066) | No | | [libevent](../depends/packages/libevent.mk) | [link](https://github.com/libevent/libevent/releases) | [2.1.12-stable](https://github.com/bitcoin/bitcoin/pull/21991) | [2.1.8](https://github.com/bitcoin/bitcoin/pull/24681) | No | -| glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.27](https://github.com/bitcoin/bitcoin/pull/27029) | Yes | +| glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.31](https://github.com/bitcoin/bitcoin/pull/29987) | Yes | | Linux Kernel | [link](https://www.kernel.org/) | N/A | [3.17.0](https://github.com/bitcoin/bitcoin/pull/27699) | Yes | ## Optional @@ -30,12 +29,11 @@ You can find installation instructions in the `build-*.md` file for your platfor | [Fontconfig](../depends/packages/fontconfig.mk) | [link](https://www.freedesktop.org/wiki/Software/fontconfig/) | [2.12.6](https://github.com/bitcoin/bitcoin/pull/23495) | 2.6 | Yes | | [FreeType](../depends/packages/freetype.mk) | [link](https://freetype.org) | [2.11.0](https://github.com/bitcoin/bitcoin/commit/01544dd78ccc0b0474571da854e27adef97137fb) | 2.3.0 | Yes | | [qrencode](../depends/packages/qrencode.mk) | [link](https://fukuchi.org/works/qrencode/) | [4.1.1](https://github.com/bitcoin/bitcoin/pull/27312) | | No | -| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.13](https://github.com/bitcoin/bitcoin/pull/29732) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No | +| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.14](https://github.com/bitcoin/bitcoin/pull/30198) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No | ### Networking | Dependency | Releases | Version used | Minimum required | Runtime | | --- | --- | --- | --- | --- | -| [libnatpmp](../depends/packages/libnatpmp.mk) | [link](https://github.com/miniupnp/libnatpmp/) | commit [f2433be...](https://github.com/bitcoin/bitcoin/pull/29708) | | No | | [MiniUPnPc](../depends/packages/miniupnpc.mk) | [link](https://miniupnp.tuxfamily.org/) | [2.2.7](https://github.com/bitcoin/bitcoin/pull/29707) | 2.1 | No | ### Notifications diff --git a/doc/descriptors.md b/doc/descriptors.md index 3b94ec03e4..8c55d4ae37 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 @@ -97,6 +98,7 @@ Descriptors consist of several types of expressions. The top level expression is - [WIF](https://en.bitcoin.it/wiki/Wallet_import_format) encoded private keys may be specified instead of the corresponding public key, with the same meaning. - `xpub` encoded extended public key or `xprv` encoded extended private key (as defined in [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)). - Followed by zero or more `/NUM` unhardened and `/NUM'` hardened BIP32 derivation steps. + - No more than one of these derivation steps may be of the form `<NUM;NUM;...;NUM>` (including hardened indicators with either or both `NUM`). If such specifiers are included, the descriptor will be parsed as multiple descriptors where the first descriptor uses all of the first `NUM` in the pair, and the second descriptor uses the second `NUM` in the pair for all `KEY` expressions, and so on. - Optionally followed by a single `/*` or `/*'` final step to denote all (direct) unhardened or hardened children. - The usage of hardened derivation steps requires providing the private key. @@ -167,9 +169,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 @@ -256,6 +258,30 @@ Note how the first key is an xprv private key with a specific derivation path, while the other two are public keys. +### Specifying receiving and change descriptors in one descriptor + +Since receiving and change addresses are frequently derived from the same +extended key(s) but with a single derivation index changed, it is convenient +to be able to specify a descriptor that can derive at the two different +indexes. Thus a single tuple of indexes is allowed in each derivation path +following the extended key. When this descriptor is parsed, multiple descriptors +will be produced, the first one will use the first index in the tuple for all +key expressions, the second will use the second index, the third will use the +third index, and so on.. + +For example, a descriptor of the form: + + multi(2,xpub.../<0;1;2>/0/*,xpub.../<2;3;4>/*) + +will expand to the two descriptors + + multi(2,xpub.../0/0/*,xpub.../2/*) + multi(2,xpub.../1/0/*,xpub.../3/*) + multi(2,xpub.../2/0/*,xpub.../4*) + +When this tuple contains only two elements, wallet implementations can use the +first descriptor for receiving addresses and the second descriptor for change addresses. + ### Compatibility with old wallets In order to easily represent the sets of scripts currently supported by diff --git a/doc/design/assumeutxo.md b/doc/design/assumeutxo.md index a4980729d0..123c02ac13 100644 --- a/doc/design/assumeutxo.md +++ b/doc/design/assumeutxo.md @@ -1,47 +1,6 @@ -# assumeutxo +# Assumeutxo Design -Assumeutxo is a feature that allows fast bootstrapping of a validating bitcoind -instance. - -## Loading a snapshot - -There is currently no canonical source for snapshots, but any downloaded snapshot -will be checked against a hash that's been hardcoded in source code. - -Once you've obtained the snapshot, you can use the RPC command `loadtxoutset` to -load it. - -### Pruning - -A pruned node can load a snapshot. To save space, it's possible to delete the -snapshot file as soon as `loadtxoutset` finishes. - -The minimum `-prune` setting is 550 MiB, but this functionality ignores that -minimum and uses at least 1100 MiB. - -As the background sync continues there will be temporarily two chainstate -directories, each multiple gigabytes in size (likely growing larger than the -downloaded snapshot). - -### Indexes - -Indexes work but don't take advantage of this feature. They always start building -from the genesis block. Once the background validation reaches the snapshot block, -indexes will continue to build all the way to the tip. - -For indexes that support pruning, note that no pruning will take place between -the snapshot and the tip, until the background sync has completed - after which -everything is pruned. Depending on how old the snapshot is, this may temporarily -use a significant amount of disk space. - -## Generating a snapshot - -The RPC command `dumptxoutset` can be used to generate a snapshot. This can be used -to create a snapshot on one node that you wish to load on another node. -It can also be used to verify the hardcoded snapshot hash in the source code. - -The utility script -`./contrib/devtools/utxo_snapshot.sh` may be of use. +For notes on the usage of Assumeutxo, please refer to [the usage doc](/doc/assumeutxo.md). ## General background @@ -79,7 +38,7 @@ data. ### "Normal" operation via initial block download `ChainstateManager` manages a single Chainstate object, for which -`m_snapshot_blockhash` is null. This chainstate is (maybe obviously) +`m_from_snapshot_blockhash` is `std::nullopt`. This chainstate is (maybe obviously) considered active. This is the "traditional" mode of operation for bitcoind. | | | diff --git a/doc/design/libraries.md b/doc/design/libraries.md index 251c52199d..24185bf477 100644 --- a/doc/design/libraries.md +++ b/doc/design/libraries.md @@ -4,10 +4,11 @@ |--------------------------|-------------| | *libbitcoin_cli* | RPC client functionality used by *bitcoin-cli* executable | | *libbitcoin_common* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_util*, but higher-level (see [Dependencies](#dependencies)). | -| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet*. | +| *libbitcoin_consensus* | Consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet*. | +| *libbitcoin_crypto* | Hardware-optimized functions for data encryption, hashing, message authentication, and key derivation. | | *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. | | *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. | -| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. | +| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`-DWITH_MULTIPROCESS=ON`](multiprocess.md) is used. | | *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. | | *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). | | *libbitcoin_wallet* | Wallet functionality used by *bitcoind* and *bitcoin-wallet* executables. | @@ -18,7 +19,7 @@ - Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. An exception is *libbitcoin_kernel*, which, at some future point, will have a documented external interface. -- Generally each library should have a corresponding source directory and namespace. Source code organization is a work in progress, so it is true that some namespaces are applied inconsistently, and if you look at [`libbitcoin_*_SOURCES`](../../src/Makefile.am) lists you can see that many libraries pull in files from outside their source directory. But when working with libraries, it is good to follow a consistent pattern like: +- Generally each library should have a corresponding source directory and namespace. Source code organization is a work in progress, so it is true that some namespaces are applied inconsistently, and if you look at [`add_library(bitcoin_* ...)`](../../src/CMakeLists.txt) lists you can see that many libraries pull in files from outside their source directory. But when working with libraries, it is good to follow a consistent pattern like: - *libbitcoin_node* code lives in `src/node/` in the `node::` namespace - *libbitcoin_wallet* code lives in `src/wallet/` in the `wallet::` namespace @@ -53,13 +54,18 @@ bitcoin-wallet[bitcoin-wallet]-->libbitcoin_wallet_tool; libbitcoin_cli-->libbitcoin_util; libbitcoin_cli-->libbitcoin_common; +libbitcoin_consensus-->libbitcoin_crypto; + libbitcoin_common-->libbitcoin_consensus; +libbitcoin_common-->libbitcoin_crypto; libbitcoin_common-->libbitcoin_util; libbitcoin_kernel-->libbitcoin_consensus; +libbitcoin_kernel-->libbitcoin_crypto; libbitcoin_kernel-->libbitcoin_util; libbitcoin_node-->libbitcoin_consensus; +libbitcoin_node-->libbitcoin_crypto; libbitcoin_node-->libbitcoin_kernel; libbitcoin_node-->libbitcoin_common; libbitcoin_node-->libbitcoin_util; @@ -67,7 +73,10 @@ libbitcoin_node-->libbitcoin_util; libbitcoinqt-->libbitcoin_common; libbitcoinqt-->libbitcoin_util; +libbitcoin_util-->libbitcoin_crypto; + libbitcoin_wallet-->libbitcoin_common; +libbitcoin_wallet-->libbitcoin_crypto; libbitcoin_wallet-->libbitcoin_util; libbitcoin_wallet_tool-->libbitcoin_wallet; @@ -78,26 +87,26 @@ class bitcoin-qt,bitcoind,bitcoin-cli,bitcoin-wallet bold ``` </td></tr><tr><td> -**Dependency graph**. Arrows show linker symbol dependencies. *Consensus* lib depends on nothing. *Util* lib is depended on by everything. *Kernel* lib depends only on consensus and util. +**Dependency graph**. Arrows show linker symbol dependencies. *Crypto* lib depends on nothing. *Util* lib is depended on by everything. *Kernel* lib depends only on consensus, crypto, and util. </td></tr></table> - The graph shows what _linker symbols_ (functions and variables) from each library other libraries can call and reference directly, but it is not a call graph. For example, there is no arrow connecting *libbitcoin_wallet* and *libbitcoin_node* libraries, because these libraries are intended to be modular and not depend on each other's internal implementation details. But wallet code is still able to call node code indirectly through the `interfaces::Chain` abstract class in [`interfaces/chain.h`](../../src/interfaces/chain.h) and node code calls wallet code through the `interfaces::ChainClient` and `interfaces::Chain::Notifications` abstract classes in the same file. In general, defining abstract classes in [`src/interfaces/`](../../src/interfaces/) can be a convenient way of avoiding unwanted direct dependencies or circular dependencies between libraries. -- *libbitcoin_consensus* should be a standalone dependency that any library can depend on, and it should not depend on any other libraries itself. +- *libbitcoin_crypto* should be a standalone dependency that any library can depend on, and it should not depend on any other libraries itself. -- *libbitcoin_util* should also be a standalone dependency that any library can depend on, and it should not depend on other internal libraries. +- *libbitcoin_consensus* should only depend on *libbitcoin_crypto*, and all other libraries besides *libbitcoin_crypto* should be allowed to depend on it. -- *libbitcoin_common* should serve a similar function as *libbitcoin_util* and be a place for miscellaneous code used by various daemon, GUI, and CLI applications and libraries to live. It should not depend on anything other than *libbitcoin_util* and *libbitcoin_consensus*. The boundary between _util_ and _common_ is a little fuzzy but historically _util_ has been used for more generic, lower-level things like parsing hex, and _common_ has been used for bitcoin-specific, higher-level things like parsing base58. The difference between util and common is mostly important because *libbitcoin_kernel* is not supposed to depend on *libbitcoin_common*, only *libbitcoin_util*. In general, if it is ever unclear whether it is better to add code to *util* or *common*, it is probably better to add it to *common* unless it is very generically useful or useful particularly to include in the kernel. +- *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*. -- *libbitcoin_kernel* should only depend on *libbitcoin_util* and *libbitcoin_consensus*. +- *libbitcoin_kernel* should only depend on *libbitcoin_util*, *libbitcoin_consensus*, and *libbitcoin_crypto*. -- The only thing that should depend on *libbitcoin_kernel* internally should be *libbitcoin_node*. GUI and wallet libraries *libbitcoinqt* and *libbitcoin_wallet* in particular should not depend on *libbitcoin_kernel* and the unneeded functionality it would pull in, like block validation. To the extent that GUI and wallet code need scripting and signing functionality, they should be get able it from *libbitcoin_consensus*, *libbitcoin_common*, and *libbitcoin_util*, instead of *libbitcoin_kernel*. +- The only thing that should depend on *libbitcoin_kernel* internally should be *libbitcoin_node*. GUI and wallet libraries *libbitcoinqt* and *libbitcoin_wallet* in particular should not depend on *libbitcoin_kernel* and the unneeded functionality it would pull in, like block validation. To the extent that GUI and wallet code need scripting and signing functionality, they should be get able it from *libbitcoin_consensus*, *libbitcoin_common*, *libbitcoin_crypto*, and *libbitcoin_util*, instead of *libbitcoin_kernel*. - GUI, node, and wallet code internal implementations should all be independent of each other, and the *libbitcoinqt*, *libbitcoin_node*, *libbitcoin_wallet* libraries should never reference each other's symbols. They should only call each other through [`src/interfaces/`](../../src/interfaces/) abstract interfaces. ## 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/design/multiprocess.md b/doc/design/multiprocess.md index 49410a4213..a781da8d1b 100644 --- a/doc/design/multiprocess.md +++ b/doc/design/multiprocess.md @@ -81,7 +81,7 @@ This section describes the major components of the Inter-Process Communication ( - In the generated code, we have C++ client subclasses that inherit from the abstract classes in [`src/interfaces/`](../../src/interfaces/). These subclasses are the workhorses of the IPC mechanism. - They implement all the methods of the interface, marshalling arguments into a structured format, sending them as requests to the IPC server via a UNIX socket, and handling the responses. - These subclasses effectively mask the complexity of IPC, presenting a familiar C++ interface to developers. -- Internally, the client subclasses generated by the `mpgen` tool wrap [client classes generated by Cap'n Proto](https://capnproto.org/cxxrpc.html#clients), and use them to send IPC requests. +- Internally, the client subclasses generated by the `mpgen` tool wrap [client classes generated by Cap'n Proto](https://capnproto.org/cxxrpc.html#clients), and use them to send IPC requests. The Cap'n Proto client classes are low-level, with non-blocking methods that use asynchronous I/O and pass request and response objects, while mpgen client subclasses provide normal C++ methods that block while executing and convert between request/response objects and arguments/return values. ### C++ Server Classes in Generated Code - On the server side, corresponding generated C++ classes receive IPC requests. These server classes are responsible for unmarshalling method arguments, invoking the corresponding methods in the local [`src/interfaces/`](../../src/interfaces/) objects, and creating the IPC response. @@ -94,7 +94,7 @@ This section describes the major components of the Inter-Process Communication ( - **Asynchronous I/O and Thread Management**: The library is also responsible for managing I/O and threading. Particularly, it ensures that IPC requests never block each other and that new threads on either side of a connection can always make client calls. It also manages worker threads on the server side of calls, ensuring that calls from the same client thread always execute on the same server thread (to avoid locking issues and support nested callbacks). ### Type Hooks in [`src/ipc/capnp/*-types.h`](../../src/ipc/capnp/) -- **Custom Type Conversions**: In [`src/ipc/capnp/*-types.h`](../../src/ipc/capnp/), function overloads of two `libmultiprocess` C++ functions, `mp::CustomReadField` and `mp::CustomBuildFields`, are defined. These overloads are used for customizing the conversion of specific C++ types to and from Cap’n Proto types. +- **Custom Type Conversions**: In [`src/ipc/capnp/*-types.h`](../../src/ipc/capnp/), function overloads of `libmultiprocess` C++ functions, `mp::CustomReadField`, `mp::CustomBuildField`, `mp::CustomReadMessage` and `mp::CustomBuildMessage`, are defined. These overloads are used for customizing the conversion of specific C++ types to and from Cap’n Proto types. - **Handling Special Cases**: The `mpgen` tool and `libmultiprocess` library can convert most C++ types to and from Cap’n Proto types automatically, including interface types, primitive C++ types, standard C++ types like `std::vector`, `std::set`, `std::map`, `std::tuple`, and `std::function`, as well as simple C++ structs that consist of aforementioned types and whose fields correspond 1:1 with Cap’n Proto struct fields. For other types, `*-types.h` files provide custom code to convert between C++ and Cap’n Proto data representations. ### Protocol-Agnostic IPC Code in [`src/ipc/`](../../src/ipc/) @@ -197,7 +197,7 @@ sequenceDiagram - Upon receiving the request, the Cap'n Proto dispatching code in the `bitcoin-node` process calls the `getBlockHash` method of the `Chain` [server class](#c-server-classes-in-generated-code). - The server class is automatically generated by the `mpgen` tool from the [`chain.capnp`](https://github.com/ryanofsky/bitcoin/blob/pr/ipc/src/ipc/capnp/chain.capnp) file in [`src/ipc/capnp/`](../../src/ipc/capnp/). - The `getBlockHash` method of the generated `Chain` server subclass in `bitcoin-wallet` receives a Cap’n Proto request object with the `height` parameter, and calls the `getBlockHash` method on its local `Chain` object with the provided `height`. - - When the call returns, it encapsulates the return value in a Cap’n Proto response, which it sends back to the `bitcoin-wallet` process, + - When the call returns, it encapsulates the return value in a Cap’n Proto response, which it sends back to the `bitcoin-wallet` process. 5. **Response and Return** - The `getBlockHash` method of the generated `Chain` client subclass in `bitcoin-wallet` which sent the request now receives the response. @@ -232,7 +232,7 @@ This modularization represents an advancement in Bitcoin Core's architecture, of - **Cap’n Proto struct**: A structured data format used in Cap’n Proto, similar to structs in C++, for organizing and transporting data across different processes. -- **client class (in generated code)**: A C++ class generated from a Cap’n Proto interface which inherits from a Bitcoin core abstract class, and implements each virtual method to send IPC requests to another process. (see also [components section](#c-client-subclasses-in-generated-code)) +- **client class (in generated code)**: A C++ class generated from a Cap’n Proto interface which inherits from a Bitcoin Core abstract class, and implements each virtual method to send IPC requests to another process. (see also [components section](#c-client-subclasses-in-generated-code)) - **IPC (inter-process communication)**: Mechanisms that enable processes to exchange requests and data. diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 7e55962471..952dbc77a0 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -13,7 +13,6 @@ Developer Notes - [Development tips and tricks](#development-tips-and-tricks) - [Compiling for debugging](#compiling-for-debugging) - [Show sources in debugging](#show-sources-in-debugging) - - [Compiling for gprof profiling](#compiling-for-gprof-profiling) - [`debug.log`](#debuglog) - [Signet, testnet, and regtest modes](#signet-testnet-and-regtest-modes) - [DEBUG_LOCKORDER](#debug_lockorder) @@ -215,14 +214,14 @@ int main() To run clang-tidy on Ubuntu/Debian, install the dependencies: ```sh -apt install clang-tidy bear clang +apt install clang-tidy clang ``` -Then, pass clang as compiler to configure, and use bear to produce the `compile_commands.json`: +Configure with clang as the compiler: ```sh -./autogen.sh && ./configure CC=clang CXX=clang++ -make clean && bear --config src/.bear-tidy-config -- make -j $(nproc) +cmake -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON +cmake --build build -j $(nproc) ``` The output is denoised of errors from external dependencies. @@ -230,13 +229,13 @@ The output is denoised of errors from external dependencies. To run clang-tidy on all source files: ```sh -( cd ./src/ && run-clang-tidy -j $(nproc) ) +( cd ./src/ && run-clang-tidy -p ../build -j $(nproc) ) ``` To run clang-tidy on the changed source lines: ```sh -git diff | ( cd ./src/ && clang-tidy-diff -p2 -j $(nproc) ) +git diff | ( cd ./src/ && clang-tidy-diff -p2 -path ../build -j $(nproc) ) ``` Coding Style (Python) @@ -339,11 +338,12 @@ Recommendations: ### Generating Documentation -The documentation can be generated with `make docs` and cleaned up with `make -clean-docs`. The resulting files are located in `doc/doxygen/html`; open -`index.html` in that directory to view the homepage. +Assuming the build directory is named `build`, +the documentation can be generated with `cmake --build build --target docs`. +The resulting files will be located in `build/doc/doxygen/html`; +open `index.html` in that directory to view the homepage. -Before running `make docs`, you'll need to install these dependencies: +Before building the `docs` target, you'll need to install these dependencies: Linux: `sudo apt install doxygen graphviz` @@ -354,8 +354,14 @@ Development tips and tricks ### Compiling for debugging -Run configure with `--enable-debug` to add additional compiler flags that -produce better debugging builds. +When using the default build configuration by running `cmake -B build`, the +`-DCMAKE_BUILD_TYPE` is set to `RelWithDebInfo`. This option adds debug symbols +but also performs some compiler optimizations that may make debugging trickier +as the code may not correspond directly to the source. + +If you need to build exclusively for debugging, set the `-DCMAKE_BUILD_TYPE` +to `Debug` (i.e. `-DCMAKE_BUILD_TYPE=Debug`). You can always check the cmake +build options of an existing build with `ccmake build`. ### Show sources in debugging @@ -386,10 +392,6 @@ ln -s /path/to/project/root/src src 3. Use `debugedit` to modify debug information in the binary. -### Compiling for gprof profiling - -Run configure with the `--enable-gprof` option, then make. - ### `debug.log` If the code is behaving strangely, take a look in the `debug.log` file in the data directory; @@ -416,8 +418,8 @@ see [test/functional/](/test/functional) for tests that run in `-regtest` mode. ### DEBUG_LOCKORDER Bitcoin Core is a multi-threaded application, and deadlocks or other -multi-threading bugs can be very difficult to track down. The `--enable-debug` -configure option adds `-DDEBUG_LOCKORDER` to the compiler flags. This inserts +multi-threading bugs can be very difficult to track down. The `-DCMAKE_BUILD_TYPE=Debug` +build option adds `-DDEBUG_LOCKORDER` to the compiler flags. This inserts run-time checks to keep track of which locks are held and adds warnings to the `debug.log` file if inconsistencies are detected. @@ -427,9 +429,8 @@ Defining `DEBUG_LOCKCONTENTION` adds a "lock" logging category to the logging RPC that, when enabled, logs the location and duration of each lock contention to the `debug.log` file. -The `--enable-debug` configure option adds `-DDEBUG_LOCKCONTENTION` to the -compiler flags. You may also enable it manually for a non-debug build by running -configure with `-DDEBUG_LOCKCONTENTION` added to your CPPFLAGS, +The `-DCMAKE_BUILD_TYPE=Debug` build option adds `-DDEBUG_LOCKCONTENTION` to the +compiler flags. You may also enable it manually by building with `-DDEBUG_LOCKCONTENTION` added to your CPPFLAGS, i.e. `CPPFLAGS="-DDEBUG_LOCKCONTENTION"`, then build and run bitcoind. You can then use the `-debug=lock` configuration option at bitcoind startup or @@ -472,34 +473,43 @@ which includes known Valgrind warnings in our dependencies that cannot be fixed in-tree. Example use: ```shell -$ valgrind --suppressions=contrib/valgrind.supp src/test/test_bitcoin +$ valgrind --suppressions=contrib/valgrind.supp build/src/test/test_bitcoin $ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \ - --show-leak-kinds=all src/test/test_bitcoin --log_level=test_suite -$ valgrind -v --leak-check=full src/bitcoind -printtoconsole -$ ./test/functional/test_runner.py --valgrind + --show-leak-kinds=all build/src/test/test_bitcoin --log_level=test_suite +$ valgrind -v --leak-check=full build/src/bitcoind -printtoconsole +$ ./build/test/functional/test_runner.py --valgrind ``` ### Compiling for test coverage -LCOV can be used to generate a test coverage report based upon `make check` +LCOV can be used to generate a test coverage report based upon `ctest` execution. LCOV must be installed on your system (e.g. the `lcov` package on Debian/Ubuntu). To enable LCOV report generation during test runs: ```shell -./configure --enable-lcov -make -make cov +cmake -B build -DCMAKE_BUILD_TYPE=Coverage +cmake --build build +cmake -P build/Coverage.cmake -# A coverage report will now be accessible at `./test_bitcoin.coverage/index.html`, -# which covers unit tests, and `./total.coverage/index.html`, which covers +# A coverage report will now be accessible at `./build/test_bitcoin.coverage/index.html`, +# which covers unit tests, and `./build/total.coverage/index.html`, which covers # 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. +enabled by setting `LCOV_OPTS="--rc branch_coverage=1"`: + +``` +cmake -DLCOV_OPTS="--rc branch_coverage=1" -P build/Coverage.cmake +``` + +To enable test parallelism: +``` +cmake -DJOBS=$(nproc) -P build/Coverage.cmake +``` ### Performance profiling with perf @@ -550,7 +560,7 @@ See the functional test documentation for how to invoke perf within tests. Bitcoin Core can be compiled with various "sanitizers" enabled, which add instrumentation for issues regarding things like memory safety, thread race conditions, or undefined behavior. This is controlled with the -`--with-sanitizers` configure flag, which should be a comma separated list of +`-DSANITIZERS` cmake build flag, which should be a comma separated list of sanitizers to enable. The sanitizer list should correspond to supported `-fsanitize=` options in your compiler. These sanitizers have runtime overhead, so they are most useful when testing changes or producing debugging builds. @@ -559,16 +569,16 @@ Some examples: ```bash # Enable both the address sanitizer and the undefined behavior sanitizer -./configure --with-sanitizers=address,undefined +cmake -B build -DSANITIZERS=address,undefined # Enable the thread sanitizer -./configure --with-sanitizers=thread +cmake -B build -DSANITIZERS=thread ``` If you are compiling with GCC you will typically need to install corresponding "san" libraries to actually compile with these flags, e.g. libasan for the address sanitizer, libtsan for the thread sanitizer, and libubsan for the -undefined sanitizer. If you are missing required libraries, the configure script +undefined sanitizer. If you are missing required libraries, the build will fail with a linker error when testing the sanitizer flags. The test suite should pass cleanly with the `thread` and `undefined` sanitizers. You @@ -584,7 +594,7 @@ See the CI config for more examples, and upstream documentation for more informa about any additional options. Not all sanitizer options can be enabled at the same time, e.g. trying to build -with `--with-sanitizers=address,thread` will fail in the configure script as +with `-DSANITIZERS=address,thread` will fail in the build as these sanitizers are mutually incompatible. Refer to your compiler manual to learn more about these options and which sanitizers are supported by your compiler. @@ -598,7 +608,6 @@ Additional resources: * [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) * [GCC Instrumentation Options](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html) * [Google Sanitizers Wiki](https://github.com/google/sanitizers/wiki) - * [Issue #12691: Enable -fsanitize flags in Travis](https://github.com/bitcoin/bitcoin/issues/12691) Locking/mutex usage notes ------------------------- @@ -609,7 +618,7 @@ The code is multi-threaded and uses mutexes and the Deadlocks due to inconsistent lock ordering (thread 1 locks `cs_main` and then `cs_wallet`, while thread 2 locks them in the opposite order: result, deadlock as each waits for the other to release its lock) are a problem. Compile with -`-DDEBUG_LOCKORDER` (or use `--enable-debug`) to get lock order inconsistencies +`-DDEBUG_LOCKORDER` (or use `-DCMAKE_BUILD_TYPE=Debug`) to get lock order inconsistencies reported in the `debug.log` file. Re-architecting the core code so there are better-defined interfaces @@ -737,8 +746,6 @@ logging messages. They should be used as follows: useful for debugging and can reasonably be enabled on a production system (that has sufficient free storage space). They will be logged if the program is started with `-debug=category` or `-debug=1`. - Note that `LogPrint(BCLog::CATEGORY, fmt, params...)` is a deprecated - alias for `LogDebug`. - `LogInfo(fmt, params...)` should only be used rarely, e.g. for startup messages or for infrequent and important events such as a new block tip @@ -1054,8 +1061,8 @@ bool Chainstate::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) ``` - Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential - deadlocks are introduced. As of 0.12, this is defined by default when - configuring with `--enable-debug`. + deadlocks are introduced. This is defined by default when + building with `-DCMAKE_BUILD_TYPE=Debug`. - When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of the current scope, so surround the statement and the code that needs the lock @@ -1462,8 +1469,9 @@ independent (node, wallet, GUI), are defined in there are [`interfaces::Chain`](../src/interfaces/chain.h), used by wallet to access the node's latest chain state, [`interfaces::Node`](../src/interfaces/node.h), used by the GUI to control the -node, and [`interfaces::Wallet`](../src/interfaces/wallet.h), used by the GUI -to control an individual wallet. There are also more specialized interface +node, [`interfaces::Wallet`](../src/interfaces/wallet.h), used by the GUI +to control an individual wallet and [`interfaces::Mining`](../src/interfaces/mining.h), +used by RPC to generate block templates. There are also more specialized interface types like [`interfaces::Handler`](../src/interfaces/handler.h) [`interfaces::ChainClient`](../src/interfaces/chain.h) passed to and from various interface methods. 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/fuzzing.md b/doc/fuzzing.md index c9fb918c8f..927b0dc8d5 100644 --- a/doc/fuzzing.md +++ b/doc/fuzzing.md @@ -7,15 +7,17 @@ To quickly get started fuzzing Bitcoin Core using [libFuzzer](https://llvm.org/d ```sh $ git clone https://github.com/bitcoin/bitcoin $ cd bitcoin/ -$ ./autogen.sh -$ CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined +$ cmake --preset=libfuzzer # macOS users: If you have problem with this step then make sure to read "macOS hints for # libFuzzer" on https://github.com/bitcoin/bitcoin/blob/master/doc/fuzzing.md#macos-hints-for-libfuzzer -$ make -$ FUZZ=process_message src/test/fuzz/fuzz +$ cmake --build build_fuzz +$ FUZZ=process_message build_fuzz/src/test/fuzz/fuzz # abort fuzzing using ctrl-c ``` +One can use `--prefix=libfuzzer-nosan` to do the same without common sanitizers enabled. +See [further](#run-without-sanitizers-for-increased-throughput) for more information. + There is also a runner script to execute all fuzz targets. Refer to `./test/fuzz/test_runner.py --help` for more details. @@ -33,7 +35,7 @@ If you specify a corpus directory then any new coverage increasing inputs will b ```sh $ mkdir -p process_message-seeded-from-thin-air/ -$ FUZZ=process_message src/test/fuzz/fuzz process_message-seeded-from-thin-air/ +$ FUZZ=process_message build_fuzz/src/test/fuzz/fuzz process_message-seeded-from-thin-air/ INFO: Seed: 840522292 INFO: Loaded 1 modules (424174 inline 8-bit counters): 424174 [0x55e121ef9ab8, 0x55e121f613a6), INFO: Loaded 1 PC tables (424174 PCs): 424174 [0x55e121f613a8,0x55e1225da288), @@ -77,7 +79,7 @@ of the test. Just make sure to use double-dash to distinguish them from the fuzzer's own arguments: ```sh -$ FUZZ=address_deserialize_v2 src/test/fuzz/fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5 --printtoconsole=1 +$ FUZZ=address_deserialize_v2 build_fuzz/src/test/fuzz/fuzz -runs=1 fuzz_corpora/address_deserialize_v2 --checkaddrman=5 --printtoconsole=1 ``` ## Fuzzing corpora @@ -88,11 +90,11 @@ To fuzz `process_message` using the [`bitcoin-core/qa-assets`](https://github.co ```sh $ git clone https://github.com/bitcoin-core/qa-assets -$ FUZZ=process_message src/test/fuzz/fuzz qa-assets/fuzz_seed_corpus/process_message/ +$ FUZZ=process_message build_fuzz/src/test/fuzz/fuzz qa-assets/fuzz_corpora/process_message/ INFO: Seed: 1346407872 INFO: Loaded 1 modules (424174 inline 8-bit counters): 424174 [0x55d8a9004ab8, 0x55d8a906c3a6), INFO: Loaded 1 PC tables (424174 PCs): 424174 [0x55d8a906c3a8,0x55d8a96e5288), -INFO: 991 files found in qa-assets/fuzz_seed_corpus/process_message/ +INFO: 991 files found in qa-assets/fuzz_corpora/process_message/ INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes INFO: seed corpus: files: 991 min: 1b max: 1858b total: 288291b rss: 150Mb #993 INITED cov: 7063 ft: 8236 corp: 25/3821b exec/s: 0 rss: 181Mb @@ -101,7 +103,15 @@ INFO: seed corpus: files: 991 min: 1b max: 1858b total: 288291b rss: 150Mb ## Run without sanitizers for increased throughput -Fuzzing on a harness compiled with `--with-sanitizers=address,fuzzer,undefined` is good for finding bugs. However, the very slow execution even under libFuzzer will limit the ability to find new coverage. A good approach is to perform occasional long runs without the additional bug-detectors (configure `--with-sanitizers=fuzzer`) and then merge new inputs into a corpus as described in the qa-assets repo (https://github.com/bitcoin-core/qa-assets/blob/main/.github/PULL_REQUEST_TEMPLATE.md). Patience is useful; even with improved throughput, libFuzzer may need days and 10s of millions of executions to reach deep/hard targets. +Fuzzing on a harness compiled with `-DSANITIZERS=address,fuzzer,undefined` is +good for finding bugs. However, the very slow execution even under libFuzzer +will limit the ability to find new coverage. A good approach is to perform +occasional long runs without the additional bug-detectors +(`--preset=libfuzzer-nosan`) and then merge new inputs into a corpus as described in +the qa-assets repo +(https://github.com/bitcoin-core/qa-assets/blob/main/.github/PULL_REQUEST_TEMPLATE.md). +Patience is useful; even with improved throughput, libFuzzer may need days and +10s of millions of executions to reach deep/hard targets. ## Reproduce a fuzzer crash reported by the CI @@ -112,8 +122,8 @@ Fuzzing on a harness compiled with `--with-sanitizers=address,fuzzer,undefined` more slowly with sanitizers enabled, but a crash should be reproducible very quickly from a crash case) - run the fuzzer with the case number appended to the seed corpus path: - `FUZZ=process_message src/test/fuzz/fuzz - qa-assets/fuzz_seed_corpus/process_message/1bc91feec9fc00b107d97dc225a9f2cdaa078eb6` + `FUZZ=process_message build_fuzz/src/test/fuzz/fuzz + qa-assets/fuzz_corpora/process_message/1bc91feec9fc00b107d97dc225a9f2cdaa078eb6` ## Submit improved coverage @@ -131,10 +141,13 @@ You may also need to take care of giving the correct path for `clang` and `clang++`, like `CC=/path/to/clang CXX=/path/to/clang++` if the non-systems `clang` does not come first in your path. -Full configure that was tested on macOS with `brew` installed `llvm`: +Full configuration step that was tested on macOS with `brew` installed `llvm`: ```sh -./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ +$ cmake --preset=libfuzzer \ + -DCMAKE_C_COMPILER="$(brew --prefix llvm)/bin/clang" \ + -DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++" \ + -DAPPEND_LDFLAGS=-Wl,-no_warn_duplicate_libraries ``` Read the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for more information. This [libFuzzer tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) might also be of interest. @@ -150,16 +163,18 @@ $ git clone https://github.com/bitcoin/bitcoin $ cd bitcoin/ $ git clone https://github.com/AFLplusplus/AFLplusplus $ make -C AFLplusplus/ source-only -$ ./autogen.sh # If afl-clang-lto is not available, see # https://github.com/AFLplusplus/AFLplusplus#a-selecting-the-best-afl-compiler-for-instrumenting-the-target -$ CC=$(pwd)/AFLplusplus/afl-clang-lto CXX=$(pwd)/AFLplusplus/afl-clang-lto++ ./configure --enable-fuzz -$ make -# For macOS you may need to ignore x86 compilation checks when running "make". If so, -# try compiling using: AFL_NO_X86=1 make +$ cmake -B build_fuzz \ + -DCMAKE_C_COMPILER="$(pwd)/AFLplusplus/afl-clang-lto" \ + -DCMAKE_CXX_COMPILER="$(pwd)/AFLplusplus/afl-clang-lto++" \ + -DBUILD_FOR_FUZZING=ON +$ cmake --build build_fuzz +# For macOS you may need to ignore x86 compilation checks when running "cmake --build". If so, +# try compiling using: AFL_NO_X86=1 cmake --build build_fuzz $ mkdir -p inputs/ outputs/ $ echo A > inputs/thin-air-input -$ FUZZ=bech32 AFLplusplus/afl-fuzz -i inputs/ -o outputs/ -- src/test/fuzz/fuzz +$ FUZZ=bech32 ./AFLplusplus/afl-fuzz -i inputs/ -o outputs/ -- build_fuzz/src/test/fuzz/fuzz # You may have to change a few kernel parameters to test optimally - afl-fuzz # will print an error and suggestion if so. ``` @@ -175,171 +190,30 @@ To quickly get started fuzzing Bitcoin Core using [Honggfuzz](https://github.com ```sh $ git clone https://github.com/bitcoin/bitcoin $ cd bitcoin/ -$ ./autogen.sh $ git clone https://github.com/google/honggfuzz $ cd honggfuzz/ $ make $ cd .. -$ CC=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang CXX=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang++ ./configure --enable-fuzz --with-sanitizers=address,undefined -$ make +$ cmake -B build_fuzz \ + -DCMAKE_C_COMPILER="$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang" \ + -DCMAKE_CXX_COMPILER="$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang++" \ + -DBUILD_FOR_FUZZING=ON \ + -DSANITIZERS=address,undefined +$ cmake --build build_fuzz $ mkdir -p inputs/ -$ FUZZ=process_message honggfuzz/honggfuzz -i inputs/ -- src/test/fuzz/fuzz +$ FUZZ=process_message ./honggfuzz/honggfuzz -i inputs/ -- build_fuzz/src/test/fuzz/fuzz ``` Read the [Honggfuzz documentation](https://github.com/google/honggfuzz/blob/master/docs/USAGE.md) for more information. -## Fuzzing the Bitcoin Core P2P layer using Honggfuzz NetDriver - -Honggfuzz NetDriver allows for very easy fuzzing of TCP servers such as Bitcoin -Core without having to write any custom fuzzing harness. The `bitcoind` server -process is largely fuzzed without modification. - -This makes the fuzzing highly realistic: a bug reachable by the fuzzer is likely -also remotely triggerable by an untrusted peer. - -To quickly get started fuzzing the P2P layer using Honggfuzz NetDriver: - -```sh -$ mkdir bitcoin-honggfuzz-p2p/ -$ cd bitcoin-honggfuzz-p2p/ -$ git clone https://github.com/bitcoin/bitcoin -$ cd bitcoin/ -$ ./autogen.sh -$ git clone https://github.com/google/honggfuzz -$ cd honggfuzz/ -$ make -$ cd .. -$ CC=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang \ - CXX=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang++ \ - ./configure --disable-wallet --with-gui=no \ - --with-sanitizers=address,undefined -$ git apply << "EOF" -diff --git a/src/compat/compat.h b/src/compat/compat.h -index 8195bceaec..cce2b31ff0 100644 ---- a/src/compat/compat.h -+++ b/src/compat/compat.h -@@ -90,8 +90,12 @@ typedef char* sockopt_arg_type; - // building with a binutils < 2.36 is subject to this ld bug. - #define MAIN_FUNCTION __declspec(dllexport) int main(int argc, char* argv[]) - #else -+#ifdef HFND_FUZZING_ENTRY_FUNCTION_CXX -+#define MAIN_FUNCTION HFND_FUZZING_ENTRY_FUNCTION_CXX(int argc, char* argv[]) -+#else - #define MAIN_FUNCTION int main(int argc, char* argv[]) - #endif -+#endif - - // Note these both should work with the current usage of poll, but best to be safe - // WIN32 poll is broken https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/ -diff --git a/src/net.cpp b/src/net.cpp -index 7601a6ea84..702d0f56ce 100644 ---- a/src/net.cpp -+++ b/src/net.cpp -@@ -727,7 +727,7 @@ int V1TransportDeserializer::readHeader(Span<const uint8_t> msg_bytes) - } - - // Check start string, network magic -- if (memcmp(hdr.pchMessageStart, m_chain_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) { -+ if (false && memcmp(hdr.pchMessageStart, m_chain_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) { // skip network magic checking - LogPrint(BCLog::NET, "Header error: Wrong MessageStart %s received, peer=%d\n", HexStr(hdr.pchMessageStart), m_node_id); - return -1; - } -@@ -788,7 +788,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds - RandAddEvent(ReadLE32(hash.begin())); - - // Check checksum and header message type string -- if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) { -+ if (false && memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) { // skip checksum checking - LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n", - SanitizeString(msg.m_type), msg.m_message_size, - HexStr(Span{hash}.first(CMessageHeader::CHECKSUM_SIZE)), -EOF -$ make -C src/ bitcoind -$ mkdir -p inputs/ -$ honggfuzz/honggfuzz --exit_upon_crash --quiet --timeout 4 -n 1 -Q \ - -E HFND_TCP_PORT=18444 -f inputs/ -- \ - src/bitcoind -regtest -discover=0 -dns=0 -dnsseed=0 -listenonion=0 \ - -nodebuglogfile -bind=127.0.0.1:18444 -logthreadnames \ - -debug -``` - -# Fuzzing Bitcoin Core using Eclipser (v1.x) - -## Quickstart guide - -To quickly get started fuzzing Bitcoin Core using [Eclipser v1.x](https://github.com/SoftSec-KAIST/Eclipser/tree/v1.x): - -```sh -$ git clone https://github.com/bitcoin/bitcoin -$ cd bitcoin/ -$ sudo vim /etc/apt/sources.list # Uncomment the lines starting with 'deb-src'. -$ sudo apt-get update -$ sudo apt-get build-dep qemu -$ sudo apt-get install libtool libtool-bin wget automake autoconf bison gdb -``` - -At this point, you must install the .NET core. The process differs, depending on your Linux distribution. -See [this link](https://learn.microsoft.com/en-us/dotnet/core/install/linux) for details. -On Ubuntu 20.04, the following should work: - -```sh -$ wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -$ sudo dpkg -i packages-microsoft-prod.deb -$ rm packages-microsoft-prod.deb -$ sudo apt-get update -$ sudo apt-get install -y dotnet-sdk-2.1 -``` - -You will also want to make sure Python is installed as `python` for the Eclipser install to succeed. - -```sh -$ git clone https://github.com/SoftSec-KAIST/Eclipser.git -$ cd Eclipser -$ git checkout v1.x -$ make -$ cd .. -$ ./autogen.sh -$ ./configure --enable-fuzz -$ make -$ mkdir -p outputs/ -$ FUZZ=bech32 dotnet Eclipser/build/Eclipser.dll fuzz -p src/test/fuzz/fuzz -t 36000 -o outputs --src stdin -``` - -This will perform 10 hours of fuzzing. - -To make further use of the inputs generated by Eclipser, you -must first decode them: - -```sh -$ dotnet Eclipser/build/Eclipser.dll decode -i outputs/testcase -o decoded_outputs -``` -This will place raw inputs in the directory `decoded_outputs/decoded_stdins`. Crashes are in the `outputs/crashes` directory, and must -be decoded in the same way. - -Fuzzing with Eclipser will likely be much more effective if using an existing corpus: - -```sh -$ git clone https://github.com/bitcoin-core/qa-assets -$ FUZZ=bech32 dotnet Eclipser/build/Eclipser.dll fuzz -p src/test/fuzz/fuzz -t 36000 -i qa-assets/fuzz_seed_corpus/bech32 outputs --src stdin -``` - -Note that fuzzing with Eclipser on certain targets (those that create 'full nodes', e.g. `process_message*`) will, -for now, slowly fill `/tmp/` with improperly cleaned-up files, which will cause spurious crashes. -See [this proposed patch](https://github.com/bitcoin/bitcoin/pull/22472) for more information. - -Read the [Eclipser documentation for v1.x](https://github.com/SoftSec-KAIST/Eclipser/tree/v1.x) for more details on using Eclipser. - - # OSS-Fuzz Bitcoin Core participates in Google's [OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/bitcoin-core) -program, which includes a dashboard of [publicly disclosed vulnerabilities](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=bitcoin-core). -Generally, we try to disclose vulnerabilities as soon as possible after they -are fixed to give users the knowledge they need to be protected. However, -because Bitcoin is a live P2P network, and not just standalone local software, -we might not fully disclose every issue within Google's standard +program, which includes a dashboard of [publicly disclosed vulnerabilities](https://issues.oss-fuzz.com/issues?q=bitcoin-core%20status:open). + +Bitcoin Core follows its [security disclosure policy](https://bitcoincore.org/en/security-advisories/), +which may differ from Google's standard [90-day disclosure window](https://google.github.io/oss-fuzz/getting-started/bug-disclosure-guidelines/) -if a partial or delayed disclosure is important to protect users or the -function of the network. +. OSS-Fuzz also produces [a fuzzing coverage report](https://oss-fuzz.com/coverage-report/job/libfuzzer_asan_bitcoin-core/latest). diff --git a/doc/init.md b/doc/init.md index 64ab971557..b570fed22c 100644 --- a/doc/init.md +++ b/doc/init.md @@ -35,8 +35,10 @@ it will use a special cookie file for authentication. The cookie is generated wi content when the daemon starts, and deleted when it exits. Read access to this file controls who can access it through RPC. -By default the cookie is stored in the data directory, but it's location can be overridden -with the option '-rpccookiefile'. +By default the cookie is stored in the data directory, but its location can be +overridden with the option `-rpccookiefile`. Default file permissions for the +cookie are "owner" (i.e. user read/writeable) via default application-wide file +umask of `0077`, but these can be overridden with the `-rpccookieperms` option. This allows for running bitcoind without having to do any manual configuration. diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am deleted file mode 100644 index 8f890da532..0000000000 --- a/doc/man/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -dist_man1_MANS= - -if BUILD_BITCOIND - dist_man1_MANS+=bitcoind.1 -endif - -if ENABLE_QT - dist_man1_MANS+=bitcoin-qt.1 -endif - -if BUILD_BITCOIN_CLI - dist_man1_MANS+=bitcoin-cli.1 -endif - -if BUILD_BITCOIN_TX - dist_man1_MANS+=bitcoin-tx.1 -endif - -if BUILD_BITCOIN_UTIL - dist_man1_MANS+=bitcoin-util.1 -endif - -if ENABLE_WALLET -if BUILD_BITCOIN_WALLET - dist_man1_MANS+=bitcoin-wallet.1 -endif -endif diff --git a/doc/multiprocess.md b/doc/multiprocess.md index 7ba89b3ff5..1757296eed 100644 --- a/doc/multiprocess.md +++ b/doc/multiprocess.md @@ -4,7 +4,7 @@ _This document describes usage of the multiprocess feature. For design informati ## Build Option -On unix systems, the `--enable-multiprocess` build option can be passed to `./configure` to build new `bitcoin-node`, `bitcoin-wallet`, and `bitcoin-gui` executables alongside existing `bitcoind` and `bitcoin-qt` executables. +On Unix systems, the `-DWITH_MULTIPROCESS=ON` build option can be passed to build the supplemental `bitcoin-node` and `bitcoin-gui` multiprocess executables. ## Debugging @@ -17,15 +17,17 @@ The multiprocess feature requires [Cap'n Proto](https://capnproto.org/) and [lib ``` cd <BITCOIN_SOURCE_DIRECTORY> make -C depends NO_QT=1 MULTIPROCESS=1 -CONFIG_SITE=$PWD/depends/x86_64-pc-linux-gnu/share/config.site ./configure -make -src/bitcoin-node -regtest -printtoconsole -debug=ipc -BITCOIND=bitcoin-node test/functional/test_runner.py +# Set host platform to output of gcc -dumpmachine or clang -dumpmachine or check the depends/ directory for the generated subdirectory name +HOST_PLATFORM="x86_64-pc-linux-gnu" +cmake -B build --toolchain=depends/$HOST_PLATFORM/toolchain.cmake +cmake --build build +build/src/bitcoin-node -regtest -printtoconsole -debug=ipc +BITCOIND=$(pwd)/build/src/bitcoin-node build/test/functional/test_runner.py ``` -The configure script will pick up settings and library locations from the depends directory, so there is no need to pass `--enable-multiprocess` as a separate flag when using the depends system (it's controlled by the `MULTIPROCESS=1` option). +The `cmake` build will pick up settings and library locations from the depends directory, so there is no need to pass `-DWITH_MULTIPROCESS=ON` as a separate flag when using the depends system (it's controlled by the `MULTIPROCESS=1` option). -Alternately, you can install [Cap'n Proto](https://capnproto.org/) and [libmultiprocess](https://github.com/chaincodelabs/libmultiprocess) packages on your system, and just run `./configure --enable-multiprocess` without using the depends system. The configure script will be able to locate the installed packages via [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/). See [Installation](https://github.com/chaincodelabs/libmultiprocess/blob/master/doc/install.md) section of the libmultiprocess readme for install steps. See [build-unix.md](build-unix.md) and [build-osx.md](build-osx.md) for information about installing dependencies in general. +Alternately, you can install [Cap'n Proto](https://capnproto.org/) and [libmultiprocess](https://github.com/chaincodelabs/libmultiprocess) packages on your system, and just run `cmake -B build -DWITH_MULTIPROCESS=ON` without using the depends system. The `cmake` build will be able to locate the installed packages via [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/). See [Installation](https://github.com/chaincodelabs/libmultiprocess/blob/master/doc/install.md) section of the libmultiprocess readme for install steps. See [build-unix.md](build-unix.md) and [build-osx.md](build-osx.md) for information about installing dependencies in general. ## Usage diff --git a/doc/multisig-tutorial.md b/doc/multisig-tutorial.md index 1d2b3244bc..1f21acc2be 100644 --- a/doc/multisig-tutorial.md +++ b/doc/multisig-tutorial.md @@ -9,15 +9,13 @@ This tutorial uses [jq](https://github.com/stedolan/jq) JSON processor to proces Before starting this tutorial, start the bitcoin node on the signet network. ```bash -./src/bitcoind -signet -daemon +./build/src/bitcoind -signet -daemon ``` This tutorial also uses the default WPKH derivation path to get the xpubs and does not conform to [BIP 45](https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki) or [BIP 87](https://github.com/bitcoin/bips/blob/master/bip-0087.mediawiki). 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 @@ -29,7 +27,7 @@ These three wallets should not be used directly for privacy reasons (public key ```bash for ((n=1;n<=3;n++)) do - ./src/bitcoin-cli -signet createwallet "participant_${n}" + ./build/src/bitcoin-cli -signet createwallet "participant_${n}" done ``` @@ -49,9 +47,9 @@ declare -A xpubs for ((n=1;n<=3;n++)) do - xpubs["internal_xpub_${n}"]=$(./src/bitcoin-cli -signet -rpcwallet="participant_${n}" listdescriptors | jq '.descriptors | [.[] | select(.desc | startswith("wpkh") and contains("/1/*"))][0] | .desc' | grep -Po '(?<=\().*(?=\))') + xpubs["internal_xpub_${n}"]=$(./build/src/bitcoin-cli -signet -rpcwallet="participant_${n}" listdescriptors | jq '.descriptors | [.[] | select(.desc | startswith("wpkh") and contains("/1/*"))][0] | .desc' | grep -Po '(?<=\().*(?=\))') - xpubs["external_xpub_${n}"]=$(./src/bitcoin-cli -signet -rpcwallet="participant_${n}" listdescriptors | jq '.descriptors | [.[] | select(.desc | startswith("wpkh") and contains("/0/*") )][0] | .desc' | grep -Po '(?<=\().*(?=\))') + xpubs["external_xpub_${n}"]=$(./build/src/bitcoin-cli -signet -rpcwallet="participant_${n}" listdescriptors | jq '.descriptors | [.[] | select(.desc | startswith("wpkh") and contains("/0/*") )][0] | .desc' | grep -Po '(?<=\().*(?=\))') done ``` @@ -73,8 +71,8 @@ Define the external and internal multisig descriptors, add the checksum and then external_desc="wsh(sortedmulti(2,${xpubs["external_xpub_1"]},${xpubs["external_xpub_2"]},${xpubs["external_xpub_3"]}))" internal_desc="wsh(sortedmulti(2,${xpubs["internal_xpub_1"]},${xpubs["internal_xpub_2"]},${xpubs["internal_xpub_3"]}))" -external_desc_sum=$(./src/bitcoin-cli -signet getdescriptorinfo $external_desc | jq '.descriptor') -internal_desc_sum=$(./src/bitcoin-cli -signet getdescriptorinfo $internal_desc | jq '.descriptor') +external_desc_sum=$(./build/src/bitcoin-cli -signet getdescriptorinfo $external_desc | jq '.descriptor') +internal_desc_sum=$(./build/src/bitcoin-cli -signet getdescriptorinfo $internal_desc | jq '.descriptor') multisig_ext_desc="{\"desc\": $external_desc_sum, \"active\": true, \"internal\": false, \"timestamp\": \"now\"}" multisig_int_desc="{\"desc\": $internal_desc_sum, \"active\": true, \"internal\": true, \"timestamp\": \"now\"}" @@ -96,7 +94,7 @@ There are other fields that can be added to the descriptors: * `internal`: Indicates whether matching outputs should be treated as something other than incoming payments (e.g. change). * `timestamp`: Sets the time from which to start rescanning the blockchain for the descriptor, in UNIX epoch time. -Documentation for these and other parameters can be found by typing `./src/bitcoin-cli help importdescriptors`. +Documentation for these and other parameters can be found by typing `./build/src/bitcoin-cli help importdescriptors`. `multisig_desc` concatenates external and internal descriptors in a JSON array and then it will be used to create the multisig wallet. @@ -109,17 +107,17 @@ Then import the descriptors created in the previous step using the `importdescri After that, `getwalletinfo` can be used to check if the wallet was created successfully. ```bash -./src/bitcoin-cli -signet -named createwallet wallet_name="multisig_wallet_01" disable_private_keys=true blank=true +./build/src/bitcoin-cli -signet -named createwallet wallet_name="multisig_wallet_01" disable_private_keys=true blank=true -./src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" importdescriptors "$multisig_desc" +./build/src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" importdescriptors "$multisig_desc" -./src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getwalletinfo +./build/src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getwalletinfo ``` Once the wallets have already been created and this tutorial needs to be repeated or resumed, it is not necessary to recreate them, just load them with the command below: ```bash -for ((n=1;n<=3;n++)); do ./src/bitcoin-cli -signet loadwallet "participant_${n}"; done +for ((n=1;n<=3;n++)); do ./build/src/bitcoin-cli -signet loadwallet "participant_${n}"; done ``` ### 1.4 Fund the wallet @@ -133,9 +131,9 @@ The url used by the script can also be accessed directly. At time of writing, th Coins received by the wallet must have at least 1 confirmation before they can be spent. It is necessary to wait for a new block to be mined before continuing. ```bash -receiving_address=$(./src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getnewaddress) +receiving_address=$(./build/src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getnewaddress) -./contrib/signet/getcoins.py -c ./src/bitcoin-cli -a $receiving_address +./contrib/signet/getcoins.py -c ./build/src/bitcoin-cli -a $receiving_address ``` To copy the receiving address onto the clipboard, use the following command. This can be useful when getting coins via the signet faucet mentioned above. @@ -147,7 +145,7 @@ echo -n "$receiving_address" | xclip -sel clip The `getbalances` RPC may be used to check the balance. Coins with `trusted` status can be spent. ```bash -./src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getbalances +./build/src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getbalances ``` ### 1.5 Create a PSBT @@ -163,13 +161,13 @@ For simplicity, the destination address is taken from the `participant_1` wallet The `walletcreatefundedpsbt` RPC is used to create and fund a transaction in the PSBT format. It is the first step in creating the PSBT. ```bash -balance=$(./src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getbalance) +balance=$(./build/src/bitcoin-cli -signet -rpcwallet="multisig_wallet_01" getbalance) amount=$(echo "$balance * 0.8" | bc -l | sed -e 's/^\./0./' -e 's/^-\./-0./') -destination_addr=$(./src/bitcoin-cli -signet -rpcwallet="participant_1" getnewaddress) +destination_addr=$(./build/src/bitcoin-cli -signet -rpcwallet="participant_1" getnewaddress) -funded_psbt=$(./src/bitcoin-cli -signet -named -rpcwallet="multisig_wallet_01" walletcreatefundedpsbt outputs="{\"$destination_addr\": $amount}" | jq -r '.psbt') +funded_psbt=$(./build/src/bitcoin-cli -signet -named -rpcwallet="multisig_wallet_01" walletcreatefundedpsbt outputs="{\"$destination_addr\": $amount}" | jq -r '.psbt') ``` There is also the `createpsbt` RPC, which serves the same purpose, but it has no access to the wallet or to the UTXO set. It is functionally the same as `createrawtransaction` and just drops the raw transaction into an otherwise blank PSBT. [[source](https://bitcointalk.org/index.php?topic=5131043.msg50573609#msg50573609)] In most cases, `walletcreatefundedpsbt` solves the problem. @@ -183,9 +181,9 @@ Optionally, the PSBT can be decoded to a JSON format using `decodepsbt` RPC. The `analyzepsbt` RPC analyzes and provides information about the current status of a PSBT and its inputs, e.g. missing signatures. ```bash -./src/bitcoin-cli -signet decodepsbt $funded_psbt +./build/src/bitcoin-cli -signet decodepsbt $funded_psbt -./src/bitcoin-cli -signet analyzepsbt $funded_psbt +./build/src/bitcoin-cli -signet analyzepsbt $funded_psbt ``` ### 1.7 Update the PSBT @@ -195,9 +193,9 @@ In the code above, two PSBTs are created. One signed by `participant_1` wallet a The `walletprocesspsbt` is used by the wallet to sign a PSBT. ```bash -psbt_1=$(./src/bitcoin-cli -signet -rpcwallet="participant_1" walletprocesspsbt $funded_psbt | jq '.psbt') +psbt_1=$(./build/src/bitcoin-cli -signet -rpcwallet="participant_1" walletprocesspsbt $funded_psbt | jq '.psbt') -psbt_2=$(./src/bitcoin-cli -signet -rpcwallet="participant_2" walletprocesspsbt $funded_psbt | jq '.psbt') +psbt_2=$(./build/src/bitcoin-cli -signet -rpcwallet="participant_2" walletprocesspsbt $funded_psbt | jq '.psbt') ``` ### 1.8 Combine the PSBT @@ -205,7 +203,7 @@ psbt_2=$(./src/bitcoin-cli -signet -rpcwallet="participant_2" walletprocesspsbt The PSBT, if signed separately by the co-signers, must be combined into one transaction before being finalized. This is done by `combinepsbt` RPC. ```bash -combined_psbt=$(./src/bitcoin-cli -signet combinepsbt "[$psbt_1, $psbt_2]") +combined_psbt=$(./build/src/bitcoin-cli -signet combinepsbt "[$psbt_1, $psbt_2]") ``` There is an RPC called `joinpsbts`, but it has a different purpose than `combinepsbt`. `joinpsbts` joins the inputs from multiple distinct PSBTs into one PSBT. @@ -219,9 +217,9 @@ The `finalizepsbt` RPC is used to produce a network serialized transaction which It checks that all inputs have complete scriptSigs and scriptWitnesses and, if so, encodes them into network serialized transactions. ```bash -finalized_psbt_hex=$(./src/bitcoin-cli -signet finalizepsbt $combined_psbt | jq -r '.hex') +finalized_psbt_hex=$(./build/src/bitcoin-cli -signet finalizepsbt $combined_psbt | jq -r '.hex') -./src/bitcoin-cli -signet sendrawtransaction $finalized_psbt_hex +./build/src/bitcoin-cli -signet sendrawtransaction $finalized_psbt_hex ``` ### 1.10 Alternative Workflow (PSBT sequential signatures) @@ -231,11 +229,11 @@ Instead of each wallet signing the original PSBT and combining them later, the w After that, the rest of the process is the same: the PSBT is finalized and transmitted to the network. ```bash -psbt_1=$(./src/bitcoin-cli -signet -rpcwallet="participant_1" walletprocesspsbt $funded_psbt | jq -r '.psbt') +psbt_1=$(./build/src/bitcoin-cli -signet -rpcwallet="participant_1" walletprocesspsbt $funded_psbt | jq -r '.psbt') -psbt_2=$(./src/bitcoin-cli -signet -rpcwallet="participant_2" walletprocesspsbt $psbt_1 | jq -r '.psbt') +psbt_2=$(./build/src/bitcoin-cli -signet -rpcwallet="participant_2" walletprocesspsbt $psbt_1 | jq -r '.psbt') -finalized_psbt_hex=$(./src/bitcoin-cli -signet finalizepsbt $psbt_2 | jq -r '.hex') +finalized_psbt_hex=$(./build/src/bitcoin-cli -signet finalizepsbt $psbt_2 | jq -r '.hex') -./src/bitcoin-cli -signet sendrawtransaction $finalized_psbt_hex +./build/src/bitcoin-cli -signet sendrawtransaction $finalized_psbt_hex ``` diff --git a/doc/offline-signing-tutorial.md b/doc/offline-signing-tutorial.md index 401ee52c1c..e03a0003a1 100644 --- a/doc/offline-signing-tutorial.md +++ b/doc/offline-signing-tutorial.md @@ -25,7 +25,7 @@ We are going to first create an `offline_wallet` on the offline host. We will th 1. On the offline machine create a wallet named `offline_wallet` secured by a wallet `passphrase`. This wallet will contain private keys and must remain unconnected to any networks at all times. ```sh -[offline]$ ./src/bitcoin-cli -signet -named createwallet \ +[offline]$ ./build/src/bitcoin-cli -signet -named createwallet \ wallet_name="offline_wallet" \ passphrase="** enter passphrase **" @@ -40,7 +40,7 @@ We are going to first create an `offline_wallet` on the offline host. We will th 2. Export the public key-only descriptors from the offline host to a JSON file named `descriptors.json`. We use `jq` here to extract the `.descriptors` field from the full RPC response. ```sh -[offline]$ ./src/bitcoin-cli -signet -rpcwallet="offline_wallet" listdescriptors \ +[offline]$ ./build/src/bitcoin-cli -signet -rpcwallet="offline_wallet" listdescriptors \ | jq -r '.descriptors' \ >> /path/to/descriptors.json ``` @@ -58,7 +58,7 @@ The `watch_only_wallet` wallet will be used to track and validate incoming trans > `disable_private_keys` indicates that the wallet should refuse to import private keys, i.e. will be a dedicated watch-only wallet. ```sh -[online]$ ./src/bitcoin-cli -signet -named createwallet \ +[online]$ ./build/src/bitcoin-cli -signet -named createwallet \ wallet_name="watch_only_wallet" \ disable_private_keys=true @@ -70,7 +70,7 @@ The `watch_only_wallet` wallet will be used to track and validate incoming trans 2. Import the `offline_wallet`s public key descriptors to the online `watch_only_wallet` using the `descriptors.json` file created on the offline wallet. ```sh -[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" importdescriptors "$(cat /path/to/descriptors.json)" +[online]$ ./build/src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" importdescriptors "$(cat /path/to/descriptors.json)" [ { @@ -109,7 +109,7 @@ At this point, it's important to understand that both the `offline_wallet` and o 1. Generate an address to receive coins. You can use _either_ the `offline_wallet` or the online `watch_only_wallet` to generate this address, as they will produce the same addresses. For the sake of this guide, we'll use the online `watch_only_wallet` to generate the address. ```sh -[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" getnewaddress +[online]$ ./build/src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" getnewaddress tb1qtu5qgc6ddhmqm5yqjvhg83qgk2t4ewajg0h6yh ``` @@ -119,7 +119,7 @@ tb1qtu5qgc6ddhmqm5yqjvhg83qgk2t4ewajg0h6yh 3. Confirm that coins were received using the online `watch_only_wallet`. Note that the transaction may take a few moments before being received on your local node, depending on its connectivity. Just re-run the command periodically until the transaction is received. ```sh -[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" listunspent +[online]$ ./build/src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" listunspent [ { @@ -148,7 +148,7 @@ tb1qtu5qgc6ddhmqm5yqjvhg83qgk2t4ewajg0h6yh 2. Create a funded but unsigned PSBT to the destination address with the online `watch_only_wallet` by using `send [{"address":amount},...]` and export the unsigned PSBT to a file `funded_psbt.txt` for easy portability to the `offline_wallet` for signing: ```sh -[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" send \ +[online]$ ./build/src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" send \ '{"tb1q9k5w0nhnhyeh78snpxh0t5t7c3lxdeg3erez32": 0.009}' \ | jq -r '.psbt' \ >> /path/to/funded_psbt.txt @@ -165,13 +165,13 @@ cHNidP8BAHECAAAAAWLHKR9/xAjetzL/FCmZU5lbfINRMWPRPHWO68PfUzkPAQAAAAD9////AoA4AQAA Decode and analyze the unsigned PSBT on the `offline_wallet` using the `funded_psbt.txt` file: ```sh -[offline]$ ./src/bitcoin-cli -signet decodepsbt $(cat /path/to/funded_psbt.txt) +[offline]$ ./build/src/bitcoin-cli -signet decodepsbt $(cat /path/to/funded_psbt.txt) { ... } -[offline]$ ./src/bitcoin-cli -signet analyzepsbt $(cat /path/to/funded_psbt.txt) +[offline]$ ./build/src/bitcoin-cli -signet analyzepsbt $(cat /path/to/funded_psbt.txt) { "inputs": [ @@ -202,13 +202,13 @@ Notice that the analysis of the PSBT shows that "signatures" are missing and sho Use the walletpassphrase command to unlock the `offline_wallet` with the passphrase. You should specify the passphrase and a timeout (in seconds) for how long you want the wallet to remain unlocked. ```sh -[offline]$ ./src/bitcoin-cli -signet -rpcwallet="offline_wallet" walletpassphrase "** enter passphrase **" 60 +[offline]$ ./build/src/bitcoin-cli -signet -rpcwallet="offline_wallet" walletpassphrase "** enter passphrase **" 60 ``` 2. Process, sign and finalize the PSBT on the `offline_wallet` using the `walletprocesspsbt` command, saving the output to a file `final_psbt.txt`. ```sh -[offline]$ ./src/bitcoin-cli -signet -rpcwallet="offline_wallet" walletprocesspsbt \ +[offline]$ ./build/src/bitcoin-cli -signet -rpcwallet="offline_wallet" walletprocesspsbt \ $(cat /path/to/funded_psbt.txt) \ | jq -r .hex \ >> /path/to/final_psbt.txt @@ -218,7 +218,7 @@ Use the walletpassphrase command to unlock the `offline_wallet` with the passphr Broadcast the funded, signed and finalized PSBT `final_psbt.txt` using `sendrawtransaction` with an online node: ```sh -[online]$ ./src/bitcoin-cli -signet sendrawtransaction $(cat /path/to/final_psbt.txt) +[online]$ ./build/src/bitcoin-cli -signet sendrawtransaction $(cat /path/to/final_psbt.txt) c2430a0e46df472b04b0ca887bbcd5c4abf7b2ce2eb71de981444a80e2b96d52 ``` @@ -228,7 +228,7 @@ c2430a0e46df472b04b0ca887bbcd5c4abf7b2ce2eb71de981444a80e2b96d52 Confirm the updated balance of the offline wallet using the `watch_only_wallet`. ```sh -[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" getbalances +[online]$ ./build/src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" getbalances { "mine": { @@ -247,7 +247,7 @@ Confirm the updated balance of the offline wallet using the `watch_only_wallet`. You can also show transactions related to the wallet using `listtransactions` ```sh -[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" listtransactions +[online]$ ./build/src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" listtransactions { ... diff --git a/doc/policy/mempool-replacements.md b/doc/policy/mempool-replacements.md index 3fd7ff2ad2..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 nVersion field is set to 3. + 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 7e983221c5..b432008d7b 100644 --- a/doc/policy/packages.md +++ b/doc/policy/packages.md @@ -36,10 +36,29 @@ The following rules are enforced for all packages: * Packages cannot have conflicting transactions, i.e. no two transactions in a package can spend the same inputs. Packages cannot have duplicate transactions. (#20833) -* No transaction in a package can conflict with a mempool transaction. Replace By Fee is - currently disabled for packages. (#20833) +* Only limited package replacements are currently considered. (#28984) - - Package RBF may be enabled in the future. + - 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. + + - No more than MAX_REPLACEMENT_CANDIDATES transactions can be replaced, analogous to + regular [replacement rule](./mempool-replacements.md) 5). + + - Replacements must pay more total total fees at the incremental relay fee (analogous to + regular [replacement rules](./mempool-replacements.md) 3 and 4). + + - Parent feerate must be lower than package feerate. + + - Must improve [feerate diagram](https://delvingbitcoin.org/t/mempool-incentive-compatibility/553). (#29242) + + - *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 TRUC transactions this can + result in more robust fee bumping. More general package RBF may be + enabled in the future. * When packages are evaluated against ancestor/descendant limits, the union of all transactions' descendants and ancestors is considered. (#21800) diff --git a/doc/productivity.md b/doc/productivity.md index e9b7bc270c..f025b4bf6e 100644 --- a/doc/productivity.md +++ b/doc/productivity.md @@ -6,8 +6,8 @@ Table of Contents * [General](#general) * [Cache compilations with `ccache`](#cache-compilations-with-ccache) - * [Disable features with `./configure`](#disable-features-with-configure) - * [Make use of your threads with `make -j`](#make-use-of-your-threads-with-make--j) + * [Disable features when generating the build system](#disable-features-when-generating-the-build-system) + * [Make use of your threads with `-j`](#make-use-of-your-threads-with--j) * [Only build what you need](#only-build-what-you-need) * [Compile on multiple machines](#compile-on-multiple-machines) * [Multiple working directories with `git worktrees`](#multiple-working-directories-with-git-worktrees) @@ -31,9 +31,9 @@ The easiest way to faster compile times is to cache compiles. `ccache` is a way > ccache is a compiler cache. It speeds up recompilation by caching the result of previous compilations and detecting when the same compilation is being done again. Supported languages are C, C++, Objective-C and Objective-C++. -Install `ccache` through your distribution's package manager, and run `./configure` with your normal flags to pick it up. +Install `ccache` through your distribution's package manager, and run `cmake -B build` with your normal configuration options 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`: @@ -46,38 +46,32 @@ Note: base_dir is required for ccache to share cached compiles of the same file You _must not_ set base_dir to "/", or anywhere that contains system headers (according to the ccache docs). -### Disable features with `./configure` +### Disable features when generating the build system -After running `./autogen.sh`, which generates the `./configure` file, use `./configure --help` to identify features that you can disable to save on compilation time. A few common flags: +During the generation of the build system only essential build options are enabled by default to save on compilation time. -```sh ---without-miniupnpc ---without-natpmp ---disable-bench ---disable-wallet ---without-gui -``` +Run `cmake -B build -LH` to see the full list of available options. GUI tools, such as `ccmake` and `cmake-gui`, can be also helpful. -If you do need the wallet enabled, it is common for devs to add `--with-incompatible-bdb`. This uses your system bdb version for the wallet, so you don't have to find a copy of bdb 4.8. Wallets from such a build will be incompatible with any release binary (and vice versa), so use with caution on mainnet. +If you do need the wallet enabled (`-DENABLE_WALLET=ON`), it is common for devs to use your system bdb version for the wallet, so you don't have to find a copy of bdb 4.8. Wallets from such a build will be incompatible with any release binary (and vice versa), so use with caution on mainnet. -### Make use of your threads with `make -j` +### Make use of your threads with `-j` -If you have multiple threads on your machine, you can tell `make` to utilize all of them with: +If you have multiple threads on your machine, you can utilize all of them with: ```sh -make -j"$(($(nproc)+1))" +cmake --build build -j "$(($(nproc)+1))" ``` ### Only build what you need -When rebuilding during development, note that running `make`, without giving a target, will do a lot of work you probably don't need. It will build the GUI (unless you've disabled it) and all the tests (which take much longer to build than the app does). +When rebuilding during development, note that running `cmake --build build`, without giving a target, will do a lot of work you probably don't need. It will build the GUI (if you've enabled it) and all the tests (which take much longer to build than the app does). Obviously, it is important to build and run the tests at appropriate times -- but when you just want a quick compile to check your work, consider picking one or a set of build targets relevant to what you're working on, e.g.: ```sh -make src/bitcoind src/bitcoin-cli -make src/qt/bitcoin-qt -make -C src bitcoin_bench +cmake --build build --target bitcoind bitcoin-cli +cmake --build build --target bitcoin-qt +cmake --build build --target bench_bitcoin ``` (You can and should combine this with `-j`, as above, for a parallel build.) @@ -110,9 +104,9 @@ To squash in `git commit --fixup` commits without rebasing over an updated maste git rebase -i --autosquash "$(git merge-base master HEAD)" ``` -To execute `make check` on every commit since last diverged from master, but without rebasing over an updated master, we can do the following: +To execute `cmake --build build && ctest --test-dir build` on every commit since last diverged from master, but without rebasing over an updated master, we can do the following: ```sh -git rebase -i --exec "make check" "$(git merge-base master HEAD)" +git rebase -i --exec "cmake --build build && ctest --test-dir build" "$(git merge-base master HEAD)" ``` ----- diff --git a/doc/release-notes-27101.md b/doc/release-notes-27101.md deleted file mode 100644 index 8775b59c00..0000000000 --- a/doc/release-notes-27101.md +++ /dev/null @@ -1,9 +0,0 @@ -JSON-RPC --------- - -The JSON-RPC server now recognizes JSON-RPC 2.0 requests and responds with -strict adherence to the specification (https://www.jsonrpc.org/specification): - -- Returning HTTP "204 No Content" responses to JSON-RPC 2.0 notifications instead of full responses. -- Returning HTTP "200 OK" responses in all other cases, rather than 404 responses for unknown methods, 500 responses for invalid parameters, etc. -- Returning either "result" fields or "error" fields in JSON-RPC responses, rather than returning both fields with one field set to null. diff --git a/doc/release-notes-27114.md b/doc/release-notes-27114.md deleted file mode 100644 index 980ffd78a4..0000000000 --- a/doc/release-notes-27114.md +++ /dev/null @@ -1,2 +0,0 @@ -- Additional flags "in" and "out" have been added to `-whitelist` to control whether - permissions apply to incoming connections and/or manual (default: incoming only).
\ No newline at end of file diff --git a/doc/release-notes-27375.md b/doc/release-notes-27375.md deleted file mode 100644 index e3f4ebdf77..0000000000 --- a/doc/release-notes-27375.md +++ /dev/null @@ -1,6 +0,0 @@ -P2P ---- - -UNIX domain sockets can now be used for proxy connections. Set `-onion` or `-proxy` -to the local socket path with the prefix `unix:` (e.g. `-onion=unix:/home/me/torsocket`). -(#27375)
\ No newline at end of file diff --git a/doc/release-notes-27679.md b/doc/release-notes-27679.md deleted file mode 100644 index dbbb30428c..0000000000 --- a/doc/release-notes-27679.md +++ /dev/null @@ -1,2 +0,0 @@ -- unix socket paths are now accepted for `-zmqpubrawblock` and `-zmqpubrawtx` with -the format `-zmqpubrawtx=unix:/path/to/file`
\ No newline at end of file diff --git a/doc/release-notes-28358.md b/doc/release-notes-28358.md new file mode 100644 index 0000000000..336aaa59ed --- /dev/null +++ b/doc/release-notes-28358.md @@ -0,0 +1,6 @@ +Updated settings +------ + +- The maximum allowed value for the `-dbcache` configuration option has been + dropped due to recent UTXO set growth. Note that before this change, large `-dbcache` + values were automatically reduced to 16 GiB (1 GiB on 32 bit systems). (#28358) diff --git a/doc/release-notes-29612.md b/doc/release-notes-29612.md deleted file mode 100644 index 31af3cab09..0000000000 --- a/doc/release-notes-29612.md +++ /dev/null @@ -1,8 +0,0 @@ -RPC ---- - -- The `dumptxoutset` RPC now returns the UTXO set dump in a new and - improved format. At the same time the `loadtxoutset` RPC now - expects this new format in dumps it tries to load. Dumps with the - old format are no longer supported and need to be recreated using - the new format in order to be usable. diff --git a/doc/release-notes-29845.md b/doc/release-notes-29845.md deleted file mode 100644 index 4994d0a34d..0000000000 --- a/doc/release-notes-29845.md +++ /dev/null @@ -1,8 +0,0 @@ -RPC ---- - -- the `warnings` field in `getblockchaininfo`, `getmininginfo` and - `getnetworkinfo` now returns all the active node warnings as an array - of strings, instead of just a single warning. The current behaviour - can temporarily be restored by running bitcoind with configuration - option `-deprecatedrpc=warnings`.
\ No newline at end of file diff --git a/doc/release-notes-30192.md b/doc/release-notes-30192.md deleted file mode 100644 index 2a6c17d455..0000000000 --- a/doc/release-notes-30192.md +++ /dev/null @@ -1,6 +0,0 @@ -Build ------ - -`--enable-lcov-branch-coverage` has been removed, given -incompatibilities between lcov version 1 & 2. `LCOV_OPTS` -should be used to set any options instead. diff --git a/doc/release-notes-empty-template.md b/doc/release-notes-empty-template.md index 96e28c3763..1ff55b5ccc 100644 --- a/doc/release-notes-empty-template.md +++ b/doc/release-notes-empty-template.md @@ -32,11 +32,18 @@ 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. +Running Bitcoin Core binaries on macOS requires self signing. +``` +cd /path/to/bitcoin-core/bin +xattr -d com.apple.quarantine bitcoin-cli bitcoin-qt bitcoin-tx bitcoin-util bitcoin-wallet bitcoind test_bitcoin +codesign -s - bitcoin-cli bitcoin-qt bitcoin-tx bitcoin-util bitcoin-wallet bitcoind test_bitcoin +``` + Compatibility ============== Bitcoin Core is supported and extensively tested on operating systems -using the Linux Kernel 3.17+, macOS 11.0+, and Windows 7 and newer. Bitcoin +using the Linux Kernel 3.17+, macOS 13.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. 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-notes/release-notes-27.1.md b/doc/release-notes/release-notes-27.1.md new file mode 100644 index 0000000000..b19d70da33 --- /dev/null +++ b/doc/release-notes/release-notes-27.1.md @@ -0,0 +1,114 @@ +27.1 Release Notes +===================== + +Bitcoin Core version 27.1 is now available from: + + <https://bitcoincore.org/bin/bitcoin-core-27.1/> + +This release includes 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 3.17+, 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 +=============== + +### Miniscript + +- #29853 sign: don't assume we are parsing a sane TapMiniscript + +### RPC + +- #29869 rpc, bugfix: Enforce maximum value for setmocktime +- #29870 rpc: Reword SighashFromStr error message +- #30094 rpc: move UniValue in blockToJSON + +### Index + +- #29776 Fix #29767, set m_synced = true after Commit() + +### Gui + +- #gui812 Fix create unsigned transaction fee bump +- #gui813 Don't permit port in proxy IP option + +### Test + +- #29892 test: Fix failing univalue float test + +### P2P + +- #30085 p2p: detect addnode cjdns peers in GetAddedNodeInfo() + +### Build + +- #29747 depends: fix mingw-w64 Qt DEBUG=1 build +- #29859 build: Fix false positive CHECK_ATOMIC test +- #29985 depends: Fix build of Qt for 32-bit platforms with recent glibc +- #30097 crypto: disable asan for sha256_sse4 with clang and -O0 +- #30151 depends: Fetch miniupnpc sources from an alternative website +- #30216 build: Fix building fuzz binary on on SunOS / illumos +- #30217 depends: Update Boost download link + +### Doc + +- #29934 doc: add LLVM instruction for macOS < 13 + +### CI + +- #29856 ci: Bump s390x to ubuntu:24.04 + +### Misc + +- #29691 Change Luke Dashjr seed to dashjr-list-of-p2p-nodes.us +- #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 +- furszy +- Hennadii Stepanov +- Jon Atack +- laanwj +- Luke Dashjr +- MarcoFalke +- nanlour +- Sjors Provoost +- willcl-ark + +As well as to everyone that helped with translations on +[Transifex](https://www.transifex.com/bitcoin/bitcoin/). diff --git a/doc/release-notes/release-notes-27064.md b/doc/release-notes/release-notes-27064.md deleted file mode 100644 index be3ecee1b8..0000000000 --- a/doc/release-notes/release-notes-27064.md +++ /dev/null @@ -1,7 +0,0 @@ -Files ------ - -The default data directory on Windows has been moved from `C:\Users\Username\AppData\Roaming\Bitcoin` -to `C:\Users\Username\AppData\Local\Bitcoin`. Bitcoin Core will check the existence -of the old directory first and continue to use that directory for backwards -compatibility if it is present.
\ No newline at end of file diff --git a/doc/release-notes/release-notes-28.0.md b/doc/release-notes/release-notes-28.0.md new file mode 100644 index 0000000000..d9e6a34d0f --- /dev/null +++ b/doc/release-notes/release-notes-28.0.md @@ -0,0 +1,371 @@ +Bitcoin Core version 28.0 is now available from: + + <https://bitcoincore.org/bin/bitcoin-core-28.0/> + +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. + +Running Bitcoin Core binaries on macOS requires self signing. +``` +cd /path/to/bitcoin-28.0/bin +xattr -d com.apple.quarantine bitcoin-cli bitcoin-qt bitcoin-tx bitcoin-util bitcoin-wallet bitcoind test_bitcoin +codesign -s - bitcoin-cli bitcoin-qt bitcoin-tx bitcoin-util bitcoin-wallet bitcoind test_bitcoin +``` + +Compatibility +============== + +Bitcoin Core is supported and extensively tested on operating systems +using the Linux Kernel 3.17+, 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 +=============== + +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. (#29775) + +Windows Data Directory +---------------------- + +The default data directory on Windows has been moved from `C:\Users\Username\AppData\Roaming\Bitcoin` +to `C:\Users\Username\AppData\Local\Bitcoin`. Bitcoin Core will check the existence +of the old directory first and continue to use that directory for backwards +compatibility if it is present. (#27064) + +JSON-RPC 2.0 Support +-------------------- + +The JSON-RPC server now recognizes JSON-RPC 2.0 requests and responds with +strict adherence to the [specification](https://www.jsonrpc.org/specification). +See [JSON-RPC-interface.md](https://github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md#json-rpc-11-vs-20) for details. (#27101) + +JSON-RPC clients may need to be updated to be compatible with the JSON-RPC server. +Please open an issue on GitHub if any compatibility issues are found. + +libbitcoinconsensus Removal +--------------------------- + +The libbitcoin-consensus library was deprecated in 27.0 and is now completely removed. (#29648) + +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) + +- UNIX domain sockets can now be used for proxy connections. Set `-onion` or `-proxy` + to the local socket path with the prefix `unix:` (e.g. `-onion=unix:/home/me/torsocket`). + (#27375) + +- UNIX socket paths are now accepted for `-zmqpubrawblock` and `-zmqpubrawtx` with + the format `-zmqpubrawtx=unix:/path/to/file` (#27679) + +- Additional "in" and "out" flags have been added to `-whitelist` to control whether + permissions apply to inbound connections and/or manual ones (default: inbound only). (#27114) + +- Transactions having a feerate that is too low will be opportunistically paired with + their child transactions and submitted as a package, thus enabling the node to download + 1-parent-1-child packages using the existing transaction relay protocol. Combined with + other mempool policies, this change allows limited "package relay" when a parent transaction + is below the mempool minimum feerate. Topologically Restricted Until Confirmation (TRUC) + parents are additionally allowed to be below the minimum relay feerate (i.e., pay 0 fees). + Use the `submitpackage` RPC to submit packages directly to the node. Warning: this P2P + feature is limited (unlike the `submitpackage` interface, a child with multiple unconfirmed + parents is not supported) and not yet reliable under adversarial conditions. (#28970) + +Mempool Policy Changes +---------------------- + +- Transactions with version number set to 3 are now treated as standard on all networks (#29496), + subject to opt-in Topologically Restricted Until Confirmation (TRUC) transaction policy as + described in [BIP 431](https://github.com/bitcoin/bips/blob/master/bip-0431.mediawiki). The + policy includes limits on spending unconfirmed outputs (#28948), eviction of a previous descendant + if a more incentive-compatible one is submitted (#29306), and a maximum transaction size of 10,000vB + (#29873). These restrictions simplify the assessment of incentive compatibility of accepting or + replacing TRUC transactions, thus ensuring any replacements are more profitable for the node and + making fee-bumping more reliable. + +- 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. (#30352) + +- Limited package RBF is now enabled, where the proposed conflicting package would result in + a connected component, aka cluster, of size 2 in the mempool. All clusters being conflicted + against must be of size 2 or lower. (#28984) + +- The default value of the `-mempoolfullrbf` configuration option has been changed from 0 to 1, + i.e. `mempoolfullrbf=1`. (#30493) + +Updated RPCs +------------ + +- The `dumptxoutset` RPC now returns the UTXO set dump in a new and + improved format. Correspondingly, the `loadtxoutset` RPC now expects + this new format in the dumps it tries to load. Dumps with the old + format are no longer supported and need to be recreated using the + new format to be usable. (#29612) + +- AssumeUTXO mainnet parameters have been added for height 840,000. + This means the `loadtxoutset` RPC can now be used on mainnet with + the matching UTXO set from that height. (#28553) + +- The `warnings` field in `getblockchaininfo`, `getmininginfo` and + `getnetworkinfo` now returns all the active node warnings as an array + of strings, instead of a single warning. The current behaviour + can be temporarily restored by running Bitcoin Core with the configuration + option `-deprecatedrpc=warnings`. (#29845) + +- Previously when using the `sendrawtransaction` RPC and specifying outputs + that are already in the UTXO set, an RPC error code of `-27` with the + message "Transaction already in block chain" was returned in response. + The error message has been changed to "Transaction outputs already in utxo set" + to more accurately describe the source of the issue. (#30212) + +- The default mode for the `estimatesmartfee` RPC has been updated from `conservative` to `economical`, + which is expected to reduce over-estimation 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 over-estimating, + the `conservative` mode remains available. (#30275) + +- RPC `scantxoutset` now returns 2 new fields in the "unspents" JSON array: `blockhash` and `confirmations`. + See the scantxoutset help for details. (#30515) + +- RPC `submitpackage` now allows 2 new arguments to be passed: `maxfeerate` and `maxburnamount`. See the + subtmitpackage help for details. (#28950) + +Changes to wallet-related RPCs can be found in the Wallet section below. + +Updated REST APIs +----------------- +- Parameter validation for `/rest/getutxos` has been improved by rejecting + truncated or overly large txids and malformed outpoint indices via raising + an HTTP_BAD_REQUEST "Parse error". These requests were previously handled + silently. (#30482, #30444) + +Build System +------------ + +- GCC 11.1 or later, or Clang 16.0 or later, +are now required to compile Bitcoin Core. (#29091, #30263) + +- The minimum required glibc to run Bitcoin Core is now +2.31. This means that RHEL 8 and Ubuntu 18.04 (Bionic) +are no-longer supported. (#29987) + +- `--enable-lcov-branch-coverage` has been removed, given +incompatibilities between lcov version 1 & 2. `LCOV_OPTS` +should be used to set any options instead. (#30192) + +Updated Settings +---------------- + +- When running with `-alertnotify`, an alert can now be raised multiple +times instead of just once. Previously, it was only raised when unknown +new consensus rules were activated. Its scope has now been increased to +include all kernel warnings. Specifically, alerts will now also be raised +when an invalid chain with a large amount of work has been detected. +Additional warnings may be added in the future. (#30058) + +Changes to GUI or wallet related settings can be found in the GUI or Wallet section below. + +Wallet +------ + +- The wallet now detects when wallet transactions conflict with the mempool. Mempool-conflicting + transactions can be seen in the `"mempoolconflicts"` field of `gettransaction`. The inputs + of mempool-conflicted transactions can now be respent without manually abandoning the + transactions when the parent transaction is dropped from the mempool, which can cause wallet + balances to appear higher. (#27307) + +- A new `max_tx_weight` option has been added to the RPCs `fundrawtransaction`, `walletcreatefundedpsbt`, and `send`. +It specifies the maximum transaction weight. If the limit is exceeded during funding, the transaction will not be built. +The default value is 4,000,000 WU. (#29523) + +- A new `createwalletdescriptor` RPC allows users to add new automatically generated + descriptors to their wallet. This can be used to upgrade wallets created prior to the + introduction of a new standard descriptor, such as taproot. (#29130) + +- A new RPC `gethdkeys` lists all of the BIP32 HD keys in use by all of the descriptors in the wallet. + These keys can be used in conjunction with `createwalletdescriptor` to create and add single key + descriptors to the wallet for a particular key that the wallet already knows. (#29130) + +- The `sendall` RPC can now spend unconfirmed change and will include additional fees as necessary + for the resulting transaction to bump the unconfirmed transactions' feerates to the specified feerate. (#28979) + +- In RPC `bumpfee`, if a `fee_rate` is specified, the feerate is no longer restricted + to following the wallet's incremental feerate of 5 sat/vb. The feerate must still be + at least the sum of the original fee and the mempool's incremental feerate. (#27969) + +GUI Changes +----------- + +- The "Migrate Wallet" menu allows users to migrate any legacy wallet in their wallet +directory, regardless of the wallets loaded. (gui#824) + +- The "Information" window now displays the maximum mempool size along with the +mempool usage. (gui#825) + +Low-level Changes +================= + +Tests +----- + +- The BIP94 timewarp attack mitigation is now active on the `regtest` network. (#30681) + +- A new `-testdatadir` option has been added to `test_bitcoin` to allow specifying the + location of unit test data directories. (#26564) + +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. (#28052) + +Chainstate +---------- + +- The chainstate database flushes that occur when blocks are pruned will no longer +empty the database cache. The cache will remain populated longer, which significantly +reduces the time for initial block download to complete. (#28280) + +Dependencies +------------ + +- The dependency on Boost.Process has been replaced with cpp-subprocess, which is contained in source. +Builders will no longer need Boost.Process to build with external signer support. (#28981) + +Credits +======= + +Thanks to everyone who directly contributed to this release: +- 0xb10c +- Alfonso Roman Zubeldia +- Andrew Toth +- AngusP +- Anthony Towns +- Antoine Poinsot +- Anton A +- Ava Chow +- Ayush Singh +- Ben Westgate +- Brandon Odiwuor +- brunoerg +- bstin +- Charlie +- Christopher Bergqvist +- Cory Fields +- crazeteam +- Daniela Brozzoni +- David Gumberg +- dergoegge +- Edil Medeiros +- Epic Curious +- Fabian Jahr +- fanquake +- furszy +- glozow +- Greg Sanders +- hanmz +- Hennadii Stepanov +- Hernan Marino +- Hodlinator +- ishaanam +- ismaelsadeeq +- Jadi +- Jon Atack +- josibake +- jrakibi +- kevkevin +- kevkevinpal +- Konstantin Akimov +- laanwj +- Larry Ruane +- Lőrinc +- Luis Schwab +- Luke Dashjr +- MarcoFalke +- marcofleon +- Marnix +- Martin Saposnic +- Martin Zumsande +- Matt Corallo +- Matthew Zipkin +- Matt Whitlock +- Max Edwards +- Michael Dietz +- Murch +- nanlour +- pablomartin4btc +- Peter Todd +- Pieter Wuille +- @RandyMcMillan +- RoboSchmied +- Roman Zeyde +- Ryan Ofsky +- Sebastian Falbesoner +- Sergi Delgado Segura +- Sjors Provoost +- spicyzboss +- StevenMia +- stickies-v +- stratospher +- Suhas Daftuar +- sunerok +- tdb3 +- TheCharlatan +- umiumi +- Vasil Dimov +- virtu +- 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..aeaed8d68c 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -5,14 +5,14 @@ Release Process ### Before every release candidate -* Update release candidate version in `configure.ac` (`CLIENT_VERSION_RC`). +* Update release candidate version in `CMakeLists.txt` (`CLIENT_VERSION_RC`). * Update manpages (after rebuilding the binaries), see [gen-manpages.py](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-manpagespy). * Update bitcoin.conf and commit changes if they exist, see [gen-bitcoin-conf.sh](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-bitcoin-confsh). ### Before every major and minor release * Update [bips.md](bips.md) to account for changes since the last release. -* Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_RC` to `0`). +* Update version in `CMakeLists.txt` (don't forget to set `CLIENT_VERSION_RC` to `0`). * Update manpages (see previous section) * Write release notes (see "Write the release notes" below) in doc/release-notes.md. If necessary, archive the previous release notes as doc/release-notes/release-notes-${VERSION}.md. @@ -20,8 +20,8 @@ Release Process ### Before every major release * On both the master branch and the new release branch: - - update `CLIENT_VERSION_MAJOR` in [`configure.ac`](../configure.ac) -* On the new release branch in [`configure.ac`](../configure.ac)(see [this commit](https://github.com/bitcoin/bitcoin/commit/742f7dd)): + - update `CLIENT_VERSION_MAJOR` in [`CMakeLists.txt`](../CMakeLists.txt) +* On the new release branch in [`CMakeLists.txt`](../CMakeLists.txt)(see [this commit](https://github.com/bitcoin/bitcoin/commit/742f7dd)): - set `CLIENT_VERSION_MINOR` to `0` - set `CLIENT_VERSION_BUILD` to `0` - set `CLIENT_VERSION_IS_RELEASE` to `true` @@ -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/doc/tracing.md b/doc/tracing.md index 0e3414205a..c12af122db 100644 --- a/doc/tracing.md +++ b/doc/tracing.md @@ -106,7 +106,7 @@ Arguments passed: 3. Transactions in the Block as `uint64` 4. Inputs spend in the Block as `int32` 5. SigOps in the Block (excluding coinbase SigOps) `uint64` -6. Time it took to connect the Block in microseconds (µs) as `uint64` +6. Time it took to connect the Block in nanoseconds (ns) as `uint64` ### Context `utxocache` @@ -366,13 +366,13 @@ USDT support. To list probes in Bitcoin Core, use `info probes` in `gdb`: ``` -$ gdb ./src/bitcoind +$ gdb ./build/src/bitcoind … (gdb) info probes Type Provider Name Where Semaphore Object -stap net inbound_message 0x000000000014419e /src/bitcoind -stap net outbound_message 0x0000000000107c05 /src/bitcoind -stap validation block_connected 0x00000000002fb10c /src/bitcoind +stap net inbound_message 0x000000000014419e /build/src/bitcoind +stap net outbound_message 0x0000000000107c05 /build/src/bitcoind +stap validation block_connected 0x00000000002fb10c /build/src/bitcoind … ``` @@ -382,7 +382,7 @@ The `readelf` tool can be used to display the USDT tracepoints in Bitcoin Core. Look for the notes with the description `NT_STAPSDT`. ``` -$ readelf -n ./src/bitcoind | grep NT_STAPSDT -A 4 -B 2 +$ readelf -n ./build/src/bitcoind | grep NT_STAPSDT -A 4 -B 2 Displaying notes found in: .note.stapsdt Owner Data size Description stapsdt 0x0000005d NT_STAPSDT (SystemTap probe descriptors) @@ -406,7 +406,7 @@ between distributions. For example, on [ubuntu binary]: https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---binary ``` -$ tplist -l ./src/bitcoind -v +$ tplist -l ./build/src/bitcoind -v b'net':b'outbound_message' [sema 0x0] 1 location(s) 6 argument(s) diff --git a/doc/translation_process.md b/doc/translation_process.md index e5ed7f4e0a..f4f0add54f 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -18,8 +18,8 @@ We use automated scripts to help extract translations in both Qt, and non-Qt sou To automatically regenerate the `bitcoin_en.ts` file, run the following commands: ```sh -cd src/ -make translate +cmake -B build --preset dev-mode -DWITH_BDB=ON -DBUILD_GUI=ON +cmake --build build --target translate ``` **Example Qt translation** diff --git a/doc/translation_strings_policy.md b/doc/translation_strings_policy.md index 1931302dda..4aa4969209 100644 --- a/doc/translation_strings_policy.md +++ b/doc/translation_strings_policy.md @@ -1,10 +1,8 @@ -Translation Strings Policy -=========================== +# Translation Strings Policy This document provides guidelines for internationalization of the Bitcoin Core software. -How to translate? ------------------- +## How to translate? To mark a message as translatable @@ -14,8 +12,7 @@ To mark a message as translatable No internationalization is used for e.g. developer scripts outside `src`. -Strings to be translated -------------------------- +## Strings to be translated On a high level, these strings are to be translated: @@ -27,8 +24,7 @@ Do not translate technical or extremely rare errors. Anything else that appears to the user in the GUI is to be translated. This includes labels, menu items, button texts, tooltips and window titles. This includes messages passed to the GUI through the UI interface through `InitMessage`, `ThreadSafeMessageBox` or `ShowProgress`. -General recommendations ------------------------- +## General recommendations ### Avoid unnecessary translation strings @@ -97,4 +93,4 @@ The second example reduces the number of pluralized words that translators have During a string freeze (often before a major release), no translation strings are to be added, modified or removed. -This can be checked by executing `make translate` in the `src` directory, then verifying that `bitcoin_en.ts` remains unchanged. +This can be checked by building the `translate` target with `cmake` ([instructions](translation_process.md)), then verifying that `bitcoin_en.ts` remains unchanged. diff --git a/doc/zmq.md b/doc/zmq.md index 07c340fb99..0a74d6eef9 100644 --- a/doc/zmq.md +++ b/doc/zmq.md @@ -46,11 +46,10 @@ operation. ## Enabling -By default, the ZeroMQ feature is automatically compiled in if the -necessary prerequisites are found. To disable, use --disable-zmq -during the *configure* step of building bitcoind: +By default, the ZeroMQ feature is not automatically compiled. +To enable, use `-DWITH_ZMQ=ON` when configuring the build system: - $ ./configure --disable-zmq (other options) + $ cmake -B build -DWITH_ZMQ=ON To actually enable operation, one must set the appropriate options on the command line or in the configuration file. @@ -163,7 +162,7 @@ Note that for `*block` topics, when the block chain tip changes, a reorganisation may occur and just the tip will be notified. It is up to the subscriber to retrieve the chain from the last known block to the new tip. Also note that no notification will occur if the tip -was in the active chain--as would be the case after calling invalidateblock RPC. +was in the active chain, as would be the case after calling the `invalidateblock` RPC. In contrast, the `sequence` topic publishes all block connections and disconnections. diff --git a/libbitcoinkernel.pc.in b/libbitcoinkernel.pc.in new file mode 100644 index 0000000000..a2cb7d3692 --- /dev/null +++ b/libbitcoinkernel.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PACKAGE_NAME@ kernel library +Description: Experimental library for the Bitcoin Core validation engine. +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lbitcoinkernel +Libs.private: -L${libdir} @LIBS_PRIVATE@ +Cflags: -I${includedir} diff --git a/share/genbuild.sh b/share/genbuild.sh deleted file mode 100755 index ecc96160e6..0000000000 --- a/share/genbuild.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# Copyright (c) 2012-2021 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -export LC_ALL=C -if [ $# -gt 1 ]; then - cd "$2" || exit 1 -fi -if [ $# -gt 0 ]; then - FILE="$1" - shift - if [ -f "$FILE" ]; then - INFO="$(head -n 1 "$FILE")" - fi -else - echo "Usage: $0 <filename> <srcroot>" - exit 1 -fi - -GIT_TAG="" -GIT_COMMIT="" -if [ "${BITCOIN_GENBUILD_NO_GIT}" != "1" ] && [ -e "$(command -v git)" ] && [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then - # clean 'dirty' status of touched files that haven't been modified - git diff >/dev/null 2>/dev/null - - # if latest commit is tagged and not dirty, then override using the tag name - RAWDESC=$(git describe --abbrev=0 2>/dev/null) - if [ "$(git rev-parse HEAD)" = "$(git rev-list -1 "$RAWDESC" 2>/dev/null)" ]; then - git diff-index --quiet HEAD -- && GIT_TAG=$RAWDESC - fi - - # otherwise generate suffix from git, i.e. string like "59887e8-dirty" - GIT_COMMIT=$(git rev-parse --short=12 HEAD) - git diff-index --quiet HEAD -- || GIT_COMMIT="$GIT_COMMIT-dirty" -fi - -if [ -n "$GIT_TAG" ]; then - NEWINFO="#define BUILD_GIT_TAG \"$GIT_TAG\"" -elif [ -n "$GIT_COMMIT" ]; then - NEWINFO="#define BUILD_GIT_COMMIT \"$GIT_COMMIT\"" -else - NEWINFO="// No build information available" -fi - -# only update build.h if necessary -if [ "$INFO" != "$NEWINFO" ]; then - echo "$NEWINFO" >"$FILE" -fi diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index b4e6f6a150..5ff736152f 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -3,7 +3,7 @@ <plist version="0.9"> <dict> <key>LSMinimumSystemVersion</key> - <string>11</string> + <string>13</string> <key>LSArchitecturePriority</key> <array> diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py index 39acec8942..4297143023 100755 --- a/share/qt/extract_strings_qt.py +++ b/share/qt/extract_strings_qt.py @@ -56,7 +56,7 @@ files = sys.argv[1:] XGETTEXT=os.getenv('XGETTEXT', 'xgettext') if not XGETTEXT: print('Cannot extract strings: xgettext utility is not installed or not configured.',file=sys.stderr) - print('Please install package "gettext" and re-run \'./configure\'.',file=sys.stderr) + print('Please install package "gettext" and re-run \'cmake -B build\'.',file=sys.stderr) sys.exit(1) child = Popen([XGETTEXT,'--output=-','--from-code=utf-8','-n','--keyword=_'] + files, stdout=PIPE) (out, err) = child.communicate() diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 2ce798bd2d..f22e256967 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -95,7 +95,9 @@ Section -post SEC0001 !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory $SMPROGRAMS\$StartMenuGroup CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet, 64-bit).lnk" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "-testnet" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" 1 + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet).lnk" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "-testnet" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" 1 + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (test signet).lnk" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "-signet" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" 2 + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet4).lnk" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "-testnet4" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" 3 CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_END WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" @@ -140,7 +142,9 @@ Section -un.post UNSEC0001 DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" - Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet, 64-bit).lnk" + Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet).lnk" + Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet4).lnk" + Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (test signet).lnk" Delete /REBOOTOK "$SMSTARTUP\Bitcoin.lnk" Delete /REBOOTOK $INSTDIR\uninstall.exe Delete /REBOOTOK $INSTDIR\debug.log diff --git a/src/.bear-tidy-config b/src/.bear-tidy-config deleted file mode 100644 index 0ab30a8d9d..0000000000 --- a/src/.bear-tidy-config +++ /dev/null @@ -1,21 +0,0 @@ -{ - "output": { - "content": { - "include_only_existing_source": true, - "paths_to_include": [], - "paths_to_exclude": [ - "src/crc32c", - "src/crypto/ctaes", - "src/leveldb", - "src/minisketch", - "src/bench/nanobench.cpp", - "src/bench/nanobench.h", - "src/secp256k1" - ] - }, - "format": { - "command_as_array": true, - "drop_output_field": false - } - } -} diff --git a/src/.clang-tidy b/src/.clang-tidy index 61adce1d50..1cf270833a 100644 --- a/src/.clang-tidy +++ b/src/.clang-tidy @@ -6,12 +6,15 @@ 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, +modernize-use-starts-ends-with, performance-*, -performance-avoid-endl, -performance-enum-size, @@ -23,8 +26,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/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..4a86465bba --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,454 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include(GNUInstallDirs) +include(AddWindowsResources) + +configure_file(${PROJECT_SOURCE_DIR}/cmake/bitcoin-build-config.h.in bitcoin-build-config.h USE_SOURCE_PERMISSIONS @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +add_custom_target(generate_build_info + BYPRODUCTS ${PROJECT_BINARY_DIR}/src/bitcoin-build-info.h + COMMAND ${CMAKE_COMMAND} -DBUILD_INFO_HEADER_PATH=${PROJECT_BINARY_DIR}/src/bitcoin-build-info.h -DSOURCE_DIR=${PROJECT_SOURCE_DIR} -P ${PROJECT_SOURCE_DIR}/cmake/script/GenerateBuildInfo.cmake + COMMENT "Generating bitcoin-build-info.h" + VERBATIM +) +add_library(bitcoin_clientversion OBJECT EXCLUDE_FROM_ALL + clientversion.cpp +) +target_link_libraries(bitcoin_clientversion + PRIVATE + core_interface +) +add_dependencies(bitcoin_clientversion generate_build_info) + +add_subdirectory(crypto) +add_subdirectory(univalue) +add_subdirectory(util) +if(WITH_MULTIPROCESS) + add_subdirectory(ipc) +endif() + +#============================= +# secp256k1 subtree +#============================= +message("") +message("Configuring secp256k1 subtree...") +set(SECP256K1_DISABLE_SHARED ON CACHE BOOL "" FORCE) +set(SECP256K1_ENABLE_MODULE_ECDH OFF CACHE BOOL "" FORCE) +set(SECP256K1_ENABLE_MODULE_RECOVERY ON CACHE BOOL "" FORCE) +set(SECP256K1_BUILD_BENCHMARK OFF CACHE BOOL "" FORCE) +set(SECP256K1_BUILD_TESTS ${BUILD_TESTS} CACHE BOOL "" FORCE) +set(SECP256K1_BUILD_EXHAUSTIVE_TESTS ${BUILD_TESTS} CACHE BOOL "" FORCE) +if(NOT BUILD_TESTS) + # Always skip the ctime tests, if we are building no other tests. + # Otherwise, they are built if Valgrind is available. See SECP256K1_VALGRIND. + set(SECP256K1_BUILD_CTIME_TESTS ${BUILD_TESTS} CACHE BOOL "" FORCE) +endif() +set(SECP256K1_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +include(GetTargetInterface) +# -fsanitize and related flags apply to both C++ and C, +# so we can pass them down to libsecp256k1 as CFLAGS and LDFLAGS. +get_target_interface(core_sanitizer_cxx_flags "" sanitize_interface COMPILE_OPTIONS) +set(SECP256K1_APPEND_CFLAGS ${core_sanitizer_cxx_flags} CACHE STRING "" FORCE) +unset(core_sanitizer_cxx_flags) +get_target_interface(core_sanitizer_linker_flags "" sanitize_interface LINK_OPTIONS) +set(SECP256K1_APPEND_LDFLAGS ${core_sanitizer_linker_flags} CACHE STRING "" FORCE) +unset(core_sanitizer_linker_flags) +# We want to build libsecp256k1 with the most tested RelWithDebInfo configuration. +enable_language(C) +foreach(config IN LISTS CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES) + if(config STREQUAL "") + continue() + endif() + string(TOUPPER "${config}" config) + set(CMAKE_C_FLAGS_${config} "${CMAKE_C_FLAGS_RELWITHDEBINFO}") +endforeach() +# If the CFLAGS environment variable is defined during building depends +# and configuring this build system, its content might be duplicated. +if(DEFINED ENV{CFLAGS}) + deduplicate_flags(CMAKE_C_FLAGS) +endif() +set(CMAKE_EXPORT_COMPILE_COMMANDS OFF) +add_subdirectory(secp256k1) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +string(APPEND CMAKE_C_COMPILE_OBJECT " ${APPEND_CPPFLAGS} ${APPEND_CFLAGS}") + +add_library(bitcoin_consensus STATIC EXCLUDE_FROM_ALL + arith_uint256.cpp + consensus/merkle.cpp + consensus/tx_check.cpp + hash.cpp + primitives/block.cpp + primitives/transaction.cpp + pubkey.cpp + script/interpreter.cpp + script/script.cpp + script/script_error.cpp + uint256.cpp +) +target_link_libraries(bitcoin_consensus + PRIVATE + core_interface + bitcoin_crypto + secp256k1 +) + +if(WITH_ZMQ) + add_subdirectory(zmq) +endif() + +# Home for common functionality shared by different executables and libraries. +# Similar to `bitcoin_util` library, but higher-level. +add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL + addresstype.cpp + base58.cpp + bech32.cpp + chainparams.cpp + chainparamsbase.cpp + coins.cpp + common/args.cpp + common/bloom.cpp + common/config.cpp + common/init.cpp + common/interfaces.cpp + common/messages.cpp + common/netif.cpp + common/pcp.cpp + common/run_command.cpp + common/settings.cpp + common/signmessage.cpp + common/system.cpp + common/url.cpp + compressor.cpp + core_read.cpp + core_write.cpp + deploymentinfo.cpp + external_signer.cpp + init/common.cpp + kernel/chainparams.cpp + key.cpp + key_io.cpp + merkleblock.cpp + net_permissions.cpp + net_types.cpp + netaddress.cpp + netbase.cpp + outputtype.cpp + policy/feerate.cpp + policy/policy.cpp + protocol.cpp + psbt.cpp + rpc/external_signer.cpp + rpc/rawtransaction_util.cpp + rpc/request.cpp + rpc/util.cpp + scheduler.cpp + script/descriptor.cpp + script/miniscript.cpp + script/parsing.cpp + script/sign.cpp + script/signingprovider.cpp + script/solver.cpp +) +target_link_libraries(bitcoin_common + PRIVATE + core_interface + bitcoin_consensus + bitcoin_util + univalue + secp256k1 + Boost::headers + $<TARGET_NAME_IF_EXISTS:USDT::headers> + $<$<PLATFORM_ID:Windows>:ws2_32> +) + + +set(installable_targets) +if(ENABLE_WALLET) + add_subdirectory(wallet) + + if(BUILD_WALLET_TOOL) + add_executable(bitcoin-wallet + bitcoin-wallet.cpp + init/bitcoin-wallet.cpp + wallet/wallettool.cpp + ) + add_windows_resources(bitcoin-wallet bitcoin-wallet-res.rc) + target_link_libraries(bitcoin-wallet + core_interface + bitcoin_wallet + bitcoin_common + bitcoin_util + Boost::headers + ) + list(APPEND installable_targets bitcoin-wallet) + endif() +endif() + + +# P2P and RPC server functionality used by `bitcoind` and `bitcoin-qt` executables. +add_library(bitcoin_node STATIC EXCLUDE_FROM_ALL + addrdb.cpp + addrman.cpp + banman.cpp + bip324.cpp + blockencodings.cpp + blockfilter.cpp + chain.cpp + consensus/tx_verify.cpp + dbwrapper.cpp + deploymentstatus.cpp + flatfile.cpp + headerssync.cpp + httprpc.cpp + httpserver.cpp + i2p.cpp + index/base.cpp + index/blockfilterindex.cpp + index/coinstatsindex.cpp + index/txindex.cpp + init.cpp + kernel/chain.cpp + kernel/checks.cpp + kernel/coinstats.cpp + kernel/context.cpp + kernel/cs_main.cpp + kernel/disconnected_transactions.cpp + kernel/mempool_removal_reason.cpp + mapport.cpp + net.cpp + net_processing.cpp + netgroup.cpp + node/abort.cpp + node/blockmanager_args.cpp + node/blockstorage.cpp + node/caches.cpp + node/chainstate.cpp + node/chainstatemanager_args.cpp + node/coin.cpp + node/coins_view_args.cpp + node/connection_types.cpp + node/context.cpp + node/database_args.cpp + node/eviction.cpp + node/interface_ui.cpp + node/interfaces.cpp + node/kernel_notifications.cpp + node/mempool_args.cpp + node/mempool_persist.cpp + node/mempool_persist_args.cpp + node/miner.cpp + node/mini_miner.cpp + node/minisketchwrapper.cpp + node/peerman_args.cpp + node/psbt.cpp + node/timeoffsets.cpp + node/transaction.cpp + node/txreconciliation.cpp + node/utxo_snapshot.cpp + node/warnings.cpp + noui.cpp + policy/fees.cpp + policy/fees_args.cpp + policy/packages.cpp + policy/rbf.cpp + policy/settings.cpp + policy/truc_policy.cpp + pow.cpp + rest.cpp + rpc/blockchain.cpp + rpc/fees.cpp + rpc/mempool.cpp + rpc/mining.cpp + rpc/net.cpp + rpc/node.cpp + rpc/output_script.cpp + rpc/rawtransaction.cpp + rpc/server.cpp + rpc/server_util.cpp + rpc/signmessage.cpp + rpc/txoutproof.cpp + script/sigcache.cpp + signet.cpp + torcontrol.cpp + txdb.cpp + txmempool.cpp + txorphanage.cpp + txrequest.cpp + validation.cpp + validationinterface.cpp + versionbits.cpp + $<$<TARGET_EXISTS:bitcoin_wallet>:wallet/init.cpp> + $<$<NOT:$<TARGET_EXISTS:bitcoin_wallet>>:dummywallet.cpp> +) +target_link_libraries(bitcoin_node + PRIVATE + core_interface + bitcoin_common + bitcoin_util + leveldb + minisketch + univalue + Boost::headers + $<TARGET_NAME_IF_EXISTS:libevent::libevent> + $<TARGET_NAME_IF_EXISTS:libevent::pthreads> + $<TARGET_NAME_IF_EXISTS:MiniUPnPc::MiniUPnPc> + $<TARGET_NAME_IF_EXISTS:bitcoin_zmq> + $<TARGET_NAME_IF_EXISTS:USDT::headers> +) + + +# Bitcoin Core bitcoind. +if(BUILD_DAEMON) + add_executable(bitcoind + bitcoind.cpp + init/bitcoind.cpp + ) + add_windows_resources(bitcoind bitcoind-res.rc) + target_link_libraries(bitcoind + core_interface + bitcoin_node + $<TARGET_NAME_IF_EXISTS:bitcoin_wallet> + ) + list(APPEND installable_targets bitcoind) +endif() +if(WITH_MULTIPROCESS) + add_executable(bitcoin-node + bitcoind.cpp + init/bitcoin-node.cpp + ) + target_link_libraries(bitcoin-node + core_interface + bitcoin_node + bitcoin_ipc + $<TARGET_NAME_IF_EXISTS:bitcoin_wallet> + ) + list(APPEND installable_targets bitcoin-node) + + if(BUILD_TESTS) + # bitcoin_ipc_test library target is defined here in src/CMakeLists.txt + # instead of src/test/CMakeLists.txt so capnp files in src/test/ are able to + # reference capnp files in src/ipc/capnp/ by relative path. The Cap'n Proto + # compiler only allows importing by relative path when the importing and + # imported files are underneath the same compilation source prefix, so the + # source prefix must be src/, not src/test/ + add_library(bitcoin_ipc_test STATIC EXCLUDE_FROM_ALL + test/ipc_test.cpp + ) + target_capnp_sources(bitcoin_ipc_test ${PROJECT_SOURCE_DIR} + test/ipc_test.capnp + ) + add_dependencies(bitcoin_ipc_test bitcoin_ipc_headers) + endif() +endif() + + +add_library(bitcoin_cli STATIC EXCLUDE_FROM_ALL + compat/stdin.cpp + rpc/client.cpp +) +target_link_libraries(bitcoin_cli + PUBLIC + core_interface + univalue +) + + +# Bitcoin Core RPC client +if(BUILD_CLI) + add_executable(bitcoin-cli bitcoin-cli.cpp) + add_windows_resources(bitcoin-cli bitcoin-cli-res.rc) + target_link_libraries(bitcoin-cli + core_interface + bitcoin_cli + bitcoin_common + bitcoin_util + $<TARGET_NAME_IF_EXISTS:libevent::libevent> + ) + list(APPEND installable_targets bitcoin-cli) +endif() + + +if(BUILD_TX) + add_executable(bitcoin-tx bitcoin-tx.cpp) + add_windows_resources(bitcoin-tx bitcoin-tx-res.rc) + target_link_libraries(bitcoin-tx + core_interface + bitcoin_common + bitcoin_util + univalue + ) + list(APPEND installable_targets bitcoin-tx) +endif() + + +if(BUILD_UTIL) + add_executable(bitcoin-util bitcoin-util.cpp) + add_windows_resources(bitcoin-util bitcoin-util-res.rc) + target_link_libraries(bitcoin-util + core_interface + bitcoin_common + bitcoin_util + ) + list(APPEND installable_targets bitcoin-util) +endif() + + +if(BUILD_GUI) + add_subdirectory(qt) +endif() + + +if(BUILD_KERNEL_LIB) + add_subdirectory(kernel) +endif() + +if(BUILD_UTIL_CHAINSTATE) + add_executable(bitcoin-chainstate + bitcoin-chainstate.cpp + ) + # TODO: The `SKIP_BUILD_RPATH` property setting can be deleted + # in the future after reordering Guix script commands to + # perform binary checks after the installation step. + # Relevant discussions: + # - https://github.com/hebasto/bitcoin/pull/236#issuecomment-2183120953 + # - https://github.com/bitcoin/bitcoin/pull/30312#issuecomment-2191235833 + set_target_properties(bitcoin-chainstate PROPERTIES + SKIP_BUILD_RPATH OFF + ) + target_link_libraries(bitcoin-chainstate + PRIVATE + core_interface + bitcoinkernel + ) +endif() + + +add_subdirectory(test/util) +if(BUILD_BENCH) + add_subdirectory(bench) +endif() + +if(BUILD_TESTS) + add_subdirectory(test) +endif() + +if(BUILD_FUZZ_BINARY) + add_subdirectory(test/fuzz) +endif() + + +install(TARGETS ${installable_targets} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) +unset(installable_targets) + +if(INSTALL_MAN) + # TODO: these stubs are no longer needed. man pages should be generated at install time. + install(DIRECTORY ../doc/man/ + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 + FILES_MATCHING PATTERN *.1 + ) +endif() diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index ad37928b4d..0000000000 --- a/src/Makefile.am +++ /dev/null @@ -1,1135 +0,0 @@ -# Copyright (c) 2013-2016 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Pattern rule to print variables, e.g. make print-top_srcdir -print-%: FORCE - @echo '$*'='$($*)' - -DIST_SUBDIRS = secp256k1 - -AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) $(CORE_LDFLAGS) -AM_CXXFLAGS = $(CORE_CXXFLAGS) $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS) -AM_OBJCXXFLAGS = $(AM_CXXFLAGS) -AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS) $(CORE_CPPFLAGS) -AM_LIBTOOLFLAGS = --preserve-dup-deps -PTHREAD_FLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -EXTRA_LIBRARIES = - -lib_LTLIBRARIES = -noinst_LTLIBRARIES = - -bin_PROGRAMS = -noinst_PROGRAMS = -check_PROGRAMS = -TESTS = -BENCHMARKS = - -BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/$(MINISKETCH_INCLUDE_DIR_INT) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) - -LIBBITCOIN_NODE=libbitcoin_node.a -LIBBITCOIN_COMMON=libbitcoin_common.a -LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a -LIBBITCOIN_CLI=libbitcoin_cli.a -LIBBITCOIN_UTIL=libbitcoin_util.a -LIBBITCOIN_CRYPTO_BASE=crypto/libbitcoin_crypto_base.la -LIBBITCOINQT=qt/libbitcoinqt.a -LIBSECP256K1=secp256k1/libsecp256k1.la - -if ENABLE_ZMQ -LIBBITCOIN_ZMQ=libbitcoin_zmq.a -endif -if BUILD_BITCOIN_KERNEL_LIB -LIBBITCOINKERNEL=libbitcoinkernel.la -endif -if ENABLE_WALLET -LIBBITCOIN_WALLET=libbitcoin_wallet.a -LIBBITCOIN_WALLET_TOOL=libbitcoin_wallet_tool.a -endif - -LIBBITCOIN_CRYPTO = $(LIBBITCOIN_CRYPTO_BASE) -if ENABLE_SSE41 -LIBBITCOIN_CRYPTO_SSE41 = crypto/libbitcoin_crypto_sse41.la -LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SSE41) -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) -endif -noinst_LTLIBRARIES += $(LIBBITCOIN_CRYPTO) - -$(LIBSECP256K1): $(wildcard secp256k1/src/*.h) $(wildcard secp256k1/src/*.c) $(wildcard secp256k1/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) - -# Make is not made aware of per-object dependencies to avoid limiting building parallelization -# But to build the less dependent modules first, we manually select their order here: -EXTRA_LIBRARIES += \ - $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_NODE) \ - $(LIBBITCOIN_CLI) \ - $(LIBBITCOIN_IPC) \ - $(LIBBITCOIN_WALLET) \ - $(LIBBITCOIN_WALLET_TOOL) \ - $(LIBBITCOIN_ZMQ) - -if BUILD_BITCOIND - bin_PROGRAMS += bitcoind -endif - -if BUILD_BITCOIN_NODE - bin_PROGRAMS += bitcoin-node -endif - -if BUILD_BITCOIN_CLI - bin_PROGRAMS += bitcoin-cli -endif - -if BUILD_BITCOIN_TX - bin_PROGRAMS += bitcoin-tx -endif - -if ENABLE_WALLET -if BUILD_BITCOIN_WALLET - bin_PROGRAMS += bitcoin-wallet -endif -endif - -if BUILD_BITCOIN_UTIL - bin_PROGRAMS += bitcoin-util -endif - -if BUILD_BITCOIN_CHAINSTATE - bin_PROGRAMS += bitcoin-chainstate -endif - -.PHONY: FORCE check-symbols check-security -# bitcoin core # -BITCOIN_CORE_H = \ - addresstype.h \ - addrdb.h \ - addrman.h \ - addrman_impl.h \ - attributes.h \ - banman.h \ - base58.h \ - bech32.h \ - bip324.h \ - blockencodings.h \ - blockfilter.h \ - chain.h \ - chainparams.h \ - chainparamsbase.h \ - chainparamsseeds.h \ - checkqueue.h \ - clientversion.h \ - coins.h \ - common/args.h \ - common/bloom.h \ - common/init.h \ - common/run_command.h \ - common/url.h \ - compat/assumptions.h \ - compat/byteswap.h \ - compat/compat.h \ - compat/cpuid.h \ - compat/endian.h \ - common/settings.h \ - common/system.h \ - compressor.h \ - consensus/consensus.h \ - consensus/tx_check.h \ - consensus/tx_verify.h \ - core_io.h \ - core_memusage.h \ - cuckoocache.h \ - dbwrapper.h \ - deploymentinfo.h \ - deploymentstatus.h \ - external_signer.h \ - flatfile.h \ - headerssync.h \ - httprpc.h \ - httpserver.h \ - i2p.h \ - index/base.h \ - index/blockfilterindex.h \ - index/coinstatsindex.h \ - index/disktxpos.h \ - index/txindex.h \ - indirectmap.h \ - init.h \ - init/common.h \ - interfaces/chain.h \ - interfaces/echo.h \ - interfaces/handler.h \ - interfaces/init.h \ - interfaces/ipc.h \ - interfaces/node.h \ - interfaces/wallet.h \ - kernel/blockmanager_opts.h \ - kernel/chain.h \ - kernel/chainparams.h \ - kernel/chainstatemanager_opts.h \ - kernel/checks.h \ - kernel/coinstats.h \ - kernel/context.h \ - kernel/cs_main.h \ - kernel/disconnected_transactions.h \ - kernel/mempool_entry.h \ - kernel/mempool_limits.h \ - kernel/mempool_options.h \ - kernel/mempool_persist.h \ - kernel/mempool_removal_reason.h \ - kernel/messagestartchars.h \ - kernel/notifications_interface.h \ - kernel/validation_cache_sizes.h \ - key.h \ - key_io.h \ - logging.h \ - logging/timer.h \ - mapport.h \ - memusage.h \ - merkleblock.h \ - net.h \ - net_permissions.h \ - net_processing.h \ - net_types.h \ - netaddress.h \ - netbase.h \ - netgroup.h \ - netmessagemaker.h \ - node/abort.h \ - node/blockmanager_args.h \ - node/blockstorage.h \ - node/caches.h \ - node/chainstate.h \ - node/chainstatemanager_args.h \ - node/coin.h \ - node/coins_view_args.h \ - node/connection_types.h \ - node/context.h \ - node/database_args.h \ - node/eviction.h \ - node/interface_ui.h \ - node/kernel_notifications.h \ - node/mempool_args.h \ - node/mempool_persist_args.h \ - node/miner.h \ - node/mini_miner.h \ - node/minisketchwrapper.h \ - node/peerman_args.h \ - node/protocol_version.h \ - node/psbt.h \ - node/timeoffsets.h \ - node/transaction.h \ - node/txreconciliation.h \ - node/utxo_snapshot.h \ - node/validation_cache_args.h \ - noui.h \ - outputtype.h \ - policy/v3_policy.h \ - policy/feerate.h \ - policy/fees.h \ - policy/fees_args.h \ - policy/packages.h \ - policy/policy.h \ - policy/rbf.h \ - policy/settings.h \ - pow.h \ - protocol.h \ - psbt.h \ - random.h \ - randomenv.h \ - rest.h \ - reverse_iterator.h \ - rpc/blockchain.h \ - rpc/client.h \ - rpc/mempool.h \ - rpc/mining.h \ - rpc/protocol.h \ - rpc/rawtransaction_util.h \ - rpc/register.h \ - rpc/request.h \ - rpc/server.h \ - rpc/server_util.h \ - rpc/util.h \ - scheduler.h \ - script/descriptor.h \ - script/keyorigin.h \ - script/miniscript.h \ - script/sigcache.h \ - script/sign.h \ - script/signingprovider.h \ - script/solver.h \ - signet.h \ - streams.h \ - support/allocators/pool.h \ - support/allocators/secure.h \ - support/allocators/zeroafterfree.h \ - support/cleanse.h \ - support/events.h \ - support/lockedpool.h \ - sync.h \ - threadsafety.h \ - torcontrol.h \ - txdb.h \ - txmempool.h \ - txorphanage.h \ - txrequest.h \ - undo.h \ - util/any.h \ - util/asmap.h \ - util/batchpriority.h \ - util/bip32.h \ - util/bitdeque.h \ - util/bytevectorhash.h \ - util/chaintype.h \ - util/check.h \ - util/epochguard.h \ - util/error.h \ - util/exception.h \ - util/fastrange.h \ - util/feefrac.h \ - util/fees.h \ - util/fs.h \ - util/fs_helpers.h \ - util/golombrice.h \ - util/hash_type.h \ - util/hasher.h \ - util/insert.h \ - util/macros.h \ - util/message.h \ - util/moneystr.h \ - util/overflow.h \ - util/overloaded.h \ - util/rbf.h \ - util/readwritefile.h \ - util/result.h \ - util/serfloat.h \ - util/signalinterrupt.h \ - util/sock.h \ - util/spanparsing.h \ - util/string.h \ - util/subprocess.h \ - util/syserror.h \ - util/task_runner.h \ - util/thread.h \ - util/threadinterrupt.h \ - util/threadnames.h \ - util/time.h \ - util/tokenpipe.h \ - util/trace.h \ - util/transaction_identifier.h \ - util/translation.h \ - util/types.h \ - util/ui_change_type.h \ - util/vector.h \ - validation.h \ - validationinterface.h \ - versionbits.h \ - wallet/bdb.h \ - wallet/coincontrol.h \ - wallet/coinselection.h \ - wallet/context.h \ - wallet/crypter.h \ - wallet/db.h \ - wallet/dump.h \ - wallet/external_signer_scriptpubkeyman.h \ - wallet/feebumper.h \ - wallet/fees.h \ - wallet/load.h \ - wallet/migrate.h \ - wallet/receive.h \ - wallet/rpc/util.h \ - wallet/rpc/wallet.h \ - wallet/salvage.h \ - wallet/scriptpubkeyman.h \ - wallet/spend.h \ - wallet/sqlite.h \ - wallet/transaction.h \ - wallet/types.h \ - wallet/wallet.h \ - wallet/walletdb.h \ - wallet/wallettool.h \ - wallet/walletutil.h \ - walletinitinterface.h \ - warnings.h \ - zmq/zmqabstractnotifier.h \ - zmq/zmqnotificationinterface.h \ - zmq/zmqpublishnotifier.h \ - zmq/zmqrpc.h \ - zmq/zmqutil.h - - -obj/build.h: FORCE - @$(MKDIR_P) $(builddir)/obj - $(AM_V_GEN) $(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \ - "$(abs_top_srcdir)" -libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h - -# node # -libbitcoin_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(LEVELDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -libbitcoin_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_node_a_SOURCES = \ - addrdb.cpp \ - addrman.cpp \ - banman.cpp \ - bip324.cpp \ - blockencodings.cpp \ - blockfilter.cpp \ - chain.cpp \ - consensus/tx_verify.cpp \ - dbwrapper.cpp \ - deploymentstatus.cpp \ - flatfile.cpp \ - headerssync.cpp \ - httprpc.cpp \ - httpserver.cpp \ - i2p.cpp \ - index/base.cpp \ - index/blockfilterindex.cpp \ - index/coinstatsindex.cpp \ - index/txindex.cpp \ - init.cpp \ - kernel/chain.cpp \ - kernel/checks.cpp \ - kernel/coinstats.cpp \ - kernel/context.cpp \ - kernel/cs_main.cpp \ - kernel/disconnected_transactions.cpp \ - kernel/mempool_persist.cpp \ - kernel/mempool_removal_reason.cpp \ - mapport.cpp \ - net.cpp \ - net_processing.cpp \ - netgroup.cpp \ - node/abort.cpp \ - node/blockmanager_args.cpp \ - node/blockstorage.cpp \ - node/caches.cpp \ - node/chainstate.cpp \ - node/chainstatemanager_args.cpp \ - node/coin.cpp \ - node/coins_view_args.cpp \ - node/connection_types.cpp \ - node/context.cpp \ - node/database_args.cpp \ - node/eviction.cpp \ - node/interface_ui.cpp \ - node/interfaces.cpp \ - node/kernel_notifications.cpp \ - node/mempool_args.cpp \ - node/mempool_persist_args.cpp \ - node/miner.cpp \ - node/mini_miner.cpp \ - node/minisketchwrapper.cpp \ - node/peerman_args.cpp \ - node/psbt.cpp \ - node/timeoffsets.cpp \ - node/transaction.cpp \ - node/txreconciliation.cpp \ - node/utxo_snapshot.cpp \ - node/validation_cache_args.cpp \ - noui.cpp \ - policy/v3_policy.cpp \ - policy/fees.cpp \ - policy/fees_args.cpp \ - policy/packages.cpp \ - policy/rbf.cpp \ - policy/settings.cpp \ - pow.cpp \ - rest.cpp \ - rpc/blockchain.cpp \ - rpc/fees.cpp \ - rpc/mempool.cpp \ - rpc/mining.cpp \ - rpc/net.cpp \ - rpc/node.cpp \ - rpc/output_script.cpp \ - rpc/rawtransaction.cpp \ - rpc/server.cpp \ - rpc/server_util.cpp \ - rpc/signmessage.cpp \ - rpc/txoutproof.cpp \ - script/sigcache.cpp \ - signet.cpp \ - torcontrol.cpp \ - txdb.cpp \ - txmempool.cpp \ - txorphanage.cpp \ - txrequest.cpp \ - validation.cpp \ - validationinterface.cpp \ - versionbits.cpp \ - $(BITCOIN_CORE_H) - -if ENABLE_WALLET -libbitcoin_node_a_SOURCES += wallet/init.cpp -libbitcoin_node_a_CPPFLAGS += $(BDB_CPPFLAGS) -endif -if !ENABLE_WALLET -libbitcoin_node_a_SOURCES += dummywallet.cpp -endif -# - -# zmq # -if ENABLE_ZMQ -libbitcoin_zmq_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) -libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_zmq_a_SOURCES = \ - zmq/zmqabstractnotifier.cpp \ - zmq/zmqnotificationinterface.cpp \ - zmq/zmqpublishnotifier.cpp \ - zmq/zmqrpc.cpp \ - zmq/zmqutil.cpp -endif -# - -# wallet # -libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(BDB_CPPFLAGS) $(SQLITE_CFLAGS) -libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_wallet_a_SOURCES = \ - wallet/coincontrol.cpp \ - wallet/context.cpp \ - wallet/crypter.cpp \ - wallet/db.cpp \ - wallet/dump.cpp \ - wallet/external_signer_scriptpubkeyman.cpp \ - wallet/feebumper.cpp \ - wallet/fees.cpp \ - wallet/interfaces.cpp \ - wallet/load.cpp \ - wallet/migrate.cpp \ - wallet/receive.cpp \ - wallet/rpc/addresses.cpp \ - wallet/rpc/backup.cpp \ - wallet/rpc/coins.cpp \ - wallet/rpc/encrypt.cpp \ - wallet/rpc/spend.cpp \ - wallet/rpc/signmessage.cpp \ - wallet/rpc/transactions.cpp \ - wallet/rpc/util.cpp \ - wallet/rpc/wallet.cpp \ - wallet/scriptpubkeyman.cpp \ - wallet/spend.cpp \ - wallet/transaction.cpp \ - wallet/wallet.cpp \ - wallet/walletdb.cpp \ - wallet/walletutil.cpp \ - wallet/coinselection.cpp \ - $(BITCOIN_CORE_H) - -if USE_SQLITE -libbitcoin_wallet_a_SOURCES += wallet/sqlite.cpp -endif -if USE_BDB -libbitcoin_wallet_a_SOURCES += wallet/bdb.cpp wallet/salvage.cpp -endif -# - -# wallet tool # -libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) -libbitcoin_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_wallet_tool_a_SOURCES = \ - wallet/wallettool.cpp \ - $(BITCOIN_CORE_H) -# - -# crypto # - -# crypto_base contains the unspecialized (unoptimized) versions of our -# crypto functions. Functions that require custom compiler flags and/or -# runtime opt-in are omitted. -crypto_libbitcoin_crypto_base_la_CPPFLAGS = $(AM_CPPFLAGS) - -# Specify -static in both CXXFLAGS and LDFLAGS so libtool will only build a -# static version of this library. We don't need a dynamic version, and a dynamic -# version can't be used on windows anyway because the library doesn't currently -# export DLL symbols. -crypto_libbitcoin_crypto_base_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -static -crypto_libbitcoin_crypto_base_la_LDFLAGS = $(AM_LDFLAGS) -static - -crypto_libbitcoin_crypto_base_la_SOURCES = \ - crypto/aes.cpp \ - crypto/aes.h \ - crypto/chacha20.h \ - crypto/chacha20.cpp \ - crypto/chacha20poly1305.h \ - crypto/chacha20poly1305.cpp \ - crypto/common.h \ - crypto/hkdf_sha256_32.cpp \ - crypto/hkdf_sha256_32.h \ - crypto/hmac_sha256.cpp \ - crypto/hmac_sha256.h \ - crypto/hmac_sha512.cpp \ - crypto/hmac_sha512.h \ - crypto/poly1305.h \ - crypto/poly1305.cpp \ - crypto/muhash.h \ - crypto/muhash.cpp \ - crypto/ripemd160.cpp \ - crypto/ripemd160.h \ - crypto/sha1.cpp \ - crypto/sha1.h \ - crypto/sha256.cpp \ - crypto/sha256.h \ - crypto/sha256_sse4.cpp \ - crypto/sha3.cpp \ - crypto/sha3.h \ - crypto/sha512.cpp \ - crypto/sha512.h \ - crypto/siphash.cpp \ - crypto/siphash.h - -# See explanation for -static in crypto_libbitcoin_crypto_base_la's LDFLAGS and -# CXXFLAGS above -crypto_libbitcoin_crypto_sse41_la_LDFLAGS = $(AM_LDFLAGS) -static -crypto_libbitcoin_crypto_sse41_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -static -crypto_libbitcoin_crypto_sse41_la_CPPFLAGS = $(AM_CPPFLAGS) -crypto_libbitcoin_crypto_sse41_la_CXXFLAGS += $(SSE41_CXXFLAGS) -crypto_libbitcoin_crypto_sse41_la_CPPFLAGS += -DENABLE_SSE41 -crypto_libbitcoin_crypto_sse41_la_SOURCES = crypto/sha256_sse41.cpp - -# See explanation for -static in crypto_libbitcoin_crypto_base_la's LDFLAGS and -# CXXFLAGS above -crypto_libbitcoin_crypto_avx2_la_LDFLAGS = $(AM_LDFLAGS) -static -crypto_libbitcoin_crypto_avx2_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -static -crypto_libbitcoin_crypto_avx2_la_CPPFLAGS = $(AM_CPPFLAGS) -crypto_libbitcoin_crypto_avx2_la_CXXFLAGS += $(AVX2_CXXFLAGS) -crypto_libbitcoin_crypto_avx2_la_CPPFLAGS += -DENABLE_AVX2 -crypto_libbitcoin_crypto_avx2_la_SOURCES = crypto/sha256_avx2.cpp - -# See explanation for -static in crypto_libbitcoin_crypto_base_la's LDFLAGS and -# CXXFLAGS above -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_SOURCES = crypto/sha256_x86_shani.cpp - -# See explanation for -static in crypto_libbitcoin_crypto_base_la's LDFLAGS and -# CXXFLAGS above -crypto_libbitcoin_crypto_arm_shani_la_LDFLAGS = $(AM_LDFLAGS) -static -crypto_libbitcoin_crypto_arm_shani_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -static -crypto_libbitcoin_crypto_arm_shani_la_CPPFLAGS = $(AM_CPPFLAGS) -crypto_libbitcoin_crypto_arm_shani_la_CXXFLAGS += $(ARM_SHANI_CXXFLAGS) -crypto_libbitcoin_crypto_arm_shani_la_CPPFLAGS += -DENABLE_ARM_SHANI -crypto_libbitcoin_crypto_arm_shani_la_SOURCES = crypto/sha256_arm_shani.cpp -# - -# consensus # -libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_consensus_a_SOURCES = \ - arith_uint256.cpp \ - arith_uint256.h \ - consensus/amount.h \ - consensus/merkle.cpp \ - consensus/merkle.h \ - consensus/params.h \ - consensus/tx_check.cpp \ - consensus/validation.h \ - hash.cpp \ - hash.h \ - prevector.h \ - primitives/block.cpp \ - primitives/block.h \ - primitives/transaction.cpp \ - primitives/transaction.h \ - pubkey.cpp \ - pubkey.h \ - script/interpreter.cpp \ - script/interpreter.h \ - script/script.cpp \ - script/script.h \ - script/script_error.cpp \ - script/script_error.h \ - serialize.h \ - span.h \ - tinyformat.h \ - uint256.cpp \ - uint256.h \ - util/strencodings.cpp \ - util/strencodings.h -# - -# common # -libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) -libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_common_a_SOURCES = \ - addresstype.cpp \ - base58.cpp \ - bech32.cpp \ - chainparams.cpp \ - coins.cpp \ - common/args.cpp \ - common/bloom.cpp \ - common/config.cpp \ - common/init.cpp \ - common/interfaces.cpp \ - common/run_command.cpp \ - common/settings.cpp \ - common/system.cpp \ - common/url.cpp \ - compressor.cpp \ - core_read.cpp \ - core_write.cpp \ - deploymentinfo.cpp \ - external_signer.cpp \ - init/common.cpp \ - kernel/chainparams.cpp \ - key.cpp \ - key_io.cpp \ - merkleblock.cpp \ - net_types.cpp \ - netaddress.cpp \ - netbase.cpp \ - net_permissions.cpp \ - outputtype.cpp \ - policy/v3_policy.cpp \ - policy/feerate.cpp \ - policy/policy.cpp \ - protocol.cpp \ - psbt.cpp \ - rpc/external_signer.cpp \ - rpc/rawtransaction_util.cpp \ - rpc/request.cpp \ - rpc/util.cpp \ - scheduler.cpp \ - script/descriptor.cpp \ - script/miniscript.cpp \ - script/sign.cpp \ - script/signingprovider.cpp \ - script/solver.cpp \ - warnings.cpp \ - $(BITCOIN_CORE_H) -# - -# util # -libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_util_a_SOURCES = \ - support/lockedpool.cpp \ - chainparamsbase.cpp \ - clientversion.cpp \ - logging.cpp \ - random.cpp \ - randomenv.cpp \ - streams.cpp \ - support/cleanse.cpp \ - sync.cpp \ - util/asmap.cpp \ - util/batchpriority.cpp \ - util/bip32.cpp \ - util/bytevectorhash.cpp \ - util/chaintype.cpp \ - util/check.cpp \ - util/error.cpp \ - util/exception.cpp \ - util/feefrac.cpp \ - util/fees.cpp \ - util/fs.cpp \ - util/fs_helpers.cpp \ - util/hasher.cpp \ - util/sock.cpp \ - util/syserror.cpp \ - util/message.cpp \ - util/moneystr.cpp \ - util/rbf.cpp \ - util/readwritefile.cpp \ - util/signalinterrupt.cpp \ - util/thread.cpp \ - util/threadinterrupt.cpp \ - util/threadnames.cpp \ - util/serfloat.cpp \ - util/spanparsing.cpp \ - util/strencodings.cpp \ - util/string.cpp \ - util/time.cpp \ - util/tokenpipe.cpp \ - $(BITCOIN_CORE_H) -# - -# cli # -libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_cli_a_SOURCES = \ - compat/stdin.h \ - compat/stdin.cpp \ - rpc/client.cpp \ - $(BITCOIN_CORE_H) - -nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h -# - -# bitcoind & bitcoin-node binaries # -bitcoin_daemon_sources = bitcoind.cpp -bitcoin_bin_cppflags = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -bitcoin_bin_cxxflags = $(AM_CXXFLAGS) $(PIE_FLAGS) -bitcoin_bin_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) - -if TARGET_WINDOWS -bitcoin_daemon_sources += bitcoind-res.rc -endif - -bitcoin_bin_ldadd = \ - $(LIBBITCOIN_WALLET) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBUNIVALUE) \ - $(LIBBITCOIN_ZMQ) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBLEVELDB) \ - $(LIBMEMENV) \ - $(LIBSECP256K1) - -bitcoin_bin_ldadd += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS) - -bitcoind_SOURCES = $(bitcoin_daemon_sources) init/bitcoind.cpp -bitcoind_CPPFLAGS = $(bitcoin_bin_cppflags) -bitcoind_CXXFLAGS = $(bitcoin_bin_cxxflags) -bitcoind_LDFLAGS = $(bitcoin_bin_ldflags) -bitcoind_LDADD = $(LIBBITCOIN_NODE) $(bitcoin_bin_ldadd) - -bitcoin_node_SOURCES = $(bitcoin_daemon_sources) init/bitcoin-node.cpp -bitcoin_node_CPPFLAGS = $(bitcoin_bin_cppflags) -bitcoin_node_CXXFLAGS = $(bitcoin_bin_cxxflags) -bitcoin_node_LDFLAGS = $(bitcoin_bin_ldflags) -bitcoin_node_LDADD = $(LIBBITCOIN_NODE) $(bitcoin_bin_ldadd) $(LIBBITCOIN_IPC) $(LIBMULTIPROCESS_LIBS) - -# bitcoin-cli binary # -bitcoin_cli_SOURCES = bitcoin-cli.cpp -bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) -bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) - -if TARGET_WINDOWS -bitcoin_cli_SOURCES += bitcoin-cli-res.rc -endif - -bitcoin_cli_LDADD = \ - $(LIBBITCOIN_CLI) \ - $(LIBUNIVALUE) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_CRYPTO) - -bitcoin_cli_LDADD += $(EVENT_LIBS) -# - -# bitcoin-tx binary # -bitcoin_tx_SOURCES = bitcoin-tx.cpp -bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -bitcoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) - -if TARGET_WINDOWS -bitcoin_tx_SOURCES += bitcoin-tx-res.rc -endif - -bitcoin_tx_LDADD = \ - $(LIBUNIVALUE) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBSECP256K1) -# - -# bitcoin-wallet binary # -bitcoin_wallet_SOURCES = bitcoin-wallet.cpp -bitcoin_wallet_SOURCES += init/bitcoin-wallet.cpp -bitcoin_wallet_CPPFLAGS = $(bitcoin_bin_cppflags) -bitcoin_wallet_CXXFLAGS = $(bitcoin_bin_cxxflags) -bitcoin_wallet_LDFLAGS = $(bitcoin_bin_ldflags) -bitcoin_wallet_LDADD = \ - $(LIBBITCOIN_WALLET_TOOL) \ - $(LIBBITCOIN_WALLET) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBUNIVALUE) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBSECP256K1) \ - $(BDB_LIBS) \ - $(SQLITE_LIBS) - -if TARGET_WINDOWS -bitcoin_wallet_SOURCES += bitcoin-wallet-res.rc -endif -# - -# bitcoin-util binary # -bitcoin_util_SOURCES = bitcoin-util.cpp -bitcoin_util_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -bitcoin_util_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -bitcoin_util_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) - -if TARGET_WINDOWS -bitcoin_util_SOURCES += bitcoin-util-res.rc -endif - -bitcoin_util_LDADD = \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBUNIVALUE) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBSECP256K1) -# - -# bitcoin-chainstate binary # -bitcoin_chainstate_SOURCES = bitcoin-chainstate.cpp -bitcoin_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) -bitcoin_chainstate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) - -bitcoin_chainstate_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(PTHREAD_FLAGS) $(LIBTOOL_APP_LDFLAGS) -static -bitcoin_chainstate_LDADD = $(LIBBITCOINKERNEL) - -# libtool is unable to calculate this indirect dependency, presumably because it's a subproject. -# libsecp256k1 only needs to be linked in when libbitcoinkernel is static. -bitcoin_chainstate_LDADD += $(LIBSECP256K1) -# - -# bitcoinkernel library # -if BUILD_BITCOIN_KERNEL_LIB -lib_LTLIBRARIES += $(LIBBITCOINKERNEL) - -libbitcoinkernel_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) $(PTHREAD_FLAGS) -libbitcoinkernel_la_LIBADD = $(LIBBITCOIN_CRYPTO) $(LIBLEVELDB) $(LIBMEMENV) $(LIBSECP256K1) -libbitcoinkernel_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) - -# libbitcoinkernel requires default symbol visibility, explicitly specify that -# here so that things still work even when user configures with -# --enable-reduce-exports -# -# Note this is a quick hack that will be removed as we incrementally define what -# to export from the library. -libbitcoinkernel_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -fvisibility=default - -# TODO: libbitcoinkernel is a work in progress consensus engine library, as more -# and more modules are decoupled from the consensus engine, this list will -# shrink to only those which are absolutely necessary. -libbitcoinkernel_la_SOURCES = \ - kernel/bitcoinkernel.cpp \ - arith_uint256.cpp \ - chain.cpp \ - clientversion.cpp \ - coins.cpp \ - compressor.cpp \ - consensus/merkle.cpp \ - consensus/tx_check.cpp \ - consensus/tx_verify.cpp \ - core_read.cpp \ - dbwrapper.cpp \ - deploymentinfo.cpp \ - deploymentstatus.cpp \ - flatfile.cpp \ - hash.cpp \ - kernel/chain.cpp \ - kernel/checks.cpp \ - kernel/chainparams.cpp \ - kernel/coinstats.cpp \ - kernel/context.cpp \ - kernel/cs_main.cpp \ - kernel/disconnected_transactions.cpp \ - kernel/mempool_persist.cpp \ - kernel/mempool_removal_reason.cpp \ - logging.cpp \ - node/blockstorage.cpp \ - node/chainstate.cpp \ - node/utxo_snapshot.cpp \ - policy/v3_policy.cpp \ - policy/feerate.cpp \ - policy/packages.cpp \ - policy/policy.cpp \ - policy/rbf.cpp \ - policy/settings.cpp \ - pow.cpp \ - primitives/block.cpp \ - primitives/transaction.cpp \ - pubkey.cpp \ - random.cpp \ - randomenv.cpp \ - script/interpreter.cpp \ - script/script.cpp \ - script/script_error.cpp \ - script/sigcache.cpp \ - script/solver.cpp \ - signet.cpp \ - streams.cpp \ - support/cleanse.cpp \ - support/lockedpool.cpp \ - sync.cpp \ - txdb.cpp \ - txmempool.cpp \ - uint256.cpp \ - util/chaintype.cpp \ - util/check.cpp \ - util/feefrac.cpp \ - util/fs.cpp \ - util/fs_helpers.cpp \ - util/hasher.cpp \ - util/moneystr.cpp \ - util/rbf.cpp \ - util/serfloat.cpp \ - util/signalinterrupt.cpp \ - util/strencodings.cpp \ - util/string.cpp \ - util/syserror.cpp \ - util/threadnames.cpp \ - util/time.cpp \ - util/tokenpipe.cpp \ - validation.cpp \ - validationinterface.cpp \ - versionbits.cpp \ - warnings.cpp - -# Required for obj/build.h to be generated first. -# More details: https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html -libbitcoinkernel_la-clientversion.l$(OBJEXT): obj/build.h -endif # BUILD_BITCOIN_KERNEL_LIB -# - -CTAES_DIST = crypto/ctaes/bench.c -CTAES_DIST += crypto/ctaes/ctaes.c -CTAES_DIST += crypto/ctaes/ctaes.h -CTAES_DIST += crypto/ctaes/README.md -CTAES_DIST += crypto/ctaes/test.c - -CLEANFILES = $(EXTRA_LIBRARIES) - -CLEANFILES += *.gcda *.gcno -CLEANFILES += compat/*.gcda compat/*.gcno -CLEANFILES += consensus/*.gcda consensus/*.gcno -CLEANFILES += crc32c/src/*.gcda crc32c/src/*.gcno -CLEANFILES += crypto/*.gcda crypto/*.gcno -CLEANFILES += index/*.gcda index/*.gcno -CLEANFILES += interfaces/*.gcda interfaces/*.gcno -CLEANFILES += node/*.gcda node/*.gcno -CLEANFILES += policy/*.gcda policy/*.gcno -CLEANFILES += primitives/*.gcda primitives/*.gcno -CLEANFILES += rpc/*.gcda rpc/*.gcno -CLEANFILES += script/*.gcda script/*.gcno -CLEANFILES += support/*.gcda support/*.gcno -CLEANFILES += univalue/*.gcda univalue/*.gcno -CLEANFILES += util/*.gcda util/*.gcno -CLEANFILES += wallet/*.gcda wallet/*.gcno -CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno -CLEANFILES += zmq/*.gcda zmq/*.gcno -CLEANFILES += obj/build.h - -EXTRA_DIST = $(CTAES_DIST) - - -config/bitcoin-config.h: config/stamp-h1 - @$(MAKE) -C $(top_builddir) $(subdir)/$(@) -config/stamp-h1: $(top_srcdir)/$(subdir)/config/bitcoin-config.h.in $(top_builddir)/config.status - $(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@) -$(top_srcdir)/$(subdir)/config/bitcoin-config.h.in: $(am__configure_deps) - $(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/bitcoin-config.h.in - -clean-local: - -$(MAKE) -C secp256k1 clean - -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno - -rm -f config.h - -rm -rf test/__pycache__ - -.rc.o: - @test -f $(WINDRES) || (echo "windres $(WINDRES) not found, but is required to compile windows resource files"; exit 1) - ## FIXME: How to get the appropriate modulename_CPPFLAGS in here? - $(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@ - -check-symbols: $(bin_PROGRAMS) - @echo "Running symbol and dynamic library checks..." - $(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS) - -check-security: $(bin_PROGRAMS) -if HARDEN - @echo "Checking binary security..." - $(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS) -endif - -libbitcoin_ipc_mpgen_input = \ - ipc/capnp/echo.capnp \ - ipc/capnp/init.capnp -EXTRA_DIST += $(libbitcoin_ipc_mpgen_input) -%.capnp: - -# Explicitly list dependencies on generated headers as described in -# https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html#Recording-Dependencies-manually -ipc/capnp/libbitcoin_ipc_a-protocol.$(OBJEXT): $(libbitcoin_ipc_mpgen_input:=.h) - -if BUILD_MULTIPROCESS -LIBBITCOIN_IPC=libbitcoin_ipc.a -libbitcoin_ipc_a_SOURCES = \ - ipc/capnp/common-types.h \ - ipc/capnp/context.h \ - ipc/capnp/init-types.h \ - ipc/capnp/protocol.cpp \ - ipc/capnp/protocol.h \ - ipc/context.h \ - ipc/exception.h \ - ipc/interfaces.cpp \ - ipc/process.cpp \ - ipc/process.h \ - ipc/protocol.h -libbitcoin_ipc_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -libbitcoin_ipc_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(LIBMULTIPROCESS_CFLAGS) - -include $(MPGEN_PREFIX)/include/mpgen.mk -libbitcoin_ipc_mpgen_output = \ - $(libbitcoin_ipc_mpgen_input:=.c++) \ - $(libbitcoin_ipc_mpgen_input:=.h) \ - $(libbitcoin_ipc_mpgen_input:=.proxy-client.c++) \ - $(libbitcoin_ipc_mpgen_input:=.proxy-server.c++) \ - $(libbitcoin_ipc_mpgen_input:=.proxy-types.c++) \ - $(libbitcoin_ipc_mpgen_input:=.proxy-types.h) \ - $(libbitcoin_ipc_mpgen_input:=.proxy.h) -nodist_libbitcoin_ipc_a_SOURCES = $(libbitcoin_ipc_mpgen_output) -CLEANFILES += $(libbitcoin_ipc_mpgen_output) -endif - -%.raw.h: %.raw - @$(MKDIR_P) $(@D) - $(AM_V_GEN) { \ - echo "static unsigned const char $(*F)_raw[] = {" && \ - $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ - echo "};"; \ - } > "$@.new" && mv -f "$@.new" "$@" - -include Makefile.minisketch.include - -include Makefile.crc32c.include -include Makefile.leveldb.include - -include Makefile.test_util.include -include Makefile.test_fuzz.include - -include Makefile.test.include - -if ENABLE_BENCH -include Makefile.bench.include -endif - -if ENABLE_QT -include Makefile.qt.include -endif - -if ENABLE_QT_TESTS -include Makefile.qttest.include -endif - -include Makefile.univalue.include diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include deleted file mode 100644 index 7ba0111fa6..0000000000 --- a/src/Makefile.bench.include +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (c) 2015-2016 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -bin_PROGRAMS += bench/bench_bitcoin -BENCH_SRCDIR = bench -BENCH_BINARY = bench/bench_bitcoin$(EXEEXT) - -RAW_BENCH_FILES = \ - bench/data/block413567.raw -GENERATED_BENCH_FILES = $(RAW_BENCH_FILES:.raw=.raw.h) - -bench_bench_bitcoin_SOURCES = \ - $(RAW_BENCH_FILES) \ - bench/addrman.cpp \ - bench/base58.cpp \ - bench/bech32.cpp \ - bench/bench.cpp \ - bench/bench.h \ - bench/bench_bitcoin.cpp \ - bench/bip324_ecdh.cpp \ - bench/block_assemble.cpp \ - bench/ccoins_caching.cpp \ - bench/chacha20.cpp \ - bench/checkblock.cpp \ - bench/checkqueue.cpp \ - bench/crypto_hash.cpp \ - bench/data.cpp \ - bench/data.h \ - bench/descriptors.cpp \ - bench/disconnected_transactions.cpp \ - bench/duplicate_inputs.cpp \ - bench/ellswift.cpp \ - bench/examples.cpp \ - bench/gcs_filter.cpp \ - bench/hashpadding.cpp \ - bench/index_blockfilter.cpp \ - bench/load_external.cpp \ - bench/lockedpool.cpp \ - bench/logging.cpp \ - bench/mempool_eviction.cpp \ - bench/mempool_stress.cpp \ - bench/merkle_root.cpp \ - bench/nanobench.cpp \ - bench/nanobench.h \ - bench/parse_hex.cpp \ - bench/peer_eviction.cpp \ - bench/poly1305.cpp \ - bench/pool.cpp \ - bench/prevector.cpp \ - bench/readblock.cpp \ - bench/rollingbloom.cpp \ - bench/rpc_blockchain.cpp \ - bench/rpc_mempool.cpp \ - bench/streams_findbyte.cpp \ - bench/strencodings.cpp \ - bench/util_time.cpp \ - bench/verify_script.cpp \ - bench/xor.cpp - -nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES) - -bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ -bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -bench_bench_bitcoin_LDADD = \ - $(LIBTEST_UTIL) \ - $(LIBBITCOIN_NODE) \ - $(LIBBITCOIN_WALLET) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBLEVELDB) \ - $(LIBMEMENV) \ - $(LIBSECP256K1) \ - $(LIBUNIVALUE) \ - $(EVENT_PTHREADS_LIBS) \ - $(EVENT_LIBS) \ - $(MINIUPNPC_LIBS) \ - $(NATPMP_LIBS) - -if ENABLE_ZMQ -bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) -endif - -if ENABLE_WALLET -bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp -bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp -bench_bench_bitcoin_SOURCES += bench/wallet_create.cpp -bench_bench_bitcoin_SOURCES += bench/wallet_loading.cpp -bench_bench_bitcoin_SOURCES += bench/wallet_create_tx.cpp -bench_bench_bitcoin_SOURCES += bench/wallet_ismine.cpp - -bench_bench_bitcoin_LDADD += $(BDB_LIBS) $(SQLITE_LIBS) -endif - -CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES) - -CLEANFILES += $(CLEAN_BITCOIN_BENCH) - -bench/data.cpp: bench/data/block413567.raw.h - -bitcoin_bench: $(BENCH_BINARY) - -bench: $(BENCH_BINARY) FORCE - $(BENCH_BINARY) - -bitcoin_bench_clean : FORCE - rm -f $(CLEAN_BITCOIN_BENCH) $(bench_bench_bitcoin_OBJECTS) $(BENCH_BINARY) diff --git a/src/Makefile.crc32c.include b/src/Makefile.crc32c.include deleted file mode 100644 index c4dd84991d..0000000000 --- a/src/Makefile.crc32c.include +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2019 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -LIBCRC32C_INT = crc32c/libcrc32c.la - -noinst_LTLIBRARIES += $(LIBCRC32C_INT) - -LIBCRC32C = $(LIBCRC32C_INT) - -CRC32C_CPPFLAGS_INT = -CRC32C_CPPFLAGS_INT += -I$(srcdir)/crc32c/include -CRC32C_CPPFLAGS_INT += -DHAVE_BUILTIN_PREFETCH=@HAVE_BUILTIN_PREFETCH@ -CRC32C_CPPFLAGS_INT += -DHAVE_MM_PREFETCH=@HAVE_MM_PREFETCH@ -CRC32C_CPPFLAGS_INT += -DHAVE_STRONG_GETAUXVAL=@HAVE_STRONG_GETAUXVAL@ -CRC32C_CPPFLAGS_INT += -DCRC32C_TESTS_BUILT_WITH_GLOG=0 - -if ENABLE_SSE42 -CRC32C_CPPFLAGS_INT += -DHAVE_SSE42=1 -else -CRC32C_CPPFLAGS_INT += -DHAVE_SSE42=0 -endif - -if ENABLE_ARM_CRC -CRC32C_CPPFLAGS_INT += -DHAVE_ARM64_CRC32C=1 -else -CRC32C_CPPFLAGS_INT += -DHAVE_ARM64_CRC32C=0 -endif - -if WORDS_BIGENDIAN -CRC32C_CPPFLAGS_INT += -DBYTE_ORDER_BIG_ENDIAN=1 -else -CRC32C_CPPFLAGS_INT += -DBYTE_ORDER_BIG_ENDIAN=0 -endif - -crc32c_libcrc32c_la_CPPFLAGS = $(AM_CPPFLAGS) $(CRC32C_CPPFLAGS_INT) $(CRC32C_CPPFLAGS) - -# Specify -static in both CXXFLAGS and LDFLAGS so libtool will only build a -# static version of this library. We don't need a dynamic version, and a dynamic -# version can't be used on windows anyway because the library doesn't currently -# export DLL symbols. -crc32c_libcrc32c_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -static -crc32c_libcrc32c_la_LDFLAGS = $(AM_LDFLAGS) -static - -crc32c_libcrc32c_la_SOURCES = -crc32c_libcrc32c_la_SOURCES += crc32c/include/crc32c/crc32c.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_arm64.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_arm64_check.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_internal.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_prefetch.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_read_le.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_round_up.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_sse42_check.h -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_sse42.h - -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c.cc -crc32c_libcrc32c_la_SOURCES += crc32c/src/crc32c_portable.cc - -if ENABLE_SSE42 -LIBCRC32C_SSE42_INT = crc32c/libcrc32c_sse42.la -noinst_LTLIBRARIES += $(LIBCRC32C_SSE42_INT) -LIBCRC32C += $(LIBCRC32C_SSE42_INT) - -crc32c_libcrc32c_sse42_la_CPPFLAGS = $(crc32c_libcrc32c_la_CPPFLAGS) -crc32c_libcrc32c_sse42_la_CXXFLAGS = $(crc32c_libcrc32c_la_CXXFLAGS) $(SSE42_CXXFLAGS) -crc32c_libcrc32c_sse42_la_LDFLAGS = $(crc32c_libcrc32c_la_LDFLAGS) - -crc32c_libcrc32c_sse42_la_SOURCES = crc32c/src/crc32c_sse42.cc -endif - -if ENABLE_ARM_CRC -LIBCRC32C_ARM_CRC_INT = crc32c/libcrc32c_arm_crc.la -noinst_LTLIBRARIES += $(LIBCRC32C_ARM_CRC_INT) -LIBCRC32C += $(LIBCRC32C_ARM_CRC_INT) - -crc32c_libcrc32c_arm_crc_la_CPPFLAGS = $(crc32c_libcrc32c_la_CPPFLAGS) -crc32c_libcrc32c_arm_crc_la_CXXFLAGS = $(crc32c_libcrc32c_la_CXXFLAGS) $(ARM_CRC_CXXFLAGS) -crc32c_libcrc32c_arm_crc_la_LDFLAGS = $(crc32c_libcrc32c_la_LDFLAGS) - -crc32c_libcrc32c_arm_crc_la_SOURCES = crc32c/src/crc32c_arm64.cc -endif diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include deleted file mode 100644 index bf14fe206b..0000000000 --- a/src/Makefile.leveldb.include +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright (c) 2016 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -LIBLEVELDB_INT = leveldb/libleveldb.la -LIBMEMENV_INT = leveldb/libmemenv.la - -noinst_LTLIBRARIES += $(LIBLEVELDB_INT) -noinst_LTLIBRARIES += $(LIBMEMENV_INT) - -LIBLEVELDB = $(LIBLEVELDB_INT) $(LIBCRC32C) -LIBMEMENV = $(LIBMEMENV_INT) - -LEVELDB_CPPFLAGS = -LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include - -LEVELDB_CPPFLAGS_INT = -LEVELDB_CPPFLAGS_INT += -I$(srcdir)/leveldb -LEVELDB_CPPFLAGS_INT += -I$(srcdir)/crc32c/include -LEVELDB_CPPFLAGS_INT += -D__STDC_LIMIT_MACROS -LEVELDB_CPPFLAGS_INT += -DHAVE_SNAPPY=0 -DHAVE_CRC32C=1 -LEVELDB_CPPFLAGS_INT += -DHAVE_FDATASYNC=@HAVE_FDATASYNC@ -LEVELDB_CPPFLAGS_INT += -DHAVE_FULLFSYNC=@HAVE_FULLFSYNC@ -LEVELDB_CPPFLAGS_INT += -DHAVE_O_CLOEXEC=@HAVE_O_CLOEXEC@ -LEVELDB_CPPFLAGS_INT += -DFALLTHROUGH_INTENDED=[[fallthrough]] - -if WORDS_BIGENDIAN -LEVELDB_CPPFLAGS_INT += -DLEVELDB_IS_BIG_ENDIAN=1 -else -LEVELDB_CPPFLAGS_INT += -DLEVELDB_IS_BIG_ENDIAN=0 -endif - -if TARGET_WINDOWS -LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_WINDOWS -D_UNICODE -DUNICODE -D__USE_MINGW_ANSI_STDIO=1 -else -LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_POSIX -endif - -leveldb_libleveldb_la_CPPFLAGS = $(AM_CPPFLAGS) $(LEVELDB_CPPFLAGS_INT) $(LEVELDB_CPPFLAGS) - -# Specify -static in both CXXFLAGS and LDFLAGS so libtool will only build a -# static version of this library. We don't need a dynamic version, and a dynamic -# version can't be used on windows anyway because the library doesn't currently -# export DLL symbols. -leveldb_libleveldb_la_CXXFLAGS = $(filter-out -Wconditional-uninitialized -Werror=conditional-uninitialized -Wsuggest-override -Werror=suggest-override, $(AM_CXXFLAGS)) $(PIE_FLAGS) -static -leveldb_libleveldb_la_LDFLAGS = $(AM_LDFLAGS) -static - -leveldb_libleveldb_la_SOURCES= -leveldb_libleveldb_la_SOURCES += leveldb/port/port_stdcxx.h -leveldb_libleveldb_la_SOURCES += leveldb/port/port.h -leveldb_libleveldb_la_SOURCES += leveldb/port/thread_annotations.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/db.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/options.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/comparator.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/filter_policy.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/slice.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/table_builder.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/env.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/export.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/c.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/iterator.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/cache.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/dumpfile.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/table.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/write_batch.h -leveldb_libleveldb_la_SOURCES += leveldb/include/leveldb/status.h -leveldb_libleveldb_la_SOURCES += leveldb/db/log_format.h -leveldb_libleveldb_la_SOURCES += leveldb/db/memtable.h -leveldb_libleveldb_la_SOURCES += leveldb/db/version_set.h -leveldb_libleveldb_la_SOURCES += leveldb/db/write_batch_internal.h -leveldb_libleveldb_la_SOURCES += leveldb/db/filename.h -leveldb_libleveldb_la_SOURCES += leveldb/db/version_edit.h -leveldb_libleveldb_la_SOURCES += leveldb/db/dbformat.h -leveldb_libleveldb_la_SOURCES += leveldb/db/builder.h -leveldb_libleveldb_la_SOURCES += leveldb/db/log_writer.h -leveldb_libleveldb_la_SOURCES += leveldb/db/db_iter.h -leveldb_libleveldb_la_SOURCES += leveldb/db/skiplist.h -leveldb_libleveldb_la_SOURCES += leveldb/db/db_impl.h -leveldb_libleveldb_la_SOURCES += leveldb/db/table_cache.h -leveldb_libleveldb_la_SOURCES += leveldb/db/snapshot.h -leveldb_libleveldb_la_SOURCES += leveldb/db/log_reader.h -leveldb_libleveldb_la_SOURCES += leveldb/table/filter_block.h -leveldb_libleveldb_la_SOURCES += leveldb/table/block_builder.h -leveldb_libleveldb_la_SOURCES += leveldb/table/block.h -leveldb_libleveldb_la_SOURCES += leveldb/table/two_level_iterator.h -leveldb_libleveldb_la_SOURCES += leveldb/table/merger.h -leveldb_libleveldb_la_SOURCES += leveldb/table/format.h -leveldb_libleveldb_la_SOURCES += leveldb/table/iterator_wrapper.h -leveldb_libleveldb_la_SOURCES += leveldb/util/crc32c.h -leveldb_libleveldb_la_SOURCES += leveldb/util/env_posix_test_helper.h -leveldb_libleveldb_la_SOURCES += leveldb/util/env_windows_test_helper.h -leveldb_libleveldb_la_SOURCES += leveldb/util/arena.h -leveldb_libleveldb_la_SOURCES += leveldb/util/random.h -leveldb_libleveldb_la_SOURCES += leveldb/util/posix_logger.h -leveldb_libleveldb_la_SOURCES += leveldb/util/hash.h -leveldb_libleveldb_la_SOURCES += leveldb/util/histogram.h -leveldb_libleveldb_la_SOURCES += leveldb/util/coding.h -leveldb_libleveldb_la_SOURCES += leveldb/util/testutil.h -leveldb_libleveldb_la_SOURCES += leveldb/util/mutexlock.h -leveldb_libleveldb_la_SOURCES += leveldb/util/logging.h -leveldb_libleveldb_la_SOURCES += leveldb/util/no_destructor.h -leveldb_libleveldb_la_SOURCES += leveldb/util/testharness.h -leveldb_libleveldb_la_SOURCES += leveldb/util/windows_logger.h - -leveldb_libleveldb_la_SOURCES += leveldb/db/builder.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/c.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/dbformat.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/db_impl.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/db_iter.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/dumpfile.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/filename.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/log_reader.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/log_writer.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/memtable.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/repair.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/table_cache.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/version_edit.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/version_set.cc -leveldb_libleveldb_la_SOURCES += leveldb/db/write_batch.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/block_builder.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/block.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/filter_block.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/format.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/iterator.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/merger.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/table_builder.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/table.cc -leveldb_libleveldb_la_SOURCES += leveldb/table/two_level_iterator.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/arena.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/bloom.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/cache.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/coding.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/comparator.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/crc32c.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/env.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/filter_policy.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/hash.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/histogram.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/logging.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/options.cc -leveldb_libleveldb_la_SOURCES += leveldb/util/status.cc - -if TARGET_WINDOWS -leveldb_libleveldb_la_SOURCES += leveldb/util/env_windows.cc -else -leveldb_libleveldb_la_SOURCES += leveldb/util/env_posix.cc -endif - -leveldb_libmemenv_la_CPPFLAGS = $(leveldb_libleveldb_la_CPPFLAGS) -leveldb_libmemenv_la_CXXFLAGS = $(leveldb_libleveldb_la_CXXFLAGS) -leveldb_libmemenv_la_LDFLAGS = $(leveldb_libleveldb_la_LDFLAGS) -leveldb_libmemenv_la_SOURCES = leveldb/helpers/memenv/memenv.cc -leveldb_libmemenv_la_SOURCES += leveldb/helpers/memenv/memenv.h diff --git a/src/Makefile.minisketch.include b/src/Makefile.minisketch.include deleted file mode 100644 index c6f894f0ca..0000000000 --- a/src/Makefile.minisketch.include +++ /dev/null @@ -1,39 +0,0 @@ -include minisketch/sources.mk - -LIBMINISKETCH_CPPFLAGS= -LIBMINISKETCH_CPPFLAGS += -DDISABLE_DEFAULT_FIELDS -DENABLE_FIELD_32 - -LIBMINISKETCH = minisketch/libminisketch.a -MINISKETCH_LIBS = $(LIBMINISKETCH) - -if ENABLE_CLMUL -LIBMINISKETCH_CLMUL = minisketch/libminisketch_clmul.a -LIBMINISKETCH_CPPFLAGS += -DHAVE_CLMUL -MINISKETCH_LIBS += $(LIBMINISKETCH_CLMUL) -endif - -EXTRA_LIBRARIES += $(MINISKETCH_LIBS) - -minisketch_libminisketch_clmul_a_SOURCES = $(MINISKETCH_FIELD_CLMUL_SOURCES_INT) $(MINISKETCH_FIELD_CLMUL_HEADERS_INT) -minisketch_libminisketch_clmul_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(CLMUL_CXXFLAGS) -minisketch_libminisketch_clmul_a_CPPFLAGS = $(AM_CPPFLAGS) $(LIBMINISKETCH_CPPFLAGS) - -minisketch_libminisketch_a_SOURCES = $(MINISKETCH_FIELD_GENERIC_SOURCES_INT) $(MINISKETCH_LIB_SOURCES_INT) -minisketch_libminisketch_a_SOURCES += $(MINISKETCH_FIELD_GENERIC_HEADERS_INT) $(MINISKETCH_LIB_HEADERS_INT) $(MINISKETCH_DIST_HEADERS_INT) -minisketch_libminisketch_a_CPPFLAGS = $(AM_CPPFLAGS) $(LIBMINISKETCH_CPPFLAGS) -minisketch_libminisketch_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) - -if ENABLE_TESTS -if !ENABLE_FUZZ -MINISKETCH_TEST = minisketch/test -TESTS += $(MINISKETCH_TEST) -check_PROGRAMS += $(MINISKETCH_TEST) - -minisketch_test_SOURCES = $(MINISKETCH_TEST_SOURCES_INT) -minisketch_test_CPPFLAGS = $(AM_CPPFLAGS) $(LIBMINISKETCH_CPPFLAGS) -minisketch_test_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -minisketch_test_LDADD = $(MINISKETCH_LIBS) -minisketch_test_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) - -endif -endif diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include deleted file mode 100644 index 1ac6b74688..0000000000 --- a/src/Makefile.qt.include +++ /dev/null @@ -1,409 +0,0 @@ -# Copyright (c) 2013-2016 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -bin_PROGRAMS += qt/bitcoin-qt - -if BUILD_BITCOIN_GUI - bin_PROGRAMS += bitcoin-gui -endif - -EXTRA_LIBRARIES += qt/libbitcoinqt.a - -# bitcoin qt core # -include Makefile.qt_locale.include - -QT_FORMS_UI = \ - qt/forms/addressbookpage.ui \ - qt/forms/askpassphrasedialog.ui \ - qt/forms/coincontroldialog.ui \ - qt/forms/createwalletdialog.ui \ - qt/forms/editaddressdialog.ui \ - qt/forms/helpmessagedialog.ui \ - qt/forms/intro.ui \ - qt/forms/modaloverlay.ui \ - qt/forms/openuridialog.ui \ - qt/forms/optionsdialog.ui \ - qt/forms/overviewpage.ui \ - qt/forms/psbtoperationsdialog.ui \ - qt/forms/receivecoinsdialog.ui \ - qt/forms/receiverequestdialog.ui \ - qt/forms/debugwindow.ui \ - qt/forms/sendcoinsdialog.ui \ - qt/forms/sendcoinsentry.ui \ - qt/forms/signverifymessagedialog.ui \ - qt/forms/transactiondescdialog.ui - -QT_MOC_CPP = \ - qt/moc_addressbookpage.cpp \ - qt/moc_addresstablemodel.cpp \ - qt/moc_askpassphrasedialog.cpp \ - qt/moc_createwalletdialog.cpp \ - qt/moc_bantablemodel.cpp \ - qt/moc_bitcoin.cpp \ - qt/moc_bitcoinaddressvalidator.cpp \ - qt/moc_bitcoinamountfield.cpp \ - qt/moc_bitcoingui.cpp \ - qt/moc_bitcoinunits.cpp \ - qt/moc_clientmodel.cpp \ - qt/moc_coincontroldialog.cpp \ - qt/moc_coincontroltreewidget.cpp \ - qt/moc_csvmodelwriter.cpp \ - qt/moc_editaddressdialog.cpp \ - qt/moc_guiutil.cpp \ - qt/moc_initexecutor.cpp \ - qt/moc_intro.cpp \ - qt/moc_macdockiconhandler.cpp \ - qt/moc_macnotificationhandler.cpp \ - qt/moc_modaloverlay.cpp \ - qt/moc_notificator.cpp \ - qt/moc_openuridialog.cpp \ - qt/moc_optionsdialog.cpp \ - qt/moc_optionsmodel.cpp \ - qt/moc_overviewpage.cpp \ - qt/moc_peertablemodel.cpp \ - qt/moc_peertablesortproxy.cpp \ - qt/moc_paymentserver.cpp \ - qt/moc_psbtoperationsdialog.cpp \ - qt/moc_qrimagewidget.cpp \ - qt/moc_qvalidatedlineedit.cpp \ - qt/moc_qvaluecombobox.cpp \ - qt/moc_receivecoinsdialog.cpp \ - qt/moc_receiverequestdialog.cpp \ - qt/moc_recentrequeststablemodel.cpp \ - qt/moc_rpcconsole.cpp \ - qt/moc_sendcoinsdialog.cpp \ - qt/moc_sendcoinsentry.cpp \ - qt/moc_signverifymessagedialog.cpp \ - qt/moc_splashscreen.cpp \ - qt/moc_trafficgraphwidget.cpp \ - qt/moc_transactiondesc.cpp \ - qt/moc_transactiondescdialog.cpp \ - qt/moc_transactionfilterproxy.cpp \ - qt/moc_transactionoverviewwidget.cpp \ - qt/moc_transactiontablemodel.cpp \ - qt/moc_transactionview.cpp \ - qt/moc_utilitydialog.cpp \ - qt/moc_walletcontroller.cpp \ - qt/moc_walletframe.cpp \ - qt/moc_walletmodel.cpp \ - qt/moc_walletview.cpp - -BITCOIN_MM = \ - qt/macdockiconhandler.mm \ - qt/macnotificationhandler.mm \ - qt/macos_appnap.mm - -QT_MOC = \ - qt/bitcoinamountfield.moc \ - qt/intro.moc \ - qt/overviewpage.moc \ - qt/rpcconsole.moc - -QT_QRC_CPP = qt/qrc_bitcoin.cpp -QT_QRC = qt/bitcoin.qrc -QT_QRC_LOCALE_CPP = qt/qrc_bitcoin_locale.cpp -QT_QRC_LOCALE = qt/bitcoin_locale.qrc - -BITCOIN_QT_H = \ - qt/addressbookpage.h \ - qt/addresstablemodel.h \ - qt/askpassphrasedialog.h \ - qt/bantablemodel.h \ - qt/bitcoin.h \ - qt/bitcoinaddressvalidator.h \ - qt/bitcoinamountfield.h \ - qt/bitcoingui.h \ - qt/bitcoinunits.h \ - qt/clientmodel.h \ - qt/coincontroldialog.h \ - qt/coincontroltreewidget.h \ - qt/createwalletdialog.h \ - qt/csvmodelwriter.h \ - qt/editaddressdialog.h \ - qt/guiconstants.h \ - qt/guiutil.h \ - qt/initexecutor.h \ - qt/intro.h \ - qt/macdockiconhandler.h \ - qt/macnotificationhandler.h \ - qt/macos_appnap.h \ - qt/modaloverlay.h \ - qt/networkstyle.h \ - qt/notificator.h \ - qt/openuridialog.h \ - qt/optionsdialog.h \ - qt/optionsmodel.h \ - qt/overviewpage.h \ - qt/paymentserver.h \ - qt/peertablemodel.h \ - qt/peertablesortproxy.h \ - qt/platformstyle.h \ - qt/psbtoperationsdialog.h \ - qt/qrimagewidget.h \ - qt/qvalidatedlineedit.h \ - qt/qvaluecombobox.h \ - qt/receivecoinsdialog.h \ - qt/receiverequestdialog.h \ - qt/recentrequeststablemodel.h \ - qt/rpcconsole.h \ - qt/sendcoinsdialog.h \ - qt/sendcoinsentry.h \ - qt/sendcoinsrecipient.h \ - qt/signverifymessagedialog.h \ - qt/splashscreen.h \ - qt/trafficgraphwidget.h \ - qt/transactiondesc.h \ - qt/transactiondescdialog.h \ - qt/transactionfilterproxy.h \ - qt/transactionoverviewwidget.h \ - qt/transactionrecord.h \ - qt/transactiontablemodel.h \ - qt/transactionview.h \ - qt/utilitydialog.h \ - qt/walletcontroller.h \ - qt/walletframe.h \ - qt/walletmodel.h \ - qt/walletmodeltransaction.h \ - qt/walletview.h \ - qt/winshutdownmonitor.h - -QT_RES_FONTS = \ - qt/res/fonts/RobotoMono-Bold.ttf - -QT_RES_ICONS = \ - qt/res/icons/add.png \ - qt/res/icons/address-book.png \ - qt/res/icons/bitcoin.ico \ - qt/res/icons/bitcoin_testnet.ico \ - qt/res/icons/bitcoin.png \ - qt/res/icons/chevron.png \ - qt/res/icons/clock1.png \ - qt/res/icons/clock2.png \ - qt/res/icons/clock3.png \ - qt/res/icons/clock4.png \ - qt/res/icons/clock5.png \ - qt/res/icons/connect0.png \ - qt/res/icons/connect1.png \ - qt/res/icons/connect2.png \ - qt/res/icons/connect3.png \ - qt/res/icons/connect4.png \ - qt/res/icons/edit.png \ - qt/res/icons/editcopy.png \ - qt/res/icons/editpaste.png \ - qt/res/icons/export.png \ - qt/res/icons/eye.png \ - qt/res/icons/eye_minus.png \ - qt/res/icons/eye_plus.png \ - qt/res/icons/fontbigger.png \ - qt/res/icons/fontsmaller.png \ - qt/res/icons/hd_disabled.png \ - qt/res/icons/hd_enabled.png \ - qt/res/icons/history.png \ - qt/res/icons/lock_closed.png \ - qt/res/icons/lock_open.png \ - qt/res/icons/network_disabled.png \ - qt/res/icons/overview.png \ - qt/res/icons/proxy.png \ - qt/res/icons/receive.png \ - qt/res/icons/remove.png \ - qt/res/icons/send.png \ - qt/res/icons/synced.png \ - qt/res/icons/transaction0.png \ - qt/res/icons/transaction2.png \ - qt/res/icons/transaction_abandoned.png \ - qt/res/icons/transaction_conflicted.png \ - qt/res/icons/tx_inout.png \ - qt/res/icons/tx_input.png \ - qt/res/icons/tx_output.png \ - qt/res/icons/tx_mined.png \ - qt/res/icons/warning.png - -BITCOIN_QT_BASE_CPP = \ - qt/bantablemodel.cpp \ - qt/bitcoin.cpp \ - qt/bitcoinaddressvalidator.cpp \ - qt/bitcoinamountfield.cpp \ - qt/bitcoingui.cpp \ - qt/bitcoinunits.cpp \ - qt/clientmodel.cpp \ - qt/csvmodelwriter.cpp \ - qt/guiutil.cpp \ - qt/initexecutor.cpp \ - qt/intro.cpp \ - qt/modaloverlay.cpp \ - qt/networkstyle.cpp \ - qt/notificator.cpp \ - qt/optionsdialog.cpp \ - qt/optionsmodel.cpp \ - qt/peertablemodel.cpp \ - qt/peertablesortproxy.cpp \ - qt/platformstyle.cpp \ - qt/qvalidatedlineedit.cpp \ - qt/qvaluecombobox.cpp \ - qt/rpcconsole.cpp \ - qt/splashscreen.cpp \ - qt/trafficgraphwidget.cpp \ - qt/utilitydialog.cpp - -BITCOIN_QT_WINDOWS_CPP = qt/winshutdownmonitor.cpp - -BITCOIN_QT_WALLET_CPP = \ - qt/addressbookpage.cpp \ - qt/addresstablemodel.cpp \ - qt/askpassphrasedialog.cpp \ - qt/coincontroldialog.cpp \ - qt/coincontroltreewidget.cpp \ - qt/createwalletdialog.cpp \ - qt/editaddressdialog.cpp \ - qt/openuridialog.cpp \ - qt/overviewpage.cpp \ - qt/paymentserver.cpp \ - qt/psbtoperationsdialog.cpp \ - qt/qrimagewidget.cpp \ - qt/receivecoinsdialog.cpp \ - qt/receiverequestdialog.cpp \ - qt/recentrequeststablemodel.cpp \ - qt/sendcoinsdialog.cpp \ - qt/sendcoinsentry.cpp \ - qt/signverifymessagedialog.cpp \ - qt/transactiondesc.cpp \ - qt/transactiondescdialog.cpp \ - qt/transactionfilterproxy.cpp \ - qt/transactionoverviewwidget.cpp \ - qt/transactionrecord.cpp \ - qt/transactiontablemodel.cpp \ - qt/transactionview.cpp \ - qt/walletcontroller.cpp \ - qt/walletframe.cpp \ - qt/walletmodel.cpp \ - qt/walletmodeltransaction.cpp \ - qt/walletview.cpp - -BITCOIN_QT_CPP = $(BITCOIN_QT_BASE_CPP) -if TARGET_WINDOWS -BITCOIN_QT_CPP += $(BITCOIN_QT_WINDOWS_CPP) -endif -if ENABLE_WALLET -BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP) -endif # ENABLE_WALLET - -QT_RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png) - -BITCOIN_QT_RC = qt/res/bitcoin-qt-res.rc - -BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER - -qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS) $(BOOST_CPPFLAGS) -qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) -qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS) - -qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \ - $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(QT_RES_FONTS) $(QT_RES_ICONS) $(QT_RES_ANIMATION) -if TARGET_DARWIN - qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM) -endif - -nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP) - -# forms/foo.h -> forms/ui_foo.h -QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h)))) - -# Most files will depend on the forms and moc files as includes. Generate them -# before anything else. -$(QT_MOC): $(QT_FORMS_H) -$(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) $(bitcoin_gui_OBJECTS) : | $(QT_MOC) - -# bitcoin-qt and bitcoin-gui binaries # -bitcoin_qt_cppflags = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(QR_CFLAGS) -bitcoin_qt_cxxflags = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) - -bitcoin_qt_sources = qt/main.cpp -if TARGET_WINDOWS - bitcoin_qt_sources += $(BITCOIN_QT_RC) -endif -bitcoin_qt_ldadd = qt/libbitcoinqt.a $(LIBBITCOIN_NODE) -if ENABLE_WALLET -bitcoin_qt_ldadd += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET) -endif -if ENABLE_ZMQ -bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) -endif -bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ - $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \ - $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS) -bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX - -qt_bitcoin_qt_CPPFLAGS = $(bitcoin_qt_cppflags) -qt_bitcoin_qt_CXXFLAGS = $(bitcoin_qt_cxxflags) -qt_bitcoin_qt_SOURCES = $(bitcoin_qt_sources) init/bitcoin-qt.cpp -qt_bitcoin_qt_LDADD = $(bitcoin_qt_ldadd) -qt_bitcoin_qt_LDFLAGS = $(bitcoin_qt_ldflags) -qt_bitcoin_qt_LIBTOOLFLAGS = $(bitcoin_qt_libtoolflags) - -bitcoin_gui_CPPFLAGS = $(bitcoin_qt_cppflags) -bitcoin_gui_CXXFLAGS = $(bitcoin_qt_cxxflags) -bitcoin_gui_SOURCES = $(bitcoin_qt_sources) init/bitcoin-gui.cpp -bitcoin_gui_LDADD = $(bitcoin_qt_ldadd) $(LIBBITCOIN_IPC) $(LIBBITCOIN_UTIL) $(LIBMULTIPROCESS_LIBS) -bitcoin_gui_LDFLAGS = $(bitcoin_qt_ldflags) -bitcoin_gui_LIBTOOLFLAGS = $(bitcoin_qt_libtoolflags) - -#locale/foo.ts -> locale/foo.qm -QT_QM=$(QT_TS:.ts=.qm) - -SECONDARY: $(QT_QM) - -$(srcdir)/qt/bitcoinstrings.cpp: FORCE - @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" - $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py \ - $(libbitcoin_node_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) \ - $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES) \ - $(BITCOIN_QT_BASE_CPP) $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) - -# The resulted bitcoin_en.xlf source file should follow Transifex requirements. -# See: https://docs.transifex.com/formats/xliff#how-to-distinguish-between-a-source-file-and-a-translation-file -translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) - @test -n $(LUPDATE) || echo "lupdate is required for updating translations" - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) -no-obsolete -I $(srcdir) -locations relative $^ -ts $(srcdir)/qt/locale/bitcoin_en.ts - @test -n $(LCONVERT) || echo "lconvert is required for updating translations" - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LCONVERT) -drop-translations -o $(srcdir)/qt/locale/bitcoin_en.xlf -i $(srcdir)/qt/locale/bitcoin_en.ts - @$(SED) -i.old -e 's|source-language="en" target-language="en"|source-language="en"|' -e '/<target xml:space="preserve"><\/target>/d' $(srcdir)/qt/locale/bitcoin_en.xlf - @rm -f $(srcdir)/qt/locale/bitcoin_en.xlf.old - -$(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) - @test -f $(RCC) || (echo "rcc $(RCC) not found, but is required for generating qrc cpp files"; exit 1) - @cp -f $< $(@D)/temp_$(<F) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale --format-version 1 $(@D)/temp_$(<F) > $@ - @rm $(@D)/temp_$(<F) - -$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(QT_RES_FONTS) $(QT_RES_ICONS) $(QT_RES_ANIMATION) - @test -f $(RCC) || (echo "rcc $(RCC) not found, but is required for generating qrc cpp files"; exit 1) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin --format-version 1 $< > $@ - -CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno qt/temp_bitcoin_locale.qrc - -CLEANFILES += $(CLEAN_QT) - -bitcoin_qt_clean: FORCE - rm -f $(CLEAN_QT) $(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) qt/bitcoin-qt$(EXEEXT) $(LIBBITCOINQT) - -bitcoin_qt : qt/bitcoin-qt$(EXEEXT) - -ui_%.h: %.ui - @test -f $(UIC) || (echo "uic $(UIC) not found, but is required for generating ui headers"; exit 1) - @$(MKDIR_P) $(@D) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(UIC) -o $@ $< || (echo "Error creating $@"; false) - -%.moc: %.cpp - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES_UNSUPPRESSED) $(MOC_DEFS) $< > $@ - -moc_%.cpp: %.h - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES_UNSUPPRESSED) $(MOC_DEFS) $< > $@ - -%.qm: %.ts - @test -f $(LRELEASE) || (echo "lrelease $(LRELEASE) not found, but is required for generating translations"; exit 1) - @$(MKDIR_P) $(@D) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LRELEASE) -silent $< -qm $@ diff --git a/src/Makefile.qt_locale.include b/src/Makefile.qt_locale.include deleted file mode 100644 index 2af9fd01af..0000000000 --- a/src/Makefile.qt_locale.include +++ /dev/null @@ -1,124 +0,0 @@ -QT_TS = \ - qt/locale/bitcoin_af.ts \ - qt/locale/bitcoin_am.ts \ - qt/locale/bitcoin_ar.ts \ - qt/locale/bitcoin_az.ts \ - qt/locale/bitcoin_az@latin.ts \ - qt/locale/bitcoin_be.ts \ - qt/locale/bitcoin_bg.ts \ - qt/locale/bitcoin_bn.ts \ - qt/locale/bitcoin_br.ts \ - qt/locale/bitcoin_bs.ts \ - qt/locale/bitcoin_ca.ts \ - qt/locale/bitcoin_cmn.ts \ - qt/locale/bitcoin_cs.ts \ - qt/locale/bitcoin_cy.ts \ - qt/locale/bitcoin_da.ts \ - qt/locale/bitcoin_de.ts \ - qt/locale/bitcoin_de_AT.ts \ - qt/locale/bitcoin_de_CH.ts \ - qt/locale/bitcoin_el.ts \ - qt/locale/bitcoin_en.ts \ - qt/locale/bitcoin_eo.ts \ - qt/locale/bitcoin_es.ts \ - qt/locale/bitcoin_es_CL.ts \ - qt/locale/bitcoin_es_CO.ts \ - qt/locale/bitcoin_es_DO.ts \ - qt/locale/bitcoin_es_MX.ts \ - qt/locale/bitcoin_es_SV.ts \ - qt/locale/bitcoin_es_VE.ts \ - qt/locale/bitcoin_et.ts \ - qt/locale/bitcoin_eu.ts \ - qt/locale/bitcoin_fa.ts \ - qt/locale/bitcoin_fi.ts \ - qt/locale/bitcoin_fil.ts \ - qt/locale/bitcoin_fo.ts \ - qt/locale/bitcoin_fr.ts \ - qt/locale/bitcoin_fr_CM.ts \ - qt/locale/bitcoin_fr_LU.ts \ - qt/locale/bitcoin_ga.ts \ - qt/locale/bitcoin_ga_IE.ts \ - qt/locale/bitcoin_gd.ts \ - qt/locale/bitcoin_gl.ts \ - qt/locale/bitcoin_gl_ES.ts \ - qt/locale/bitcoin_gu.ts \ - qt/locale/bitcoin_ha.ts \ - qt/locale/bitcoin_hak.ts \ - qt/locale/bitcoin_he.ts \ - qt/locale/bitcoin_hi.ts \ - qt/locale/bitcoin_hr.ts \ - qt/locale/bitcoin_hu.ts \ - qt/locale/bitcoin_id.ts \ - qt/locale/bitcoin_is.ts \ - qt/locale/bitcoin_it.ts \ - qt/locale/bitcoin_ja.ts \ - qt/locale/bitcoin_ka.ts \ - qt/locale/bitcoin_kk.ts \ - qt/locale/bitcoin_kk@latin.ts \ - qt/locale/bitcoin_kl.ts \ - qt/locale/bitcoin_km.ts \ - qt/locale/bitcoin_kn.ts \ - qt/locale/bitcoin_ko.ts \ - qt/locale/bitcoin_ku.ts \ - qt/locale/bitcoin_ku_IQ.ts \ - qt/locale/bitcoin_ky.ts \ - qt/locale/bitcoin_la.ts \ - qt/locale/bitcoin_lb.ts \ - qt/locale/bitcoin_lt.ts \ - qt/locale/bitcoin_lv.ts \ - qt/locale/bitcoin_mg.ts \ - qt/locale/bitcoin_mi.ts \ - qt/locale/bitcoin_mk.ts \ - qt/locale/bitcoin_ml.ts \ - qt/locale/bitcoin_mn.ts \ - qt/locale/bitcoin_mr.ts \ - qt/locale/bitcoin_mr_IN.ts \ - qt/locale/bitcoin_ms.ts \ - qt/locale/bitcoin_mt.ts \ - qt/locale/bitcoin_my.ts \ - qt/locale/bitcoin_nb.ts \ - qt/locale/bitcoin_ne.ts \ - qt/locale/bitcoin_nl.ts \ - qt/locale/bitcoin_no.ts \ - qt/locale/bitcoin_pa.ts \ - qt/locale/bitcoin_pam.ts \ - qt/locale/bitcoin_pl.ts \ - qt/locale/bitcoin_pt.ts \ - qt/locale/bitcoin_pt_BR.ts \ - qt/locale/bitcoin_ro.ts \ - qt/locale/bitcoin_ru.ts \ - qt/locale/bitcoin_sc.ts \ - qt/locale/bitcoin_sd.ts \ - qt/locale/bitcoin_si.ts \ - qt/locale/bitcoin_sk.ts \ - qt/locale/bitcoin_sl.ts \ - qt/locale/bitcoin_sn.ts \ - qt/locale/bitcoin_so.ts \ - qt/locale/bitcoin_sq.ts \ - qt/locale/bitcoin_sr.ts \ - qt/locale/bitcoin_sr@ijekavianlatin.ts \ - qt/locale/bitcoin_sr@latin.ts \ - qt/locale/bitcoin_sv.ts \ - qt/locale/bitcoin_sw.ts \ - qt/locale/bitcoin_szl.ts \ - qt/locale/bitcoin_ta.ts \ - qt/locale/bitcoin_te.ts \ - qt/locale/bitcoin_tk.ts \ - qt/locale/bitcoin_tl.ts \ - qt/locale/bitcoin_tr.ts \ - qt/locale/bitcoin_ug.ts \ - qt/locale/bitcoin_uk.ts \ - qt/locale/bitcoin_ur.ts \ - qt/locale/bitcoin_uz.ts \ - qt/locale/bitcoin_uz@Cyrl.ts \ - qt/locale/bitcoin_uz@Latn.ts \ - qt/locale/bitcoin_vi.ts \ - qt/locale/bitcoin_yo.ts \ - qt/locale/bitcoin_yue.ts \ - qt/locale/bitcoin_zh-Hans.ts \ - qt/locale/bitcoin_zh-Hant.ts \ - qt/locale/bitcoin_zh.ts \ - qt/locale/bitcoin_zh_CN.ts \ - qt/locale/bitcoin_zh_HK.ts \ - qt/locale/bitcoin_zh_TW.ts \ - qt/locale/bitcoin_zu.ts diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include deleted file mode 100644 index 89c659d4b9..0000000000 --- a/src/Makefile.qttest.include +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2013-2016 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -bin_PROGRAMS += qt/test/test_bitcoin-qt -TESTS += qt/test/test_bitcoin-qt - -TEST_QT_MOC_CPP = \ - qt/test/moc_apptests.cpp \ - qt/test/moc_optiontests.cpp \ - qt/test/moc_rpcnestedtests.cpp \ - qt/test/moc_uritests.cpp - -if ENABLE_WALLET -TEST_QT_MOC_CPP += \ - qt/test/moc_addressbooktests.cpp \ - qt/test/moc_wallettests.cpp -endif # ENABLE_WALLET - -TEST_QT_H = \ - qt/test/addressbooktests.h \ - qt/test/apptests.h \ - qt/test/optiontests.h \ - qt/test/rpcnestedtests.h \ - qt/test/uritests.h \ - qt/test/util.h \ - qt/test/wallettests.h - -qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(BOOST_CPPFLAGS) - -qt_test_test_bitcoin_qt_SOURCES = \ - init/bitcoin-qt.cpp \ - qt/test/apptests.cpp \ - qt/test/optiontests.cpp \ - qt/test/rpcnestedtests.cpp \ - qt/test/test_main.cpp \ - qt/test/uritests.cpp \ - qt/test/util.cpp \ - $(TEST_QT_H) -if ENABLE_WALLET -qt_test_test_bitcoin_qt_SOURCES += \ - qt/test/addressbooktests.cpp \ - qt/test/wallettests.cpp \ - wallet/test/wallet_test_fixture.cpp -endif # ENABLE_WALLET - -nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP) - -qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_NODE) $(LIBTEST_UTIL) -if ENABLE_WALLET -qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET) -endif -if ENABLE_ZMQ -qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) -endif -qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ - $(LIBMEMENV) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \ - $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \ - $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS) -qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) - -CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno - -CLEANFILES += $(CLEAN_BITCOIN_QT_TEST) - -test_bitcoin_qt : qt/test/test_bitcoin-qt$(EXEEXT) - -test_bitcoin_qt_check : qt/test/test_bitcoin-qt$(EXEEXT) FORCE - $(MAKE) check-TESTS TESTS=$^ - -test_bitcoin_qt_clean: FORCE - rm -f $(CLEAN_BITCOIN_QT_TEST) $(qt_test_test_bitcoin_qt_OBJECTS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include deleted file mode 100644 index 742022ca93..0000000000 --- a/src/Makefile.test.include +++ /dev/null @@ -1,484 +0,0 @@ -# Copyright (c) 2013-2016 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -if ENABLE_FUZZ_BINARY -noinst_PROGRAMS += test/fuzz/fuzz -endif - -if ENABLE_TESTS -bin_PROGRAMS += test/test_bitcoin -endif - -TEST_SRCDIR = test -TEST_BINARY=test/test_bitcoin$(EXEEXT) -FUZZ_BINARY=test/fuzz/fuzz$(EXEEXT) - -JSON_TEST_FILES = \ - test/data/script_tests.json \ - test/data/bip341_wallet_vectors.json \ - test/data/base58_encode_decode.json \ - test/data/blockfilters.json \ - test/data/key_io_valid.json \ - test/data/key_io_invalid.json \ - test/data/script_tests.json \ - test/data/sighash.json \ - test/data/tx_invalid.json \ - test/data/tx_valid.json - -RAW_TEST_FILES = \ - test/data/asmap.raw - -GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) - -BITCOIN_TEST_SUITE = \ - test/main.cpp \ - $(TEST_UTIL_H) - -FUZZ_SUITE_LD_COMMON = \ - $(LIBTEST_UTIL) \ - $(LIBTEST_FUZZ) \ - $(LIBBITCOIN_NODE) \ - $(LIBBITCOIN_WALLET) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBBITCOIN_CLI) \ - $(LIBUNIVALUE) \ - $(LIBLEVELDB) \ - $(LIBMEMENV) \ - $(LIBSECP256K1) \ - $(MINISKETCH_LIBS) \ - $(EVENT_LIBS) \ - $(EVENT_PTHREADS_LIBS) - -if USE_UPNP -FUZZ_SUITE_LD_COMMON += $(MINIUPNPC_LIBS) -endif - -if USE_NATPMP -FUZZ_SUITE_LD_COMMON += $(NATPMP_LIBS) -endif - -# test_bitcoin binary # -BITCOIN_TESTS =\ - test/addrman_tests.cpp \ - test/allocator_tests.cpp \ - test/amount_tests.cpp \ - test/argsman_tests.cpp \ - test/arith_uint256_tests.cpp \ - test/banman_tests.cpp \ - test/base32_tests.cpp \ - test/base58_tests.cpp \ - test/base64_tests.cpp \ - test/bech32_tests.cpp \ - test/bip32_tests.cpp \ - test/bip324_tests.cpp \ - test/blockchain_tests.cpp \ - test/blockencodings_tests.cpp \ - test/blockfilter_index_tests.cpp \ - test/blockfilter_tests.cpp \ - test/blockmanager_tests.cpp \ - test/bloom_tests.cpp \ - test/bswap_tests.cpp \ - test/checkqueue_tests.cpp \ - test/coins_tests.cpp \ - test/coinstatsindex_tests.cpp \ - test/common_url_tests.cpp \ - test/compilerbug_tests.cpp \ - test/compress_tests.cpp \ - test/crypto_tests.cpp \ - test/cuckoocache_tests.cpp \ - test/dbwrapper_tests.cpp \ - test/denialofservice_tests.cpp \ - test/descriptor_tests.cpp \ - test/disconnected_transactions.cpp \ - test/feefrac_tests.cpp \ - test/flatfile_tests.cpp \ - test/fs_tests.cpp \ - test/getarg_tests.cpp \ - test/hash_tests.cpp \ - test/headers_sync_chainwork_tests.cpp \ - test/httpserver_tests.cpp \ - test/i2p_tests.cpp \ - test/interfaces_tests.cpp \ - test/key_io_tests.cpp \ - test/key_tests.cpp \ - test/logging_tests.cpp \ - test/mempool_tests.cpp \ - test/merkle_tests.cpp \ - test/merkleblock_tests.cpp \ - test/miner_tests.cpp \ - test/miniminer_tests.cpp \ - test/miniscript_tests.cpp \ - test/minisketch_tests.cpp \ - test/multisig_tests.cpp \ - test/net_peer_connection_tests.cpp \ - test/net_peer_eviction_tests.cpp \ - test/net_tests.cpp \ - test/netbase_tests.cpp \ - test/orphanage_tests.cpp \ - test/peerman_tests.cpp \ - test/pmt_tests.cpp \ - test/policy_fee_tests.cpp \ - test/policyestimator_tests.cpp \ - test/pool_tests.cpp \ - test/pow_tests.cpp \ - test/prevector_tests.cpp \ - test/raii_event_tests.cpp \ - test/random_tests.cpp \ - test/rbf_tests.cpp \ - test/rest_tests.cpp \ - test/result_tests.cpp \ - test/reverselock_tests.cpp \ - test/rpc_tests.cpp \ - test/sanity_tests.cpp \ - test/scheduler_tests.cpp \ - test/script_p2sh_tests.cpp \ - test/script_parse_tests.cpp \ - test/script_segwit_tests.cpp \ - test/script_standard_tests.cpp \ - test/script_tests.cpp \ - test/scriptnum10.h \ - test/scriptnum_tests.cpp \ - test/serfloat_tests.cpp \ - test/serialize_tests.cpp \ - test/settings_tests.cpp \ - test/sighash_tests.cpp \ - test/sigopcount_tests.cpp \ - test/skiplist_tests.cpp \ - test/sock_tests.cpp \ - test/span_tests.cpp \ - test/streams_tests.cpp \ - test/sync_tests.cpp \ - test/system_tests.cpp \ - test/timeoffsets_tests.cpp \ - test/torcontrol_tests.cpp \ - test/transaction_tests.cpp \ - test/translation_tests.cpp \ - test/txindex_tests.cpp \ - test/txpackage_tests.cpp \ - test/txreconciliation_tests.cpp \ - test/txrequest_tests.cpp \ - test/txvalidation_tests.cpp \ - test/txvalidationcache_tests.cpp \ - test/uint256_tests.cpp \ - test/util_tests.cpp \ - test/util_threadnames_tests.cpp \ - test/validation_block_tests.cpp \ - test/validation_chainstate_tests.cpp \ - test/validation_chainstatemanager_tests.cpp \ - test/validation_flush_tests.cpp \ - test/validation_tests.cpp \ - test/validationinterface_tests.cpp \ - test/versionbits_tests.cpp \ - test/xoroshiro128plusplus_tests.cpp - -if ENABLE_WALLET -BITCOIN_TESTS += \ - wallet/test/feebumper_tests.cpp \ - wallet/test/psbt_wallet_tests.cpp \ - wallet/test/spend_tests.cpp \ - wallet/test/wallet_tests.cpp \ - wallet/test/walletdb_tests.cpp \ - wallet/test/wallet_crypto_tests.cpp \ - wallet/test/wallet_transaction_tests.cpp \ - wallet/test/coinselector_tests.cpp \ - wallet/test/init_tests.cpp \ - wallet/test/ismine_tests.cpp \ - wallet/test/rpc_util_tests.cpp \ - wallet/test/scriptpubkeyman_tests.cpp \ - wallet/test/walletload_tests.cpp \ - wallet/test/group_outputs_tests.cpp - -FUZZ_SUITE_LD_COMMON +=\ - $(SQLITE_LIBS) \ - $(BDB_LIBS) - -if USE_BDB -BITCOIN_TESTS += wallet/test/db_tests.cpp -endif - -FUZZ_WALLET_SRC = \ - wallet/test/fuzz/coincontrol.cpp \ - wallet/test/fuzz/coinselection.cpp \ - wallet/test/fuzz/crypter.cpp \ - wallet/test/fuzz/fees.cpp \ - wallet/test/fuzz/parse_iso8601.cpp \ - wallet/test/fuzz/wallet_bdb_parser.cpp - -if USE_SQLITE -FUZZ_WALLET_SRC += \ - wallet/test/fuzz/notifications.cpp \ - wallet/test/fuzz/scriptpubkeyman.cpp -endif # USE_SQLITE - -BITCOIN_TEST_SUITE += \ - wallet/test/wallet_test_fixture.cpp \ - wallet/test/wallet_test_fixture.h \ - wallet/test/init_test_fixture.cpp \ - wallet/test/init_test_fixture.h -endif # ENABLE_WALLET - -if BUILD_MULTIPROCESS -# Add boost ipc_tests definition to BITCOIN_TESTS -BITCOIN_TESTS += test/ipc_tests.cpp - -# Build ipc_test code in a separate library so it can be compiled with custom -# LIBMULTIPROCESS_CFLAGS without those flags affecting other tests -LIBBITCOIN_IPC_TEST=libbitcoin_ipc_test.a -EXTRA_LIBRARIES += $(LIBBITCOIN_IPC_TEST) -libbitcoin_ipc_test_a_SOURCES = \ - test/ipc_test.cpp \ - test/ipc_test.h -libbitcoin_ipc_test_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -libbitcoin_ipc_test_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(LIBMULTIPROCESS_CFLAGS) - -# Generate various .c++/.h files from the ipc_test.capnp file -include $(MPGEN_PREFIX)/include/mpgen.mk -EXTRA_DIST += test/ipc_test.capnp -libbitcoin_ipc_test_mpgen_output = \ - test/ipc_test.capnp.c++ \ - test/ipc_test.capnp.h \ - test/ipc_test.capnp.proxy-client.c++ \ - test/ipc_test.capnp.proxy-server.c++ \ - test/ipc_test.capnp.proxy-types.c++ \ - test/ipc_test.capnp.proxy-types.h \ - test/ipc_test.capnp.proxy.h -nodist_libbitcoin_ipc_test_a_SOURCES = $(libbitcoin_ipc_test_mpgen_output) -CLEANFILES += $(libbitcoin_ipc_test_mpgen_output) -endif - -# Explicitly list dependencies on generated headers as described in -# https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html#Recording-Dependencies-manually -test/libbitcoin_ipc_test_a-ipc_test.$(OBJEXT): test/ipc_test.capnp.h - -test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) -test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS) -test_test_bitcoin_LDADD = $(LIBTEST_UTIL) -if ENABLE_WALLET -test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) -test_test_bitcoin_CPPFLAGS += $(BDB_CPPFLAGS) -endif -if BUILD_MULTIPROCESS -test_test_bitcoin_LDADD += $(LIBBITCOIN_IPC_TEST) $(LIBMULTIPROCESS_LIBS) -endif - -test_test_bitcoin_LDADD += $(LIBBITCOIN_NODE) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ - $(LIBLEVELDB) $(LIBMEMENV) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) $(MINISKETCH_LIBS) -test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) - -test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) -test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -static - -if ENABLE_ZMQ -test_test_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) -FUZZ_SUITE_LD_COMMON += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) -endif - -if ENABLE_FUZZ_BINARY -test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS) -test_fuzz_fuzz_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_fuzz_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_fuzz_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -test_fuzz_fuzz_SOURCES = \ - $(FUZZ_WALLET_SRC) \ - test/fuzz/addition_overflow.cpp \ - test/fuzz/addrman.cpp \ - test/fuzz/asmap.cpp \ - test/fuzz/asmap_direct.cpp \ - test/fuzz/autofile.cpp \ - test/fuzz/banman.cpp \ - test/fuzz/base_encode_decode.cpp \ - test/fuzz/bech32.cpp \ - test/fuzz/bip324.cpp \ - test/fuzz/bitdeque.cpp \ - test/fuzz/block.cpp \ - test/fuzz/block_header.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/coins_view.cpp \ - test/fuzz/coinscache_sim.cpp \ - test/fuzz/connman.cpp \ - test/fuzz/crypto.cpp \ - test/fuzz/crypto_aes256.cpp \ - test/fuzz/crypto_aes256cbc.cpp \ - test/fuzz/crypto_chacha20.cpp \ - test/fuzz/crypto_common.cpp \ - test/fuzz/crypto_diff_fuzz_chacha20.cpp \ - test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \ - test/fuzz/crypto_poly1305.cpp \ - test/fuzz/cuckoocache.cpp \ - test/fuzz/decode_tx.cpp \ - test/fuzz/descriptor_parse.cpp \ - test/fuzz/deserialize.cpp \ - test/fuzz/eval_script.cpp \ - test/fuzz/feefrac.cpp \ - test/fuzz/fee_rate.cpp \ - test/fuzz/feeratediagram.cpp \ - test/fuzz/fees.cpp \ - test/fuzz/flatfile.cpp \ - test/fuzz/float.cpp \ - test/fuzz/golomb_rice.cpp \ - test/fuzz/headerssync.cpp \ - test/fuzz/hex.cpp \ - test/fuzz/http_request.cpp \ - test/fuzz/integer.cpp \ - test/fuzz/key.cpp \ - test/fuzz/key_io.cpp \ - test/fuzz/kitchen_sink.cpp \ - test/fuzz/load_external_block_file.cpp \ - test/fuzz/locale.cpp \ - test/fuzz/merkleblock.cpp \ - test/fuzz/message.cpp \ - test/fuzz/miniscript.cpp \ - test/fuzz/minisketch.cpp \ - test/fuzz/mini_miner.cpp \ - test/fuzz/muhash.cpp \ - test/fuzz/multiplication_overflow.cpp \ - test/fuzz/net.cpp \ - test/fuzz/net_permissions.cpp \ - test/fuzz/netaddress.cpp \ - test/fuzz/netbase_dns_lookup.cpp \ - test/fuzz/node_eviction.cpp \ - test/fuzz/p2p_transport_serialization.cpp \ - test/fuzz/package_eval.cpp \ - test/fuzz/parse_hd_keypath.cpp \ - test/fuzz/parse_numbers.cpp \ - test/fuzz/parse_script.cpp \ - test/fuzz/parse_univalue.cpp \ - test/fuzz/partially_downloaded_block.cpp \ - test/fuzz/policy_estimator.cpp \ - test/fuzz/policy_estimator_io.cpp \ - test/fuzz/poolresource.cpp \ - test/fuzz/pow.cpp \ - test/fuzz/prevector.cpp \ - test/fuzz/primitives_transaction.cpp \ - test/fuzz/process_message.cpp \ - test/fuzz/process_messages.cpp \ - test/fuzz/protocol.cpp \ - test/fuzz/psbt.cpp \ - test/fuzz/random.cpp \ - test/fuzz/rbf.cpp \ - test/fuzz/rolling_bloom_filter.cpp \ - test/fuzz/rpc.cpp \ - test/fuzz/script.cpp \ - test/fuzz/script_assets_test_minimizer.cpp \ - test/fuzz/script_descriptor_cache.cpp \ - test/fuzz/script_flags.cpp \ - test/fuzz/script_format.cpp \ - test/fuzz/script_interpreter.cpp \ - test/fuzz/script_ops.cpp \ - test/fuzz/script_sigcache.cpp \ - test/fuzz/script_sign.cpp \ - test/fuzz/scriptnum_ops.cpp \ - test/fuzz/secp256k1_ec_seckey_import_export_der.cpp \ - test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp \ - test/fuzz/signature_checker.cpp \ - test/fuzz/signet.cpp \ - test/fuzz/socks5.cpp \ - test/fuzz/span.cpp \ - test/fuzz/spanparsing.cpp \ - test/fuzz/string.cpp \ - test/fuzz/strprintf.cpp \ - test/fuzz/system.cpp \ - test/fuzz/timeoffsets.cpp \ - test/fuzz/torcontrol.cpp \ - test/fuzz/transaction.cpp \ - test/fuzz/tx_in.cpp \ - test/fuzz/tx_out.cpp \ - test/fuzz/tx_pool.cpp \ - test/fuzz/txorphan.cpp \ - test/fuzz/txrequest.cpp \ - test/fuzz/utxo_snapshot.cpp \ - test/fuzz/utxo_total_supply.cpp \ - test/fuzz/validation_load_mempool.cpp \ - test/fuzz/versionbits.cpp -endif # ENABLE_FUZZ_BINARY - -nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) - -$(BITCOIN_TESTS): $(GENERATED_TEST_FILES) - -CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno test/fuzz/*.gcda test/fuzz/*.gcno test/util/*.gcda test/util/*.gcno $(GENERATED_TEST_FILES) $(addsuffix .log,$(basename $(BITCOIN_TESTS))) - -CLEANFILES += $(CLEAN_BITCOIN_TEST) - -if TARGET_WINDOWS -bitcoin_test: $(TEST_BINARY) -else -if ENABLE_BENCH -bitcoin_test: $(TEST_BINARY) $(BENCH_BINARY) -else -bitcoin_test: $(TEST_BINARY) -endif -endif - -bitcoin_test_check: $(TEST_BINARY) FORCE - $(MAKE) check-TESTS TESTS=$^ - -bitcoin_test_clean : FORCE - rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) - -check-unit: $(BITCOIN_TESTS:.cpp=.cpp.test) - -check-local: check-unit -if BUILD_BITCOIN_TX - @echo "Running test/util/test_runner.py..." - $(PYTHON) $(top_builddir)/test/util/test_runner.py -endif - @echo "Running test/util/rpcauth-test.py..." - $(PYTHON) $(top_builddir)/test/util/rpcauth-test.py -if TARGET_WINDOWS -else -if ENABLE_BENCH - @echo "Running bench/bench_bitcoin (one iteration sanity check, only high priority)..." - $(BENCH_BINARY) -sanity-check -priority-level=high -endif -endif - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check - -if ENABLE_TESTS -UNIVALUE_TESTS = univalue/test/object univalue/test/unitester -noinst_PROGRAMS += $(UNIVALUE_TESTS) -TESTS += $(UNIVALUE_TESTS) - -univalue_test_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT) -univalue_test_unitester_LDADD = $(LIBUNIVALUE) -univalue_test_unitester_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\" -univalue_test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -univalue_test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT) -univalue_test_object_LDADD = $(LIBUNIVALUE) -univalue_test_object_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) -univalue_test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) -endif - -%.cpp.test: %.cpp - @echo Running tests: $$(\ - cat $< | \ - grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | \ - cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1\ - ) from $< - $(AM_V_at)export TEST_LOGFILE=$(abs_builddir)/$$(\ - echo $< | grep -E -o "(wallet/test/.*\.cpp|test/.*\.cpp)" | $(SED) -e s/\.cpp/.log/ \ - ) && \ - $(TEST_BINARY) --catch_system_errors=no -l test_suite -t "$$(\ - cat $< | \ - grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | \ - cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1\ - )" -- DEBUG_LOG_OUT > "$$TEST_LOGFILE" 2>&1 || (cat "$$TEST_LOGFILE" && false) - -%.json.h: %.json - @$(MKDIR_P) $(@D) - $(AM_V_GEN) { \ - echo "#include <string>" && \ - echo "namespace json_tests{" && \ - echo "static const std::string $(*F){" && \ - $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ - echo "};};"; \ - } > "$@.new" && mv -f "$@.new" "$@" diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include deleted file mode 100644 index b4337991e4..0000000000 --- a/src/Makefile.test_fuzz.include +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2013-2020 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -LIBTEST_FUZZ=libtest_fuzz.a - -EXTRA_LIBRARIES += \ - $(LIBTEST_FUZZ) - -TEST_FUZZ_H = \ - test/fuzz/fuzz.h \ - test/fuzz/FuzzedDataProvider.h \ - test/fuzz/util.h \ - test/fuzz/util/descriptor.h \ - test/fuzz/util/mempool.h \ - test/fuzz/util/net.h - -libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) -libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libtest_fuzz_a_SOURCES = \ - test/fuzz/fuzz.cpp \ - test/fuzz/util.cpp \ - test/fuzz/util/descriptor.cpp \ - test/fuzz/util/mempool.cpp \ - test/fuzz/util/net.cpp \ - $(TEST_FUZZ_H) diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include deleted file mode 100644 index 6a1fd712bd..0000000000 --- a/src/Makefile.test_util.include +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2013-2019 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -LIBTEST_UTIL=libtest_util.a - -EXTRA_LIBRARIES += \ - $(LIBTEST_UTIL) - -TEST_UTIL_H = \ - test/util/blockfilter.h \ - test/util/chainstate.h \ - test/util/coins.h \ - test/util/index.h \ - test/util/json.h \ - test/util/logging.h \ - test/util/mining.h \ - test/util/net.h \ - test/util/poolresourcetester.h \ - test/util/random.h \ - test/util/script.h \ - test/util/setup_common.h \ - test/util/str.h \ - test/util/transaction_utils.h \ - test/util/txmempool.h \ - test/util/validation.h \ - test/util/xoroshiro128plusplus.h - -if ENABLE_WALLET -TEST_UTIL_H += wallet/test/util.h -endif # ENABLE_WALLET - -libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) -libtest_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libtest_util_a_SOURCES = \ - test/util/blockfilter.cpp \ - test/util/coins.cpp \ - test/util/index.cpp \ - test/util/json.cpp \ - test/util/logging.cpp \ - test/util/mining.cpp \ - test/util/net.cpp \ - test/util/random.cpp \ - test/util/script.cpp \ - test/util/setup_common.cpp \ - test/util/str.cpp \ - test/util/transaction_utils.cpp \ - test/util/txmempool.cpp \ - test/util/validation.cpp - -if ENABLE_WALLET -libtest_util_a_SOURCES += wallet/test/util.cpp -endif # ENABLE_WALLET - -libtest_util_a_SOURCES += $(TEST_UTIL_H) diff --git a/src/Makefile.univalue.include b/src/Makefile.univalue.include deleted file mode 100644 index 3644e36368..0000000000 --- a/src/Makefile.univalue.include +++ /dev/null @@ -1,6 +0,0 @@ -include univalue/sources.mk - -LIBUNIVALUE = libunivalue.la -noinst_LTLIBRARIES += $(LIBUNIVALUE) -libunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT) $(UNIVALUE_DIST_HEADERS_INT) $(UNIVALUE_LIB_HEADERS_INT) $(UNIVALUE_TEST_FILES_INT) -libunivalue_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 4d34c24ba9..4637906441 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <addrdb.h> @@ -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 @@ -73,7 +73,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data remove(pathTmp); return false; } - if (!FileCommit(fileout.Get())) { + if (!fileout.Commit()) { fileout.fclose(); remove(pathTmp); LogError("%s: Failed to flush file %s\n", __func__, fs::PathToString(pathTmp)); 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..358d4fc0a8 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <addrman.h> #include <addrman_impl.h> @@ -188,7 +188,7 @@ void AddrManImpl::Serialize(Stream& s_) const int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); s << nUBuckets; - std::unordered_map<int, int> mapUnkIds; + std::unordered_map<nid_type, int> mapUnkIds; int nIds = 0; for (const auto& entry : mapInfo) { mapUnkIds[entry.first] = nIds; @@ -342,7 +342,7 @@ void AddrManImpl::Unserialize(Stream& s_) serialized_asmap_checksum == supplied_asmap_checksum}; if (!restore_bucketing) { - LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n"); + LogDebug(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n"); } for (auto bucket_entry : bucket_entries) { @@ -387,7 +387,7 @@ void AddrManImpl::Unserialize(Stream& s_) } } if (nLost + nLostUnk > 0) { - LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost); + LogDebug(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost); } const int check_code{CheckAddrman()}; @@ -398,7 +398,7 @@ void AddrManImpl::Unserialize(Stream& s_) } } -AddrInfo* AddrManImpl::Find(const CService& addr, int* pnId) +AddrInfo* AddrManImpl::Find(const CService& addr, nid_type* pnId) { AssertLockHeld(cs); @@ -413,11 +413,11 @@ AddrInfo* AddrManImpl::Find(const CService& addr, int* pnId) return nullptr; } -AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) +AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource, nid_type* pnId) { AssertLockHeld(cs); - int nId = nIdCount++; + nid_type nId = nIdCount++; mapInfo[nId] = AddrInfo(addr, addrSource); mapAddr[addr] = nId; mapInfo[nId].nRandomPos = vRandom.size(); @@ -438,8 +438,8 @@ void AddrManImpl::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size()); - int nId1 = vRandom[nRndPos1]; - int nId2 = vRandom[nRndPos2]; + nid_type nId1 = vRandom[nRndPos1]; + nid_type nId2 = vRandom[nRndPos2]; const auto it_1{mapInfo.find(nId1)}; const auto it_2{mapInfo.find(nId2)}; @@ -453,7 +453,7 @@ void AddrManImpl::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const vRandom[nRndPos2] = nId1; } -void AddrManImpl::Delete(int nId) +void AddrManImpl::Delete(nid_type nId) { AssertLockHeld(cs); @@ -476,19 +476,19 @@ void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos) // if there is an entry in the specified bucket, delete it. if (vvNew[nUBucket][nUBucketPos] != -1) { - int nIdDelete = vvNew[nUBucket][nUBucketPos]; + nid_type nIdDelete = vvNew[nUBucket][nUBucketPos]; AddrInfo& infoDelete = mapInfo[nIdDelete]; assert(infoDelete.nRefCount > 0); infoDelete.nRefCount--; vvNew[nUBucket][nUBucketPos] = -1; - LogPrint(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToStringAddrPort(), nUBucket, nUBucketPos); + LogDebug(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToStringAddrPort(), nUBucket, nUBucketPos); if (infoDelete.nRefCount == 0) { Delete(nIdDelete); } } } -void AddrManImpl::MakeTried(AddrInfo& info, int nId) +void AddrManImpl::MakeTried(AddrInfo& info, nid_type nId) { AssertLockHeld(cs); @@ -515,7 +515,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId) // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there). if (vvTried[nKBucket][nKBucketPos] != -1) { // find an item to evict - int nIdEvict = vvTried[nKBucket][nKBucketPos]; + nid_type nIdEvict = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nIdEvict) == 1); AddrInfo& infoOld = mapInfo[nIdEvict]; @@ -536,7 +536,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId) vvNew[nUBucket][nUBucketPos] = nIdEvict; nNew++; m_network_counts[infoOld.GetNetwork()].n_new++; - LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n", + LogDebug(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n", infoOld.ToStringAddrPort(), nKBucket, nKBucketPos, nUBucket, nUBucketPos); } assert(vvTried[nKBucket][nKBucketPos] == -1); @@ -554,7 +554,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::c if (!addr.IsRoutable()) return false; - int nId; + nid_type nId; AddrInfo* pinfo = Find(addr, &nId); // Do not set a penalty for a source's self-announcement @@ -612,7 +612,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::c pinfo->nRefCount++; vvNew[nUBucket][nUBucketPos] = nId; const auto mapped_as{m_netgroupman.GetMappedAS(addr)}; - LogPrint(BCLog::ADDRMAN, "Added %s%s to new[%i][%i]\n", + LogDebug(BCLog::ADDRMAN, "Added %s%s to new[%i][%i]\n", addr.ToStringAddrPort(), (mapped_as ? strprintf(" mapped to AS%i", mapped_as) : ""), nUBucket, nUBucketPos); } else { if (pinfo->nRefCount == 0) { @@ -627,7 +627,7 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSecond { AssertLockHeld(cs); - int nId; + nid_type nId; m_last_good = time; @@ -663,7 +663,7 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSecond } // Output the entry we'd be colliding with, for debugging purposes auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]); - LogPrint(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n", + LogDebug(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToStringAddrPort() : "", addr.ToStringAddrPort(), m_tried_collisions.size()); @@ -672,7 +672,7 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSecond // move nId to the tried tables MakeTried(info, nId); const auto mapped_as{m_netgroupman.GetMappedAS(addr)}; - LogPrint(BCLog::ADDRMAN, "Moved %s%s to tried[%i][%i]\n", + LogDebug(BCLog::ADDRMAN, "Moved %s%s to tried[%i][%i]\n", addr.ToStringAddrPort(), (mapped_as ? strprintf(" mapped to AS%i", mapped_as) : ""), tried_bucket, tried_bucket_pos); return true; } @@ -685,7 +685,7 @@ bool AddrManImpl::Add_(const std::vector<CAddress>& vAddr, const CNetAddr& sourc added += AddSingle(*it, source, time_penalty) ? 1 : 0; } if (added > 0) { - LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToStringAddr(), nTried, nNew); + LogDebug(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToStringAddr(), nTried, nNew); } return added > 0; } @@ -710,7 +710,7 @@ void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, NodeSeconds } } -std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::optional<Network> network) const +std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, const std::unordered_set<Network>& networks) const { AssertLockHeld(cs); @@ -719,13 +719,18 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::option size_t new_count = nNew; size_t tried_count = nTried; - if (network.has_value()) { - auto it = m_network_counts.find(*network); - if (it == m_network_counts.end()) return {}; - - auto counts = it->second; - new_count = counts.n_new; - tried_count = counts.n_tried; + if (!networks.empty()) { + new_count = 0; + tried_count = 0; + for (auto& network : networks) { + auto it = m_network_counts.find(network); + if (it == m_network_counts.end()) { + continue; + } + auto counts = it->second; + new_count += counts.n_new; + tried_count += counts.n_tried; + } } if (new_only && new_count == 0) return {}; @@ -753,14 +758,15 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::option // Iterate over the positions of that bucket, starting at the initial one, // and looping around. - int i, position, node_id; + int i, position; + nid_type node_id; for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) { position = (initial_position + i) % ADDRMAN_BUCKET_SIZE; node_id = GetEntry(search_tried, bucket, position); if (node_id != -1) { - if (network.has_value()) { + if (!networks.empty()) { const auto it{mapInfo.find(node_id)}; - if (Assume(it != mapInfo.end()) && it->second.GetNetwork() == *network) break; + if (Assume(it != mapInfo.end()) && networks.contains(it->second.GetNetwork())) break; } else { break; } @@ -776,8 +782,8 @@ 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)) { - LogPrint(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new"); + if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) { + LogDebug(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new"); return {info, info.m_last_try}; } @@ -786,7 +792,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::option } } -int AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const +nid_type AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const { AssertLockHeld(cs); @@ -837,7 +843,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct addresses.push_back(ai); } - LogPrint(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size()); + LogDebug(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size()); return addresses; } @@ -849,7 +855,7 @@ std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries_(bool std::vector<std::pair<AddrInfo, AddressPosition>> infos; for (int bucket = 0; bucket < bucket_count; ++bucket) { for (int position = 0; position < ADDRMAN_BUCKET_SIZE; ++position) { - int id = GetEntry(from_tried, bucket, position); + nid_type id = GetEntry(from_tried, bucket, position); if (id >= 0) { AddrInfo info = mapInfo.at(id); AddressPosition location = AddressPosition( @@ -904,8 +910,8 @@ void AddrManImpl::ResolveCollisions_() { AssertLockHeld(cs); - for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) { - int id_new = *it; + for (std::set<nid_type>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) { + nid_type id_new = *it; bool erase_collision = false; @@ -923,7 +929,7 @@ void AddrManImpl::ResolveCollisions_() } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty // Get the to-be-evicted address that is being tested - int id_old = vvTried[tried_bucket][tried_bucket_pos]; + nid_type id_old = vvTried[tried_bucket][tried_bucket_pos]; AddrInfo& info_old = mapInfo[id_old]; const auto current_time{Now<NodeSeconds>()}; @@ -935,7 +941,7 @@ void AddrManImpl::ResolveCollisions_() // Give address at least 60 seconds to successfully connect if (current_time - info_old.m_last_try > 60s) { - LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort()); + LogDebug(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort()); // Replaces an existing address already in the tried table with the new address Good_(info_new, false, current_time); @@ -945,7 +951,7 @@ void AddrManImpl::ResolveCollisions_() // If the collision hasn't resolved in some reasonable amount of time, // just evict the old entry -- we must not be able to // connect to it for some reason. - LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort()); + LogDebug(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort()); Good_(info_new, false, current_time); erase_collision = true; } @@ -969,11 +975,11 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision_() if (m_tried_collisions.size() == 0) return {}; - std::set<int>::iterator it = m_tried_collisions.begin(); + std::set<nid_type>::iterator it = m_tried_collisions.begin(); // Selects a random element from m_tried_collisions std::advance(it, insecure_rand.randrange(m_tried_collisions.size())); - int id_new = *it; + nid_type id_new = *it; // If id_new not found in mapInfo remove it from m_tried_collisions if (mapInfo.count(id_new) != 1) { @@ -1058,15 +1064,15 @@ int AddrManImpl::CheckAddrman() const LOG_TIME_MILLIS_WITH_CATEGORY_MSG_ONCE( strprintf("new %i, tried %i, total %u", nNew, nTried, vRandom.size()), BCLog::ADDRMAN); - std::unordered_set<int> setTried; - std::unordered_map<int, int> mapNew; + std::unordered_set<nid_type> setTried; + std::unordered_map<nid_type, int> mapNew; std::unordered_map<Network, NewTriedCount> local_counts; if (vRandom.size() != (size_t)(nTried + nNew)) return -7; for (const auto& entry : mapInfo) { - int n = entry.first; + nid_type n = entry.first; const AddrInfo& info = entry.second; if (info.fInTried) { if (!TicksSinceEpoch<std::chrono::seconds>(info.m_last_success)) { @@ -1208,11 +1214,11 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision() return ret; } -std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool new_only, std::optional<Network> network) const +std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool new_only, const std::unordered_set<Network>& networks) const { LOCK(cs); Check(); - auto addrRet = Select_(new_only, network); + auto addrRet = Select_(new_only, networks); Check(); return addrRet; } @@ -1315,9 +1321,9 @@ std::pair<CAddress, NodeSeconds> AddrMan::SelectTriedCollision() return m_impl->SelectTriedCollision(); } -std::pair<CAddress, NodeSeconds> AddrMan::Select(bool new_only, std::optional<Network> network) const +std::pair<CAddress, NodeSeconds> AddrMan::Select(bool new_only, const std::unordered_set<Network>& networks) const { - return m_impl->Select(new_only, network); + return m_impl->Select(new_only, networks); } std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const diff --git a/src/addrman.h b/src/addrman.h index be2ee8c2cb..ba6e13bf97 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -15,6 +15,7 @@ #include <cstdint> #include <memory> #include <optional> +#include <unordered_set> #include <utility> #include <vector> @@ -154,12 +155,12 @@ public: * an address from the new table or an empty pair. Passing `false` will return an * empty pair or an address from either the new or tried table (it does not * guarantee a tried entry). - * @param[in] network Select only addresses of this network (nullopt = all). Passing a network may + * @param[in] networks Select only addresses of these networks (empty = all). Passing networks may * slow down the search. * @return CAddress The record for the selected peer. * seconds The last time we attempted to connect to that peer. */ - std::pair<CAddress, NodeSeconds> Select(bool new_only = false, std::optional<Network> network = std::nullopt) const; + std::pair<CAddress, NodeSeconds> Select(bool new_only = false, const std::unordered_set<Network>& networks = {}) const; /** * Return all or many randomly selected addresses, optionally by network. diff --git a/src/addrman_impl.h b/src/addrman_impl.h index dd7f7b318f..a0390b7154 100644 --- a/src/addrman_impl.h +++ b/src/addrman_impl.h @@ -33,6 +33,13 @@ static constexpr int32_t ADDRMAN_BUCKET_SIZE_LOG2{6}; static constexpr int ADDRMAN_BUCKET_SIZE{1 << ADDRMAN_BUCKET_SIZE_LOG2}; /** + * User-defined type for the internally used nIds + * This used to be int, making it feasible for attackers to cause an overflow, + * see https://bitcoincore.org/en/2024/07/31/disclose-addrman-int-overflow/ + */ +using nid_type = int64_t; + +/** * Extended statistics about a CAddress */ class AddrInfo : public CAddress @@ -125,7 +132,7 @@ public: std::pair<CAddress, NodeSeconds> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs); - std::pair<CAddress, NodeSeconds> Select(bool new_only, std::optional<Network> network) const + std::pair<CAddress, NodeSeconds> Select(bool new_only, const std::unordered_set<Network>& networks) const EXCLUSIVE_LOCKS_REQUIRED(!cs); std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered = true) const @@ -179,36 +186,36 @@ private: static constexpr uint8_t INCOMPATIBILITY_BASE = 32; //! last used nId - int nIdCount GUARDED_BY(cs){0}; + nid_type nIdCount GUARDED_BY(cs){0}; //! table with information about all nIds - std::unordered_map<int, AddrInfo> mapInfo GUARDED_BY(cs); + std::unordered_map<nid_type, AddrInfo> mapInfo GUARDED_BY(cs); //! find an nId based on its network address and port. - std::unordered_map<CService, int, CServiceHash> mapAddr GUARDED_BY(cs); + std::unordered_map<CService, nid_type, CServiceHash> mapAddr GUARDED_BY(cs); //! randomly-ordered vector of all nIds //! This is mutable because it is unobservable outside the class, so any //! changes to it (even in const methods) are also unobservable. - mutable std::vector<int> vRandom GUARDED_BY(cs); + mutable std::vector<nid_type> vRandom GUARDED_BY(cs); // number of "tried" entries int nTried GUARDED_BY(cs){0}; //! list of "tried" buckets - int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs); + nid_type vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs); //! number of (unique) "new" entries int nNew GUARDED_BY(cs){0}; //! list of "new" buckets - int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs); + nid_type vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs); //! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse. NodeSeconds m_last_good GUARDED_BY(cs){1s}; //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions. - std::set<int> m_tried_collisions; + std::set<nid_type> m_tried_collisions; /** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */ const int32_t m_consistency_check_ratio; @@ -225,22 +232,22 @@ private: std::unordered_map<Network, NewTriedCount> m_network_counts GUARDED_BY(cs); //! Find an entry. - AddrInfo* Find(const CService& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); + AddrInfo* Find(const CService& addr, nid_type* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom. - AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); + AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, nid_type* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Swap two elements in vRandom. void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs); //! Delete an entry. It must not be in tried, and have refcount 0. - void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs); + void Delete(nid_type nId) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Clear a position in a "new" table. This is the only place where entries are actually deleted. void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Move an entry from the "new" table(s) to the "tried" table - void MakeTried(AddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs); + void MakeTried(AddrInfo& info, nid_type nId) EXCLUSIVE_LOCKS_REQUIRED(cs); /** Attempt to add a single address to addrman's new table. * @see AddrMan::Add() for parameters. */ @@ -252,13 +259,13 @@ private: void Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs); - std::pair<CAddress, NodeSeconds> Select_(bool new_only, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs); + std::pair<CAddress, NodeSeconds> Select_(bool new_only, const std::unordered_set<Network>& networks) const EXCLUSIVE_LOCKS_REQUIRED(cs); /** Helper to generalize looking up an addrman entry from either table. * - * @return int The nid of the entry. If the addrman position is empty or not found, returns -1. + * @return nid_type The nid of the entry. If the addrman position is empty or not found, returns -1. * */ - int GetEntry(bool use_tried, size_t bucket, size_t position) const EXCLUSIVE_LOCKS_REQUIRED(cs); + nid_type GetEntry(bool use_tried, size_t bucket, size_t position) const EXCLUSIVE_LOCKS_REQUIRED(cs); std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered = true) const EXCLUSIVE_LOCKS_REQUIRED(cs); 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/banman.cpp b/src/banman.cpp index 9f668d76a3..2dbfc76df2 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -36,7 +36,7 @@ void BanMan::LoadBanlist() if (m_ban_db.Read(m_banned)) { SweepBanned(); // sweep out unused entries - LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(), + LogDebug(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } else { LogPrintf("Recreating the banlist database\n"); @@ -65,7 +65,7 @@ void BanMan::DumpBanlist() m_is_dirty = true; } - LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(), + LogDebug(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } @@ -193,7 +193,7 @@ void BanMan::SweepBanned() m_banned.erase(it++); m_is_dirty = true; notify_ui = true; - LogPrint(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString()); + LogDebug(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString()); } else { ++it; } diff --git a/src/banman.h b/src/banman.h index c6df7ec3c3..57ba2ac23c 100644 --- a/src/banman.h +++ b/src/banman.h @@ -34,7 +34,7 @@ class CSubNet; // disk on shutdown and reloaded on startup. Banning can be used to // prevent connections with spy nodes or other griefers. // -// 2. Discouragement. If a peer misbehaves enough (see Misbehaving() in +// 2. Discouragement. If a peer misbehaves (see Misbehaving() in // net_processing.cpp), we'll mark that address as discouraged. We still allow // incoming connections from them, but they're preferred for eviction when // we receive new incoming connections. We never make outgoing connections to diff --git a/src/base58.cpp b/src/base58.cpp index cf5d62f164..f9165ed55f 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -14,6 +14,8 @@ #include <limits> +using util::ContainsNoNUL; + /** All alphanumeric characters except for "0", "I", "O", and "l" */ static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static const int8_t mapBase58[256] = { diff --git a/src/bech32.cpp b/src/bech32.cpp index c3c4ca8006..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"; @@ -363,13 +360,13 @@ std::string Encode(Encoding encoding, const std::string& hrp, const data& values // to return a lowercase Bech32/Bech32m string, but if given an uppercase HRP, the // result will always be invalid. for (const char& c : hrp) assert(c < 'A' || c > 'Z'); - data checksum = CreateChecksum(encoding, hrp, values); - data combined = Cat(values, checksum); - std::string ret = hrp + '1'; - ret.reserve(ret.size() + combined.size()); - for (const auto c : combined) { - ret += CHARSET[c]; - } + + std::string ret; + ret.reserve(hrp.size() + 1 + values.size() + CHECKSUM_SIZE); + ret += hrp; + ret += '1'; + for (const uint8_t& i : values) ret += CHARSET[i]; + for (const uint8_t& i : CreateChecksum(encoding, hrp, values)) ret += CHARSET[i]; return ret; } @@ -393,6 +390,7 @@ DecodeResult Decode(const std::string& str, CharLimit limit) { values[i] = rev; } std::string hrp; + hrp.reserve(pos); for (size_t i = 0; i < pos; ++i) { hrp += LowerCase(str[i]); } @@ -425,6 +423,7 @@ std::pair<std::string, std::vector<int>> LocateErrors(const std::string& str, Ch } std::string hrp; + hrp.reserve(pos); for (size_t i = 0; i < pos; ++i) { hrp += LowerCase(str[i]); } 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/.gitignore b/src/bench/.gitignore deleted file mode 100644 index e231fe4cab..0000000000 --- a/src/bench/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bench_bitcoin diff --git a/src/bench/CMakeLists.txt b/src/bench/CMakeLists.txt new file mode 100644 index 0000000000..8a52980e07 --- /dev/null +++ b/src/bench/CMakeLists.txt @@ -0,0 +1,84 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include(GenerateHeaders) +generate_header_from_raw(data/block413567.raw benchmark::data) + +add_executable(bench_bitcoin + bench_bitcoin.cpp + bench.cpp + nanobench.cpp + ${CMAKE_CURRENT_BINARY_DIR}/data/block413567.raw.h +# Benchmarks: + addrman.cpp + base58.cpp + bech32.cpp + bip324_ecdh.cpp + block_assemble.cpp + ccoins_caching.cpp + chacha20.cpp + checkblock.cpp + checkblockindex.cpp + checkqueue.cpp + cluster_linearize.cpp + crypto_hash.cpp + descriptors.cpp + disconnected_transactions.cpp + duplicate_inputs.cpp + ellswift.cpp + examples.cpp + gcs_filter.cpp + hashpadding.cpp + index_blockfilter.cpp + load_external.cpp + lockedpool.cpp + logging.cpp + mempool_eviction.cpp + mempool_stress.cpp + merkle_root.cpp + parse_hex.cpp + peer_eviction.cpp + poly1305.cpp + pool.cpp + prevector.cpp + random.cpp + readblock.cpp + rollingbloom.cpp + rpc_blockchain.cpp + rpc_mempool.cpp + sign_transaction.cpp + streams_findbyte.cpp + strencodings.cpp + util_time.cpp + verify_script.cpp + xor.cpp +) + +target_link_libraries(bench_bitcoin + core_interface + test_util + bitcoin_node + Boost::headers +) + +if(ENABLE_WALLET) + target_sources(bench_bitcoin + PRIVATE + coin_selection.cpp + wallet_balance.cpp + wallet_create.cpp + wallet_create_tx.cpp + wallet_loading.cpp + wallet_ismine.cpp + ) + target_link_libraries(bench_bitcoin bitcoin_wallet) +endif() + +add_test(NAME bench_sanity_check_high_priority + COMMAND bench_bitcoin -sanity-check -priority-level=high +) + +install(TARGETS bench_bitcoin + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp index f044feebba..ceef6c29ab 100644 --- a/src/bench/addrman.cpp +++ b/src/bench/addrman.cpp @@ -4,12 +4,18 @@ #include <addrman.h> #include <bench/bench.h> +#include <compat/compat.h> +#include <netaddress.h> #include <netbase.h> #include <netgroup.h> +#include <protocol.h> #include <random.h> +#include <span.h> +#include <uint256.h> #include <util/check.h> #include <util/time.h> +#include <cstring> #include <optional> #include <vector> @@ -127,7 +133,7 @@ static void AddrManSelectByNetwork(benchmark::Bench& bench) FillAddrMan(addrman); bench.run([&] { - (void)addrman.Select(/*new_only=*/false, NET_I2P); + (void)addrman.Select(/*new_only=*/false, {NET_I2P}); }); } diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp index 78748bc5bd..f078c33964 100644 --- a/src/bench/base58.cpp +++ b/src/bench/base58.cpp @@ -2,11 +2,12 @@ // 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 <base58.h> +#include <bench/bench.h> +#include <span.h> #include <array> +#include <cstring> #include <vector> diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp index 9922653766..6aa73bd056 100644 --- a/src/bench/bech32.cpp +++ b/src/bench/bech32.cpp @@ -2,20 +2,19 @@ // 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 <bech32.h> +#include <bench/bench.h> #include <util/strencodings.h> -#include <string> #include <vector> +using namespace util::hex_literals; static void Bech32Encode(benchmark::Bench& bench) { - std::vector<uint8_t> v = ParseHex("c97f5a67ec381b760aeaf67573bc164845ff39a3bb26a1cee401ac67243b48db"); + constexpr std::array<uint8_t, 32> v{"c97f5a67ec381b760aeaf67573bc164845ff39a3bb26a1cee401ac67243b48db"_hex_u8}; std::vector<unsigned char> tmp = {0}; - tmp.reserve(1 + 32 * 8 / 5); + tmp.reserve(1 + v.size() * 8 / 5); ConvertBits<8, 5, true>([&](unsigned char c) { tmp.push_back(c); }, v.begin(), v.end()); bench.batch(v.size()).unit("byte").run([&] { bech32::Encode(bech32::Encoding::BECH32, "bc", tmp); diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index a13a693ad7..a2dbb11888 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -4,20 +4,26 @@ #include <bench/bench.h> -#include <test/util/setup_common.h> +#include <test/util/setup_common.h> // IWYU pragma: keep +#include <tinyformat.h> #include <util/fs.h> #include <util/string.h> #include <chrono> +#include <compare> #include <fstream> #include <functional> #include <iostream> #include <map> +#include <ratio> #include <regex> +#include <set> +#include <stdexcept> #include <string> #include <vector> using namespace std::chrono_literals; +using util::Join; const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; diff --git a/src/bench/bench.h b/src/bench/bench.h index 6065ddf3fc..f0705f4fed 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -5,17 +5,18 @@ #ifndef BITCOIN_BENCH_BENCH_H #define BITCOIN_BENCH_BENCH_H +#include <bench/nanobench.h> // IWYU pragma: export #include <util/fs.h> #include <util/macros.h> #include <chrono> +#include <cstdint> #include <functional> #include <map> #include <string> +#include <utility> #include <vector> -#include <bench/nanobench.h> // IWYU pragma: export - /* * Usage: diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 8c421c3fec..555dca7d59 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -3,19 +3,22 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> - -#include <clientversion.h> #include <common/args.h> #include <crypto/sha256.h> +#include <tinyformat.h> #include <util/fs.h> -#include <util/strencodings.h> +#include <util/string.h> #include <chrono> #include <cstdint> +#include <cstdlib> +#include <exception> #include <iostream> #include <sstream> #include <vector> +using util::SplitString; + static const char* DEFAULT_BENCH_FILTER = ".*"; static constexpr int64_t DEFAULT_MIN_TIME_MS{10}; /** Priority level default value, run "all" priority levels */ diff --git a/src/bench/bip324_ecdh.cpp b/src/bench/bip324_ecdh.cpp index 88f3932ad8..e6a614dadf 100644 --- a/src/bench/bip324_ecdh.cpp +++ b/src/bench/bip324_ecdh.cpp @@ -3,12 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> - #include <key.h> #include <pubkey.h> #include <random.h> #include <span.h> +#include <algorithm> #include <array> #include <cstddef> diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index ba8ec16119..4005701cae 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -3,17 +3,21 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <consensus/validation.h> -#include <crypto/sha256.h> +#include <consensus/consensus.h> #include <node/miner.h> +#include <primitives/transaction.h> #include <random.h> +#include <script/script.h> +#include <sync.h> #include <test/util/mining.h> #include <test/util/script.h> #include <test/util/setup_common.h> -#include <txmempool.h> #include <validation.h> - +#include <array> +#include <cassert> +#include <cstddef> +#include <memory> #include <vector> static void AssembleBlock(benchmark::Bench& bench) diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index 05b2f5435c..351861536c 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -4,10 +4,15 @@ #include <bench/bench.h> #include <coins.h> +#include <consensus/amount.h> +#include <key.h> #include <policy/policy.h> +#include <primitives/transaction.h> +#include <script/script.h> #include <script/signingprovider.h> #include <test/util/transaction_utils.h> +#include <cassert> #include <vector> // Microbenchmark for simple accesses to a CCoinsViewCache database. Note from diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp index e0bb07d8be..f154d8c6be 100644 --- a/src/bench/chacha20.cpp +++ b/src/bench/chacha20.cpp @@ -6,6 +6,11 @@ #include <bench/bench.h> #include <crypto/chacha20.h> #include <crypto/chacha20poly1305.h> +#include <span.h> + +#include <cstddef> +#include <cstdint> +#include <vector> /* Number of bytes to process per iteration */ static const uint64_t BUFFER_SIZE_TINY = 64; diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index b81878006c..9558d64f19 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -3,15 +3,24 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <bench/data.h> - +#include <bench/data/block413567.raw.h> #include <chainparams.h> #include <common/args.h> #include <consensus/validation.h> +#include <primitives/block.h> +#include <primitives/transaction.h> +#include <serialize.h> +#include <span.h> #include <streams.h> #include <util/chaintype.h> #include <validation.h> +#include <cassert> +#include <cstddef> +#include <memory> +#include <optional> +#include <vector> + // These are the two major time-sinks which happen after we have fully received // a block off the wire, but before we can relay the block on to peers using // compact block relay. diff --git a/src/bench/checkblockindex.cpp b/src/bench/checkblockindex.cpp new file mode 100644 index 0000000000..a5c152b387 --- /dev/null +++ b/src/bench/checkblockindex.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2023-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 <bench/bench.h> +#include <test/util/setup_common.h> +#include <validation.h> + +#include <memory> + +static void CheckBlockIndex(benchmark::Bench& bench) +{ + auto testing_setup{MakeNoLogFileContext<TestChain100Setup>()}; + // Mine some more blocks + testing_setup->mineBlocks(1000); + bench.run([&] { + testing_setup->m_node.chainman->CheckBlockIndex(); + }); +} + + +BENCHMARK(CheckBlockIndex, benchmark::PriorityLevel::HIGH); diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp index c973fe9f71..d1454f3634 100644 --- a/src/bench/checkqueue.cpp +++ b/src/bench/checkqueue.cpp @@ -7,9 +7,11 @@ #include <common/system.h> #include <key.h> #include <prevector.h> -#include <pubkey.h> #include <random.h> +#include <cstddef> +#include <cstdint> +#include <utility> #include <vector> static const size_t BATCHES = 101; diff --git a/src/bench/cluster_linearize.cpp b/src/bench/cluster_linearize.cpp new file mode 100644 index 0000000000..7d011975dd --- /dev/null +++ b/src/bench/cluster_linearize.cpp @@ -0,0 +1,419 @@ +// 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 <cluster_linearize.h> +#include <test/util/cluster_linearize.h> +#include <util/bitset.h> +#include <util/strencodings.h> + +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <vector> + +using namespace cluster_linearize; +using namespace util::hex_literals; + +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.AddDependencies(SetType::Singleton(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.AddDependencies(SetType::Singleton(0), i); + } + return depgraph; +} + +// Construct a difficult graph. These need at least sqrt(2^(n-1)) iterations in the implemented +// algorithm (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.AddDependencies(SetType::Singleton(0), 1); + } else if (i == 2) { + depgraph.AddTransaction({6, 1}); + depgraph.AddDependencies(SetType::Singleton(2), 1); + } else if (i == 3) { + depgraph.AddTransaction({5, 1}); + depgraph.AddDependencies(SetType::Singleton(2), 3); + } else if ((i & 1) == 0) { + depgraph.AddTransaction({7, 1}); + depgraph.AddDependencies(SetType::Singleton(i - 1), i); + } else { + depgraph.AddTransaction({5, 1}); + depgraph.AddDependencies(SetType::Singleton(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.AddDependencies(SetType::Singleton(0), 1); + } else if (i == 2) { + depgraph.AddTransaction({1, 1}); + depgraph.AddDependencies(SetType::Singleton(0), 2); + } else if (i & 1) { + depgraph.AddTransaction({4, 1}); + depgraph.AddDependencies(SetType::Singleton(i - 1), i); + } else { + depgraph.AddTransaction({0, 1}); + depgraph.AddDependencies(SetType::Singleton(i), 3); + } + } + } + return depgraph; +} + +/** Benchmark that does search-based candidate finding with a specified number of iterations. + * + * Its goal is measuring how much time every additional search iteration in linearization costs, + * by running with a low and a high count, subtracting the results, and divided by the number + * iterations difference. + */ +template<typename SetType> +void BenchLinearizeWorstCase(ClusterIndex ntx, benchmark::Bench& bench, uint64_t iter_limit) +{ + const auto depgraph = MakeHardGraph<SetType>(ntx); + uint64_t rng_seed = 0; + bench.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 benchmarked per-iteration count (obtained by running BenchLinearizeWorstCase for a + * high and a low iteration count, subtracting them, and dividing by the difference in count), 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.AddDependencies(SetType::Singleton(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); + }); +} + +template<size_t N> +void BenchLinearizeOptimally(benchmark::Bench& bench, const std::array<uint8_t, N>& serialized) +{ + // Determine how many transactions the serialized cluster has. + ClusterIndex num_tx{0}; + { + SpanReader reader{serialized}; + DepGraph<BitSet<128>> depgraph; + reader >> Using<DepGraphFormatter>(depgraph); + num_tx = depgraph.TxCount(); + assert(num_tx < 128); + } + + SpanReader reader{serialized}; + auto runner_fn = [&]<typename SetType>() noexcept { + DepGraph<SetType> depgraph; + reader >> Using<DepGraphFormatter>(depgraph); + uint64_t rng_seed = 0; + bench.run([&] { + auto res = Linearize(depgraph, /*max_iterations=*/10000000, rng_seed++); + assert(res.second); + }); + }; + + if (num_tx <= 32) { + runner_fn.template operator()<BitSet<32>>(); + } else if (num_tx <= 64) { + runner_fn.template operator()<BitSet<64>>(); + } else if (num_tx <= 96) { + runner_fn.template operator()<BitSet<96>>(); + } else if (num_tx <= 128) { + runner_fn.template operator()<BitSet<128>>(); + } else { + assert(false); + } +} + +} // namespace + +static void Linearize16TxWorstCase20Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<16>>(16, bench, 20); } +static void Linearize16TxWorstCase120Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<16>>(16, bench, 120); } +static void Linearize32TxWorstCase5000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<32>>(32, bench, 5000); } +static void Linearize32TxWorstCase15000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<32>>(32, bench, 15000); } +static void Linearize48TxWorstCase5000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<48>>(48, bench, 5000); } +static void Linearize48TxWorstCase15000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<48>>(48, bench, 15000); } +static void Linearize64TxWorstCase5000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<64>>(64, bench, 5000); } +static void Linearize64TxWorstCase15000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<64>>(64, bench, 15000); } +static void Linearize75TxWorstCase5000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<75>>(75, bench, 5000); } +static void Linearize75TxWorstCase15000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<75>>(75, bench, 15000); } +static void Linearize99TxWorstCase5000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<99>>(99, bench, 5000); } +static void Linearize99TxWorstCase15000Iters(benchmark::Bench& bench) { BenchLinearizeWorstCase<BitSet<99>>(99, bench, 15000); } + +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); } + +// The following example clusters were constructed by replaying historical mempool activity, and +// selecting for ones that take many iterations (after the introduction of some but not all +// linearization algorithm optimizations). + +/* 2023-05-05T23:12:21Z 71, 521780, 543141,*/ +static constexpr auto BENCH_EXAMPLE_00 = "801081a5360092239efc6201810982ab58029b6b98c86803800eed7804800ecb7e058f2f878778068030d43407853e81902a08962a81d176098010b6620a8010b2280b8010da3a0c9f069da9580d800db11e0e9d719ad37a0f967897ed5210990e99fc0e11812c81982012804685823e0f0a893982b6040a10804682c146110a6e80db5c120a8010819806130a8079858f0c140a8054829a120c12803483a1760c116f81843c0d11718189000e11800d81ac2c0f11800d81e50e10117181c77c1111822e87f2601012815983d17211127180f2121212811584a21e1312800e80d1781412813c83e81815126f80ef5016126f80ff6c16126f80f66017126e80fd541812800d81942a1912800e80dd781a12800d81f96c1b12805282e7581b127180fd721c1271a918230b805fc11a220d8118a15a2d036f80e5002011817684d8241e346f80e1181c37805082fc04260024800d81f8621734803382b354270b12805182ca2e162f800e80d52e0d32803dc360201b850e818c400b318c49808a5a290210805181d65823142a800d81a34e0850800e81fb3c0851886994fc0a280b00082c805482d208032e28805e83ba380059801081cd4a0159811884f770002e0015e17280e49024300a0000000000000031803dcb48014200"_hex_u8; +/* 2023-12-06T09:30:01Z 81, 141675, 647053,*/ +static constexpr auto BENCH_EXAMPLE_01 = "b348f1fc4000f365818a9e2c01b44cf7ca0002b004f0b02003b33ef8ae3004b334f9e87005800d81c85e06b368fae26007b05ef2e14208be1a8093a50409b15cf5ee500a802c80a1420b802dea440c802ce50a0d802cdc320e802cd7220f802dd72210805380f74a118174f370126e96b32812127182c4701312817389d26414128035848c221512800e82bf3816126f81e4341712801082b228181280518af57418128040859a0019127182d0401a12803e858b641b127182c4421c126f82b3481d12811486b6301e12821d89e7281f126e8a8b421f127182d6642012806284c12021126e81d34822126e86a76222126e86d8102212805187b6542312800d82fc002412803d848e0e2512801082d27a26126e8589642612800e83a9602712800e83bd0028126e81ef1a29116e858d7228126f82db5e2912801083843c2a127181c93c2b126e85d0162b127181c5622c126e84f8262c12800f8392202d12800e82b66c2e126e81d0082f12803282d50430126e84f9003012805f84be6c3112846e88df0e2b12804080d44c340a8b31898808350a800ed760350b801083a1182b517182817e2a51800e82b6582951803583cb52420030806284cb6c204f7181d300204f82688ce0303e001d800e82bb200f488010808a182822a3289cd63041000a6fcd100a408a7caaa7024800002f803584e0741e27288f3386dd783b001000802683f27e004b8c44bcd0763f0000000000000000000100000e00"_hex_u8; +/* 2023-04-04T00:26:50Z 90, 99930, 529375,*/ +static constexpr auto BENCH_EXAMPLE_02 = "815b80b61e00800da63001cd378da70e028010991a03800e9d3e0480109708058010991a068010973a07da738fa72408de7491831009b35b88f0080a9d4485de180b71974e0c71974e0d80108e500eb27988a75a0f719632108061a56c11801087761280108a1413807893441480538c1415a606828806168010893e1780548c40188e4b80bb2c196eab3e1718805ed60e18188051c97a19188010cf781a1871b11e1b1871c5281c1880508080581d186e80b13c1e188035cf421f18805fe0482018804caa661f198035a9001f156e80cb701d1871a2281e1871ad281f18817380a16020186f98642118805ee04821198010b6702219800ea12623196eb67024198035808b0025196fa65c26198054ba1c2719807680bf7c28198053cd782919803d80b80429198051db5a2a198040d3742b19976584bb1c28196efc1c281971b21a29198052bc762a1971a2502b196eb73c2c19976381ab0c2a18806290543409862081c3423b00336fbc70224d80109e7c1c52805ebd5c1942800eb57016468034ba423405158118da28350416927480f4743000159f6a81c9462e00188051ec5e380e00800e9e420775800d9e26007c906c82f754251d0025870480f12c14280023800d9e26027e9e1385ed08102900001a804fac7a018001719856028001800da87e0180039b1a868b60064102246e9f42018005800da87e028005850d81d600026d862381a2200e0008230015831480a5480342000524803eeb32006e873582a4700a0100351300"_hex_u8; +/* 2023-05-08T15:51:59Z 87, 76869, 505222,*/ +static constexpr auto BENCH_EXAMPLE_03 = "c040b9e15a00b10eac842601805f85931802c104bae17403ae50aaa336049d76a9bf7005c55bbeab6606ae2aa9c72c07805e81992e08af7dab817a096e80a7e4520909803e92bd780a097185c76c0b096e98e7380b09850bb9953c0c09803389f6260d096f859d620e09803f88d3000f0971829c6e1009837690f6481109806285931811097181f56814076ea09b74120980408eb73213096f87853214096f86e2701509803f8c860016098a6fe6c3721709814f92a204180980628a8a441909803285df681a0980348498661b096e8290781c096e978e081c097187da1a1d097186c05c1e097185893c1f09805f8ad9002009800d84e74e21097183a67a22097182e23423097184b53a23096ea393062309840faddd46240980618eb732250980548bee6a2609807986883c2709718298402809815388b6582909805384ec742a097181b9142b096e97b5262b096e85e14e2c0980518abb5c2d09805489e75a2e09803187e3382f097180eb1c34046f87c34a2f098309a5c54430097186911831098054899c083209801083bc1033097081e02a3409805f848f0c35096e80d4343a057180c37040006f80a22438097180a0503f03816f8381444003803f80ef003f05800580a4283f066ef72845016efb91663e09923d808d8216470041803584837c46012f9247dc86684501268267a09610450222862184db68440712803585ea40440113835d97887805800b8723c7a40a4b00022f81529ae2143c0c1f80548b8f381b311980408e955c055e802589dc10037e801083b54602658010848130006700"_hex_u8; +/* 2023-05-01T19:32:10Z 35, 55747, 504128,*/ +static constexpr auto BENCH_EXAMPLE_04 = "801af95c00801af72801801af95c02873e85f2180202873e85f2180202873e85f21802028018fb2802068018fb2803068018fb2804068018fb2805068018fb2806068018fb2807068018fb2808068018fb2809068018fb280a068018fb280a058018fb280b058018fb280c058018fb280d058018fb280e058018fb280f058018fb2810058018fb2811058018fb2812058018fb2813058018fb2814058018fb2815058018fb2815048018fb2816048018fb2817048018fb2818048018fb2819048018fb281a048018fb281b04810d80d9481f00000100"_hex_u8; +/* 2023-02-27T17:06:38Z 60, 55680, 502749,*/ +static constexpr auto BENCH_EXAMPLE_05 = "b5108ab56600b26d89f85601b07383b01602b22683c96003b34a83d82e04b12f83b53a05b20e83c75a066e80840a06068040be0007066fb10608066fb2120906800eba320a06842b80b05a0a066eff420b067199300b068124c3140c0680618085180d066faa1c0e068010b4440f068051af541006800da1781106857881946812066eee1613068052b31014068324808d361506806180885c150671b03216066ef11017068052b63218066ef3521806803f80865419066e93441a068035a13e1b0680628085181c06806ec4481d068117e72c1e06719c721f068077c42420068159808d1821066eef0c21058010b90022056f9908230571993024058010b00a25058010b00a260580608087402705803fc10027068032b42828068051b6322906800db11e212a8324808d361933803ff400192f826381a7141a2f8032ac08152a800db54c044e8323808d3630010002018158d84000042d821cea12002807853580d462002d01891181d022002e00"_hex_u8; +/* 2023-04-20T22:25:49Z 99, 49100, 578622,*/ +static constexpr auto BENCH_EXAMPLE_06 = "bf3c87c14c008010955a01b21d85e07002800d946c036e8e3404b77f86c26605b33c85f55e06bd06879852078010970a08bd4b87cf00098123a7720ab2158687680b8054d4440b0a8062fa4c0c0a71ac400d0a80628081540e0a8010a2580f0a8054b676100a8032b85c110a6e9a40120a6e809012130a817f80c31e140a8175808674150a719d46160a8172d86415098033c1481609800da4181709800ada2e1809803dc85219098034b4041a096ef5501b098052d67c1c098051d3281d09800ebc4a1e098175808c641f098061c55020098078c85021096e8081141f0b6faf1e200b8061da68210b8062f000220b800ebc20230b8035d058240b8053de32250b8050b610250b6fad32260b803dc276270b803d80a610280b6ef812290b8052b6322a0b800eb57e2b0b8052bd062c0b719e522d0b71a3762e0b8010bb1e2f0b80109a78310a80109962320a8051a60c330a6f9f3e320b6e808b24330b719e40340b8117cc50350b803d80971a360b8051b930370b6f9e0a380b719b10390b8052a6003a0b6e808c76390a7195603a0a6f935c3b0a8054a31a3c0a803ce30c3b0b803fa3003c0b800dbe2a3d0b8f3480a84244058005851a44069d1bf824400b83098f284507719c723d4f6f9c1c3449719c722f4f6eb23c304f8061c5502e528061da682b4e8118bb724e022a8054b35028476e941c1d51815be02c4f01148557808e3a4f070e8104af464e001180329d364e010d805f9f6a421b9c3387aa744c0d4d71ac400b800881748098444710338173809b780b80008054d444292c12821dc040550403078b4682b4664517003f00"_hex_u8; +/* 2023-06-05T19:56:12Z 52, 44896, 540514,*/ +static constexpr auto BENCH_EXAMPLE_07 = "b317998a4000b40098d53e01b45b99814802b7289b940003b3699a9d1204b6619a807a05814682cb78050571d854060571d8540705800e808d7a0805803480c06a09056e8189280a056ffd060b05800d80ea7a0c05803c80b80c0c03803e80d86e0d036ed2280e03811581804a0f036fd34e1003805380eb6811036e81f60e12038010ec101204805f80e83a13048033809534140471e00a15048010f95816046e81fa301704805180a74c1705800d808f1018056fd55c1905800e8091481a056e80a76e1b05805f80e2741c0571809b021c05826382c8401d0571df201e05800e809d2c1f05850083e87c1f05811580af68200571f20a21056ff9042205803e80df1e23056e81956c24056e9f542604805180e83829000e800e8080621325803380b0402a020d6ef8100e2c8c4889a96a2c000f803580ce4c2c000b6e9f54062a803480c96406260500"_hex_u8; +/* 2023-12-05T23:48:44Z 69, 44283, 586734,*/ +static constexpr auto BENCH_EXAMPLE_08 = "83728ce80000b90befca1001806083b24002b40de6da3203b545e9c35c04b34beede3005b068e8883006d41c80b1e14c07b337e7841208b26beadb2e096e83892e090980518487380a096e82815c0a096e81ce3c0b097181db200c097181d4020d09810084ed600e096e96b0100f0971819a0210086e93da2e0f09803583ee5e1009803583c66c1109800d82bb6e1209800d81d56a1309803c82e622140971819f521509803d84a55c15057181d6161605806283ac5217056e949c5a18056e89e8641806815889e23419067181de321a066e8af2641a076e82a70a1b07803583f2081c076f81e76e1d076e81d33e1e07800d83b8761e086e82a5541f087181de302008805f84ad0021086e81c74022086e81bd3e23086e9288182408806184b3102409803283816025096e91ed662609830a88e70827096e81d14a27097181ce6028096e8cf03829097181883832016f81835c3103806181e0103203804180b8103204863584fe183304800de66434046e9e4c34056e81d6742f429213c0eb602e3d6483b06c283a6e81d73c263d6e82f9581831805485ab360e37805080c62609398b3189880838010603916db1f3583a03000110873199f8623c000000011100"_hex_u8; +/* 2023-04-14T19:36:52Z 77, 20418, 501117,*/ +static constexpr auto BENCH_EXAMPLE_09 = "bf2989d00400815bca5c01af1e86f97602800d9d6c03800d8a3404b47988866e05b36287f92e0680109f68078010991a08805ecf1208076e80933e09078062d01c0a078054b6760b078053b6760c076f9c1c0d078054b6760e0771af260f0771b17e10078032f57011078035d56812078054e1581307886b83dc301407817480d13013068005a6001406803d80821a15066ef3201606800ea2181706800da628180671ab1219068054db0c1a06719b001b06815b80a11c1c068050b9301d066fac2a1e068033ab481f06719b1020068035ab721e07803dc2761f0771ae3c20078040f60e210771ce282207800ea4322307882a81a66024078035ad4625076efe7e26078162808e1827078118bb7228076eac7428088010bf58290871a04c2a0871bc722b086fa8382c08803d80a0142d088035d6282e088051c30c2f086efc623008800d9f6231086f986432088117bb7237028010a63034068010c84e2740800ea64c2237832c80933e1f3b830880c454390208813c80955c3905068032c73611348010a03c093c837a808a101b278050ac34093a8051ac34291b8f3b8187401d28881a82cb3a3a0a37977b86d20843000028996686a7083f030f8078d3761b27106e995a08499070839b5a1131000b00"_hex_u8; +/* 2023-11-07T17:59:35Z 48, 4792, 498995,*/ +static constexpr auto BENCH_EXAMPLE_10 = "875f89aa1000b51ec09d7201c55cc7a72e02a11aa1fb3203b233a7f95204800ef56205b33ea9d13006803e80b26e07d90ec9dd4008b45eabbe6c09806080ca000a815984e8680a0a6f80925e0a0a803f80e1660c09937c94b7420d086e82f5640a086e80997e0b086f808d320c08800580a5640d086f8089100e08804080c9060f088115819a1c10086e82961a0f0a805f81bc0a100a6ff826110a6ef53e120a807584c60c110a6e818f32120a803c81c246130a805481d508140a8159838410150a7180a55c160a6f80821c170a6fe6101c066fe6101d06805080f854190a6e81b27c1a0a8155819c701e06805180ae0c21046e8b9a222501805180f53422001680f26880f8a62a220116803580da582007058153838e6e21000c800d80a712033a807681ae1c23000308834a82d36023020205815981e03a051a08001700"_hex_u8; +/* 2023-11-16T10:47:08Z 77, 473962, 486863,*/ +static constexpr auto BENCH_EXAMPLE_11 = "801980c06000801980c06001801980c06002801980c06003801980c06004801980c06005801980c06006801980c06007801980c06008801980c06009801980c0600a801980c0600b801980c0600c801980c0600d801980c0600e801980c0600f801980c060108019d12c11800f80b1601111800f80b1601111801080b1601111800f80b160100e800f80b160100f801980c060110f800f80b160140d801180b1601111801180b160100d801180b160120c801180b1600f10801180b1600f11801980c0601011800f80b160140e800f80b160110f801980c060170a801180b1601210801980c060140f800f80b1601311801980c0602005801180b1601f07800f80b1601b0c800fca7c1611812081f9601638812081f9601637812081fb001636801080b160142f801980c0600e2a801080b1600f2a801180b1600d25801980c0600e25800f80b1600d27801980c0600e27801980c0600d27801180b1600e26812080b1500c27812081f960201025812081f960200f27812081fc201d101c812081fc201d101d812081fc201d0f1f812081fc201d0f20812081f9601b1016800f80b1600a35800f80b1600a36800f80b1600e32801080b160122f812081f960280040812081fc20121d1b812081f960112713812081f960160d37812081fc20140d2b812081f960130d2d812081fc20130c2c812081fb001b0157812081fb001a0245812081fc20140030812081fc20092747812081fb000b152500"_hex_u8; +/* 2023-10-06T20:44:09Z 40, 341438, 341438,*/ +static constexpr auto BENCH_EXAMPLE_12 = "80318f4c0080318f4c0180318f4c0280318f4c0380318f4c0480318f4c0580318f4c0680318f4c078033a57807078033a57807078033a57807078033a57807078033a57807078033a57807078033a57807078033a578070780318f4c0e0180318f4c0d0380318f4c0c0580318f4c0b078033a57803128033a57803128033a57803128033a578031280318f4c0412810b9c28140300810c9c281303028033a57802188033a57802188033a5780218810c9c280b01108033a578001c810c9c2807050f8033a578001b810c98040700158033a578001c810c98040301158033a5780019806ca1240101118033a578001300"_hex_u8; +/* 2023-11-15T21:40:46Z 96, 23608, 138286,*/ +static constexpr auto BENCH_EXAMPLE_13 = "8060829f4000b157bab07a01b27cc2b16802b22fbce54603826480a95804803da81a05bc7bcac93806800de55207800daf0608805bc71809805bc7180a800d9d4a0b805bbc700c8152d7180d805bb9380e850a8886260f800d80d33410bf38d3d55011b41dc4eb6012bd70d2ce2e138d3596af7812137180cd501313805e81f7281413718092001513803d81f90016136e8b916c1713801081861a17106e80cd2a18106f80cc3c19106e80cf161911800d80fe781b107180d87c1c106e80fb081d10803e8286701d11800d81c4781f10804082a6002010801081912e21107180ff0021116e81da4a2310850b8b864023116e89db3224116e84ff7e2610897c95993427106f80bb1a240b803581c272250b8032828c10260b6e80d42a270b804082b35a280b800d80fe3e290b805cc0282312821d8697022b0b6e8add562c0b805281c8063007811883f1082313800d80fe3e24137180c9142513800d8380102613803382c00e2713805eb32228136e8494542913800e8186742913806082b74c2a1380528285782b13800d818f7a2c136e84a5562d1380508286702e136f80a46e3e04803f8191364102805481ad4c3d076e809a5a3e077180fe4032136e838b7233138c4790cf384106853584ab624206805b80932a4801806280966c48028168ef04400b7181bd524903806282db5c375b9316acbf703a599c68c5a454385c6e81d63e364a6f80ff64334e817485a6784f023171819536234e800d81826e1e498053829a12420018834c87cb14291d2e840e8bc94c1d2825800d81b7220368811783fe0e271f1f811783e758380f001ecd55809edf6e56000000003a815984ba76008010d54d80aebb4e2c22000000000000002c807682f150007a00"_hex_u8; +/* 2023-12-06T09:18:20Z 93, 68130, 122830,*/ +static constexpr auto BENCH_EXAMPLE_14 = "b26beadb2e00800d80ca0a01d41c80b1e14c02b068e8883003800d81af1604b34beede30056e80b14006b151f5d46c07b93e8085b02608b30cf98b1009b14ef6b3040ab176f6ab480bb7078082b8640c800d81c6460d802c80a8080e802c80a8080f802c80a14210802ce50a11802cd722127181ce6012126e81d14a13126e9b8b00141282428dd42c15128051828408150e6e81bd3e150f805f84ad00160f7181de30170f6e81c740180f800d83b876190f6e82a5541a0f6e81d33e1a106e82a70a1b106f81e76e1c10803583f2081d106e82d9401e106e96e4441f107181de321e12815889e2341f127182d60c20126e979d4e21126e8282262410800d82972c25106f838a5822126f82842a23127182d24a2412803e84bc2a2512800d83c81a26126e84f8142712805085a22c27126e889e6a2812801083aa50281280348598102912801082d5522a126e85865c2b127182c7602b1282468c82042c126e84972c2d12805485d93a2d12801083c7322e12815386e1582f126e84fb0c30126f82eb6c3011813a85b47a3111803f869f5c3211805181ed30370d6e84bf0a3411804180e1383809815883aa183a08815a8392203e05807681f140380c6e9e4c4005805485ab363255805183856030406e82f9582c45805185c1001b4f82418df1001a4e803283c50e430026800d83a6201a4b836886be3044010b8b318988084c0101803183a6120776800d828a1e087682338ae050301c33873199f8624d010032813986bc663c1034800d83a5220a6f800d82be52048000805183e364084907800d83cc4a018005815987b41e1832000017884b9dce72035035803284c11e00800885769d9538192f0000000002001000"_hex_u8; +/* 2023-12-14T02:02:29Z 55, 247754, 247754,*/ +static constexpr auto BENCH_EXAMPLE_15 = "801980c06000801980c06001801980c06002801980c06003801980c06004801980c06005801980c06006801980c06007801980c06008801980c06009801980c0600a801980c0600b801980c0600c801980c0600d801980c0600e801180b1600e0e801180b1600e0e801180b1600e0e801180b1600e0e801180b1600e0e801180b1600e0e801180b1600d07801180b1600f06801180b1600c0a801180b1600f08801180b1600c0c801180b1600c0d801180b1600c0e801180b160100b801180b1601309812081fc200e2a812081fc200e29812081fc200e28812081fc200e0e18812081fc200e0e17801980c060042e812081fc200e0d07812081fc200e0d08812081fc200e0c0a812081fc200e0d0a801980c060081e812081fc200f0c0c812081fc200f0c0d812081fc200f0c0e801180b160083a801180b1600426801980c0600b20801980c0600a22812081fc200f0b30801180b160022b801180b160022b812081fc20062422812081fc2006220b812081fc200c0a1e812081fc2012041a00"_hex_u8; +/* 2023-12-14T15:17:20Z 76, 102600, 103935,*/ +static constexpr auto BENCH_EXAMPLE_16 = "801980c06000801980c06001801980c06002801980c06003801980c06004801180b1600404801180b1600404801180b1600404801980c0600504801980c0600802801980c0600803801180b1600704801980c0600804801280b1600804812081fc200810812081fc20080f812081fc20080e801180b160080c800f80b160080d801980c060090d801180b160090e801980c0600a0e812181fc200a0c801180b1600a0d812181fd400a0c801980c0600a1c801980c0600916801180b1600719801180b160061b801980c0600d15801980c0600717812081fc200718801980c0600716801180b160072d801180b1600722801180b1600525801980c060091b801980c060071e801080b160071f801280b160061d812081fc20063a812181f960160815801280b1600525801980c0600625801180b1600626801980c0600726801980c0600536801180b160032b801980c060042b801280b160032d801980c060033e801180b160043e812181fc20100c27801080b160042f801980c0600342801180b1600442812081fc20150d25800f80b1600245812081fd40120619812081fc20040243812081fc20120c2c812081fd40120a1d812181fb00100623812081fc20030347812081fc20072126801980c0600236812081fc20040d2b812081fc20120328801980c0600237801180b1600337812081fc20052230801180b1600239812081fc2008242c812081fd4005112d812081fb00070b32812081f96011034700"_hex_u8; +/* 2023-12-15T07:12:29Z 98, 112693, 112730,*/ +static constexpr auto BENCH_EXAMPLE_17 = "801980c06000801980c06001801980c06002801980c06003801980c06004801980c06005801980c06006801180b1600606801180b1600606801180b1600606801180b1600606801280b1600606801180b1600606801180b1600606801980c0600d00801980c0600b03801980c0600b04801980c0600f01812081fc200a16812081fc200a15812081fc200a14812081fc200a13812081fd400a12812181fc200a11812181fc200a0f801180b1600a10801180b1600a10801980c0600a10801180b1600b10801180b1600b10801980c0600621801980c0600915801980c060041b801180b160051b801980c0600f12801980c0600f13801980c0600d15801980c0600c17801980c060072e800f80b160082e812181fc200d150e801980c0600922801180b1600923801980c0600823801180b1600623801180b1600a20801180b1600e1c801180b1600b20801180b1600b21801980c0600a3e800f80b1600b3e801980c0600931801180b1600a31812181fc20140325801180b1600a30801180b160054c801180b160043b801980c0600336812181fc200253812081f960090944812081fc2007003c801980c0600339801180b1600433801980c0600453801980c0600340801980c060033d801080b160043d812081f960070854801980c060045a801180b160055a801180b1600545801980c0600643801980c0600641801280b1600739801180b1600562812081fc20121f27812181fc20210137812181fc2016112f801980c0600259801980c0600156812181fc20053a31801180b160025c801180b1600257801980c0600357812081fc200d2d1e812181fc20102444812181fc20035a801180b160035b801980c0600751812181fc2007392a812181fc20025f801980c060045e801180b1600350812081fc20070f6f801180b1600263812181fc201b1322812181fc2011283b812081fc2002442100"_hex_u8; +/* 2023-12-16T02:25:33Z 99, 112399, 112399,*/ +static constexpr auto BENCH_EXAMPLE_18 = "801980c06000801980c06001801980c06002801980c06003801980c06004801980c06005801980c06006801980c06007801180b16008801180b16009801180b1600a801180b1600a0a801180b1600a0a801180b1600a0a801180b1600a0a801980c0600d06801180b1600b09801980c0601005801180b1600c0a801980c0600d0a801980c0601106801180b1600e0a801980c0601207801980c0601207801180b160100a812081e668100a812081e668100a812081e668100a801980c0601407801980c0601606812081fc201226812081fc201225812081fc201224812081fc201223801180b1600e21801980c0600b1e801180b1600c1e801180b1601316801980c060091b801980c0601312801980c0600a1c801180b160190e801180b1601315801180b1600e1b801180b1601713801180b1600f1c801980c0600d34801980c0600d30801980c060102e801980c060122d801980c0600b2a801980c0600b2a801980c0600b2b801180b1601122801180b1600e26801180b1601025801180b1600f26812081fc20280032812081fc20270034812081fc20250034801180b1600d4b801980c0600d457a809a000d46801980c0601044801980c0600e46801180b1600f43801180b160123f801180b160123e801180b1601130801180b1601131801180b1601131812081fc20230a36801980c0600a5a801180b1600a5b801980c0600a5b801180b1600b5b801980c0600b5a801180b1600f57801180b1600d3f801980c0600669801980c0600568801980c0600466801180b1600945801180b1600649801180b1600945812081fc2018234b812081fc20142534812081fc20142532812081fc20142530801180b160074d801180b1600a4b801180b1600a4a812081fc20221662812081fc200c0472812081fc20072e42812081fc20062c23812081fc20100572812081fc200f036c812081fc2001345100"_hex_u8; +/* 2023-03-31T19:24:02Z 78, 90393, 152832,*/ +static constexpr auto BENCH_EXAMPLE_19 = "800dd042008028b13c018028b13c028028b13c038029b13c048029b13c058029b13c0680299948078029b13c088029b13c09802899480a802899480b8028b13c0c80299e700d802899480e802999480f8029b13c10802999481180299948128028b13c138029b13c1480289e701580289948168028b13c1780289948188028994819802899481a802999481b802999481c802899481d802999481e8028b13c1f8029b13c20802999482180299948228028b13c2380298c242480289948258029b13c2680288c242780298c242880299e70298f5a80ea762a824780aa00292a82038090402429813fcf00152a8203809040142a813ff700112982038090402d002d813ff70028002c8203809040270024824780aa00270025820380904025002882038090401e022a82038090401d042782038090401c01298203809040190029813ff700170028813ff700140128807b9258120128841280f6402c01002e82038090402b00062b820380904027000031813ff70011192d82038090401d000129851981a9403a0000003b82038090400c182e813ff7000b0f2982038090401314141b807b925805192b84568190001121000334807bdd400149824780aa00001f2a813ff700003d0b8203809040050d1915807bdd4001498728828f400b010004050501000a050c851981a9400104050b061a0400"_hex_u8; + +static void LinearizeOptimallyExample00(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_00); } +static void LinearizeOptimallyExample01(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_01); } +static void LinearizeOptimallyExample02(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_02); } +static void LinearizeOptimallyExample03(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_03); } +static void LinearizeOptimallyExample04(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_04); } +static void LinearizeOptimallyExample05(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_05); } +static void LinearizeOptimallyExample06(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_06); } +static void LinearizeOptimallyExample07(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_07); } +static void LinearizeOptimallyExample08(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_08); } +static void LinearizeOptimallyExample09(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_09); } +static void LinearizeOptimallyExample10(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_10); } +static void LinearizeOptimallyExample11(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_11); } +static void LinearizeOptimallyExample12(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_12); } +static void LinearizeOptimallyExample13(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_13); } +static void LinearizeOptimallyExample14(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_14); } +static void LinearizeOptimallyExample15(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_15); } +static void LinearizeOptimallyExample16(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_16); } +static void LinearizeOptimallyExample17(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_17); } +static void LinearizeOptimallyExample18(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_18); } +static void LinearizeOptimallyExample19(benchmark::Bench& bench) { BenchLinearizeOptimally(bench, BENCH_EXAMPLE_19); } + +BENCHMARK(Linearize16TxWorstCase20Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize16TxWorstCase120Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize32TxWorstCase5000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize32TxWorstCase15000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize48TxWorstCase5000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize48TxWorstCase15000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize64TxWorstCase5000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize64TxWorstCase15000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize75TxWorstCase5000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize75TxWorstCase15000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize99TxWorstCase5000Iters, benchmark::PriorityLevel::HIGH); +BENCHMARK(Linearize99TxWorstCase15000Iters, 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); + +BENCHMARK(LinearizeOptimallyExample00, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample01, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample02, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample03, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample04, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample05, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample06, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample07, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample08, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample09, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample10, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample11, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample12, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample13, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample14, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample15, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample16, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample17, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample18, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeOptimallyExample19, benchmark::PriorityLevel::HIGH); diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 171c61c46f..a752f73610 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -3,15 +3,28 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> +#include <consensus/amount.h> #include <interfaces/chain.h> #include <node/context.h> +#include <outputtype.h> +#include <policy/feerate.h> #include <policy/policy.h> +#include <primitives/transaction.h> +#include <random.h> +#include <sync.h> +#include <util/result.h> #include <wallet/coinselection.h> #include <wallet/spend.h> -#include <wallet/wallet.h> #include <wallet/test/util.h> +#include <wallet/transaction.h> +#include <wallet/wallet.h> +#include <cassert> +#include <map> +#include <memory> #include <set> +#include <utility> +#include <vector> using node::NodeContext; using wallet::AttemptSelection; diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index 1685a120b4..65da942ad7 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -11,11 +11,14 @@ #include <crypto/sha3.h> #include <crypto/sha512.h> #include <crypto/siphash.h> -#include <hash.h> #include <random.h> +#include <span.h> #include <tinyformat.h> #include <uint256.h> +#include <cstdint> +#include <vector> + /* Number of bytes to hash per iteration */ static const uint64_t BUFFER_SIZE = 1000*1000; @@ -196,22 +199,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 +261,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/data.cpp b/src/bench/data.cpp deleted file mode 100644 index 35558b3aa7..0000000000 --- a/src/bench/data.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <bench/data.h> - -namespace benchmark { -namespace data { - -#include <bench/data/block413567.raw.h> -const std::vector<uint8_t> block413567{std::begin(block413567_raw), std::end(block413567_raw)}; - -} // namespace data -} // namespace benchmark diff --git a/src/bench/data.h b/src/bench/data.h deleted file mode 100644 index 5f13d766ea..0000000000 --- a/src/bench/data.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2019 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_BENCH_DATA_H -#define BITCOIN_BENCH_DATA_H - -#include <cstdint> -#include <vector> - -namespace benchmark { -namespace data { - -extern const std::vector<uint8_t> block413567; - -} // namespace data -} // namespace benchmark - -#endif // BITCOIN_BENCH_DATA_H diff --git a/src/bench/descriptors.cpp b/src/bench/descriptors.cpp index 5d6bcb8ce8..c45456645b 100644 --- a/src/bench/descriptors.cpp +++ b/src/bench/descriptors.cpp @@ -4,11 +4,16 @@ #include <bench/bench.h> #include <key.h> -#include <pubkey.h> #include <script/descriptor.h> +#include <script/script.h> +#include <script/signingprovider.h> +#include <cassert> +#include <cstdint> +#include <memory> #include <string> #include <utility> +#include <vector> static void ExpandDescriptor(benchmark::Bench& bench) { @@ -18,12 +23,12 @@ static void ExpandDescriptor(benchmark::Bench& bench) const std::pair<int64_t, int64_t> range = {0, 1000}; FlatSigningProvider provider; std::string error; - auto desc = Parse(desc_str, provider, error); + auto descs = Parse(desc_str, provider, error); bench.run([&] { for (int i = range.first; i <= range.second; ++i) { std::vector<CScript> scripts; - bool success = desc->Expand(i, provider, scripts, provider); + bool success = descs[0]->Expand(i, provider, scripts, provider); assert(success); } }); diff --git a/src/bench/disconnected_transactions.cpp b/src/bench/disconnected_transactions.cpp index f48175d472..7c3c34bbbc 100644 --- a/src/bench/disconnected_transactions.cpp +++ b/src/bench/disconnected_transactions.cpp @@ -5,9 +5,18 @@ #include <bench/bench.h> #include <kernel/disconnected_transactions.h> #include <primitives/block.h> -#include <test/util/random.h> +#include <primitives/transaction.h> +#include <script/script.h> #include <test/util/setup_common.h> +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iterator> +#include <memory> +#include <vector> + constexpr size_t BLOCK_VTX_COUNT{4000}; constexpr size_t BLOCK_VTX_COUNT_10PERCENT{400}; diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index b56054ae89..9f22fa3646 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -3,15 +3,28 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> +#include <chain.h> #include <chainparams.h> +#include <consensus/consensus.h> #include <consensus/merkle.h> #include <consensus/validation.h> #include <pow.h> +#include <primitives/block.h> +#include <primitives/transaction.h> #include <random.h> +#include <script/script.h> +#include <sync.h> #include <test/util/setup_common.h> -#include <txmempool.h> +#include <uint256.h> #include <validation.h> +#include <cassert> +#include <cstdint> +#include <memory> +#include <string> +#include <utility> +#include <vector> + static void DuplicateInputs(benchmark::Bench& bench) { diff --git a/src/bench/ellswift.cpp b/src/bench/ellswift.cpp index 4780db8e1c..4dfef0e9c5 100644 --- a/src/bench/ellswift.cpp +++ b/src/bench/ellswift.cpp @@ -3,9 +3,14 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> - #include <key.h> +#include <pubkey.h> #include <random.h> +#include <span.h> +#include <uint256.h> + +#include <algorithm> +#include <cassert> static void EllSwiftCreate(benchmark::Bench& bench) { diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp index 0af4ee98fe..e6cc3d4d54 100644 --- a/src/bench/gcs_filter.cpp +++ b/src/bench/gcs_filter.cpp @@ -4,6 +4,11 @@ #include <bench/bench.h> #include <blockfilter.h> +#include <uint256.h> + +#include <cstdint> +#include <utility> +#include <vector> static GCSFilter::ElementSet GenerateGCSTestElements() { diff --git a/src/bench/hashpadding.cpp b/src/bench/hashpadding.cpp index e9d2c25fe3..cca5c07506 100644 --- a/src/bench/hashpadding.cpp +++ b/src/bench/hashpadding.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <hash.h> +#include <crypto/sha256.h> #include <random.h> #include <uint256.h> diff --git a/src/bench/index_blockfilter.cpp b/src/bench/index_blockfilter.cpp index 5e0bfbfea6..eac09688c8 100644 --- a/src/bench/index_blockfilter.cpp +++ b/src/bench/index_blockfilter.cpp @@ -2,14 +2,30 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php. -#include <bench/bench.h> - #include <addresstype.h> +#include <bench/bench.h> +#include <blockfilter.h> +#include <chain.h> +#include <index/base.h> #include <index/blockfilterindex.h> -#include <node/chainstate.h> -#include <node/context.h> +#include <interfaces/chain.h> +#include <primitives/block.h> +#include <primitives/transaction.h> +#include <pubkey.h> +#include <script/script.h> +#include <span.h> +#include <sync.h> #include <test/util/setup_common.h> +#include <uint256.h> #include <util/strencodings.h> +#include <util/time.h> +#include <validation.h> + +#include <cassert> +#include <memory> +#include <vector> + +using namespace util::hex_literals; // Very simple block filter index sync benchmark, only using coinbase outputs. static void BlockFilterIndexSync(benchmark::Bench& bench) @@ -18,7 +34,7 @@ static void BlockFilterIndexSync(benchmark::Bench& bench) // Create more blocks int CHAIN_SIZE = 600; - CPubKey pubkey{ParseHex("02ed26169896db86ced4cbb7b3ecef9859b5952825adbeab998fb5b307e54949c9")}; + CPubKey pubkey{"02ed26169896db86ced4cbb7b3ecef9859b5952825adbeab998fb5b307e54949c9"_hex_u8}; CScript script = GetScriptForDestination(WitnessV0KeyHash(pubkey)); std::vector<CMutableTransaction> noTxns; for (int i = 0; i < CHAIN_SIZE - 100; i++) { diff --git a/src/bench/load_external.cpp b/src/bench/load_external.cpp index fba1233901..8f9399c60d 100644 --- a/src/bench/load_external.cpp +++ b/src/bench/load_external.cpp @@ -3,13 +3,24 @@ // file COPYING or https://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <bench/data.h> +#include <bench/data/block413567.raw.h> #include <chainparams.h> -#include <clientversion.h> +#include <flatfile.h> +#include <node/blockstorage.h> +#include <span.h> +#include <streams.h> #include <test/util/setup_common.h> -#include <util/chaintype.h> +#include <uint256.h> +#include <util/fs.h> #include <validation.h> +#include <cstdint> +#include <cstdio> +#include <map> +#include <memory> +#include <stdexcept> +#include <vector> + /** * The LoadExternalBlockFile() function is used during -reindex and -loadblock. * diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp index 6851ed0bd8..5f39ddc41b 100644 --- a/src/bench/lockedpool.cpp +++ b/src/bench/lockedpool.cpp @@ -3,9 +3,10 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> - #include <support/lockedpool.h> +#include <cstddef> +#include <cstdint> #include <vector> #define ASIZE 2048 diff --git a/src/bench/logging.cpp b/src/bench/logging.cpp index c97c4e151b..3bf2b7edb2 100644 --- a/src/bench/logging.cpp +++ b/src/bench/logging.cpp @@ -5,11 +5,13 @@ #include <bench/bench.h> #include <logging.h> #include <test/util/setup_common.h> -#include <util/chaintype.h> + +#include <functional> +#include <vector> // All but 2 of the benchmarks should have roughly similar performance: // -// LogPrintWithoutCategory should be ~3 orders of magnitude faster, as nothing is logged. +// LogWithoutDebug should be ~3 orders of magnitude faster, as nothing is logged. // // LogWithoutWriteToFile should be ~2 orders of magnitude faster, as it avoids disk writes. @@ -20,73 +22,43 @@ 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(); }); } -static void LogPrintLevelWithThreadNames(benchmark::Bench& bench) -{ - Logging(bench, {"-logthreadnames=1", "-debug=net"}, [] { - LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", "test"); }); -} - -static void LogPrintLevelWithoutThreadNames(benchmark::Bench& bench) +static void LogWithDebug(benchmark::Bench& bench) { - Logging(bench, {"-logthreadnames=0", "-debug=net"}, [] { - LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", "test"); }); + Logging(bench, {"-logthreadnames=0", "-debug=net"}, [] { LogDebug(BCLog::NET, "%s\n", "test"); }); } -static void LogPrintWithCategory(benchmark::Bench& bench) +static void LogWithoutDebug(benchmark::Bench& bench) { - Logging(bench, {"-logthreadnames=0", "-debug=net"}, [] { LogPrint(BCLog::NET, "%s\n", "test"); }); -} - -static void LogPrintWithoutCategory(benchmark::Bench& bench) -{ - Logging(bench, {"-logthreadnames=0", "-debug=0"}, [] { LogPrint(BCLog::NET, "%s\n", "test"); }); -} - -static void LogPrintfCategoryWithThreadNames(benchmark::Bench& bench) -{ - Logging(bench, {"-logthreadnames=1", "-debug=net"}, [] { - LogPrintfCategory(BCLog::NET, "%s\n", "test"); - }); -} - -static void LogPrintfCategoryWithoutThreadNames(benchmark::Bench& bench) -{ - Logging(bench, {"-logthreadnames=0", "-debug=net"}, [] { - LogPrintfCategory(BCLog::NET, "%s\n", "test"); - }); + Logging(bench, {"-logthreadnames=0", "-debug=0"}, [] { LogDebug(BCLog::NET, "%s\n", "test"); }); } -static void LogPrintfWithThreadNames(benchmark::Bench& bench) +static void LogWithThreadNames(benchmark::Bench& bench) { - Logging(bench, {"-logthreadnames=1"}, [] { LogPrintf("%s\n", "test"); }); + Logging(bench, {"-logthreadnames=1"}, [] { LogInfo("%s\n", "test"); }); } -static void LogPrintfWithoutThreadNames(benchmark::Bench& bench) +static void LogWithoutThreadNames(benchmark::Bench& bench) { - Logging(bench, {"-logthreadnames=0"}, [] { LogPrintf("%s\n", "test"); }); + Logging(bench, {"-logthreadnames=0"}, [] { LogInfo("%s\n", "test"); }); } static void LogWithoutWriteToFile(benchmark::Bench& bench) { // Disable writing the log to a file, as used for unit tests and fuzzing in `MakeNoLogFileContext`. Logging(bench, {"-nodebuglogfile", "-debug=1"}, [] { - LogPrintf("%s\n", "test"); - LogPrint(BCLog::NET, "%s\n", "test"); + LogInfo("%s\n", "test"); + LogDebug(BCLog::NET, "%s\n", "test"); }); } -BENCHMARK(LogPrintLevelWithThreadNames, benchmark::PriorityLevel::HIGH); -BENCHMARK(LogPrintLevelWithoutThreadNames, benchmark::PriorityLevel::HIGH); -BENCHMARK(LogPrintWithCategory, benchmark::PriorityLevel::HIGH); -BENCHMARK(LogPrintWithoutCategory, benchmark::PriorityLevel::HIGH); -BENCHMARK(LogPrintfCategoryWithThreadNames, benchmark::PriorityLevel::HIGH); -BENCHMARK(LogPrintfCategoryWithoutThreadNames, benchmark::PriorityLevel::HIGH); -BENCHMARK(LogPrintfWithThreadNames, benchmark::PriorityLevel::HIGH); -BENCHMARK(LogPrintfWithoutThreadNames, benchmark::PriorityLevel::HIGH); +BENCHMARK(LogWithDebug, benchmark::PriorityLevel::HIGH); +BENCHMARK(LogWithoutDebug, benchmark::PriorityLevel::HIGH); +BENCHMARK(LogWithThreadNames, benchmark::PriorityLevel::HIGH); +BENCHMARK(LogWithoutThreadNames, benchmark::PriorityLevel::HIGH); BENCHMARK(LogWithoutWriteToFile, benchmark::PriorityLevel::HIGH); diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index 1a9b013277..84f873d183 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -3,10 +3,19 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <kernel/mempool_entry.h> +#include <consensus/amount.h> +#include <kernel/cs_main.h> #include <policy/policy.h> +#include <primitives/transaction.h> +#include <script/script.h> +#include <sync.h> #include <test/util/setup_common.h> #include <txmempool.h> +#include <util/check.h> + +#include <cstdint> +#include <memory> +#include <vector> static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index fe3e204fb3..67f689e4ea 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -3,16 +3,23 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <kernel/mempool_entry.h> +#include <consensus/amount.h> #include <policy/policy.h> +#include <primitives/transaction.h> #include <random.h> +#include <script/script.h> +#include <sync.h> #include <test/util/setup_common.h> #include <txmempool.h> -#include <util/chaintype.h> #include <validation.h> +#include <cstddef> +#include <cstdint> +#include <memory> #include <vector> +class CCoinsViewCache; + static void AddTx(const CTransactionRef& tx, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) { int64_t nTime = 0; @@ -106,7 +113,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/merkle_root.cpp b/src/bench/merkle_root.cpp index 55409335bd..98ce197ea5 100644 --- a/src/bench/merkle_root.cpp +++ b/src/bench/merkle_root.cpp @@ -3,11 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> - #include <consensus/merkle.h> #include <random.h> #include <uint256.h> +#include <vector> + static void MerkleRoot(benchmark::Bench& bench) { FastRandomContext rng(true); diff --git a/src/bench/peer_eviction.cpp b/src/bench/peer_eviction.cpp index e04f3c403c..5b08cc758b 100644 --- a/src/bench/peer_eviction.cpp +++ b/src/bench/peer_eviction.cpp @@ -3,13 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <net.h> #include <netaddress.h> +#include <node/eviction.h> #include <random.h> #include <test/util/net.h> -#include <test/util/setup_common.h> -#include <algorithm> +#include <chrono> #include <functional> #include <vector> diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp index be0e5f2c2d..f58afe9845 100644 --- a/src/bench/poly1305.cpp +++ b/src/bench/poly1305.cpp @@ -5,9 +5,12 @@ #include <bench/bench.h> #include <crypto/poly1305.h> - #include <span.h> +#include <cstddef> +#include <cstdint> +#include <vector> + /* Number of bytes to process per iteration */ static constexpr uint64_t BUFFER_SIZE_TINY = 64; static constexpr uint64_t BUFFER_SIZE_SMALL = 256; diff --git a/src/bench/pool.cpp b/src/bench/pool.cpp index b2a5f8debf..40b098f54c 100644 --- a/src/bench/pool.cpp +++ b/src/bench/pool.cpp @@ -5,7 +5,11 @@ #include <bench/bench.h> #include <support/allocators/pool.h> +#include <cstddef> +#include <cstdint> +#include <functional> #include <unordered_map> +#include <utility> template <typename Map> void BenchFillClearMap(benchmark::Bench& bench, Map& map) diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp index 2524e215e4..9b83c42693 100644 --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -3,11 +3,13 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <prevector.h> + +#include <bench/bench.h> #include <serialize.h> #include <streams.h> -#include <type_traits> -#include <bench/bench.h> +#include <type_traits> +#include <vector> struct nontrivial_t { int x{-1}; diff --git a/src/bench/random.cpp b/src/bench/random.cpp new file mode 100644 index 0000000000..c2aa66850a --- /dev/null +++ b/src/bench/random.cpp @@ -0,0 +1,105 @@ +// 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 <algorithm> +#include <cstdint> +#include <iterator> +#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/readblock.cpp b/src/bench/readblock.cpp index 2b2bfe069e..058d953b4e 100644 --- a/src/bench/readblock.cpp +++ b/src/bench/readblock.cpp @@ -3,15 +3,22 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <bench/data.h> - -#include <consensus/validation.h> +#include <bench/data/block413567.raw.h> +#include <flatfile.h> #include <node/blockstorage.h> +#include <primitives/block.h> +#include <primitives/transaction.h> +#include <serialize.h> +#include <span.h> #include <streams.h> #include <test/util/setup_common.h> -#include <util/chaintype.h> #include <validation.h> +#include <cassert> +#include <cstdint> +#include <memory> +#include <vector> + static FlatFilePos WriteBlockToDisk(ChainstateManager& chainman) { DataStream stream{benchmark::data::block413567}; diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp index de76a87278..6b3e1c434e 100644 --- a/src/bench/rollingbloom.cpp +++ b/src/bench/rollingbloom.cpp @@ -6,7 +6,9 @@ #include <bench/bench.h> #include <common/bloom.h> #include <crypto/common.h> +#include <span.h> +#include <cstdint> #include <vector> static void RollingBloom(benchmark::Bench& bench) diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 713853e8c5..7e3e2d8e48 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -3,15 +3,23 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <bench/data.h> - +#include <bench/data/block413567.raw.h> +#include <chain.h> +#include <core_io.h> +#include <primitives/block.h> +#include <primitives/transaction.h> #include <rpc/blockchain.h> +#include <serialize.h> +#include <span.h> #include <streams.h> #include <test/util/setup_common.h> -#include <util/chaintype.h> +#include <uint256.h> +#include <univalue.h> #include <validation.h> -#include <univalue.h> +#include <cstddef> +#include <memory> +#include <vector> namespace { diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp index a55aa0c794..6e8757bbd5 100644 --- a/src/bench/rpc_mempool.cpp +++ b/src/bench/rpc_mempool.cpp @@ -3,14 +3,19 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> +#include <consensus/amount.h> #include <kernel/cs_main.h> -#include <kernel/mempool_entry.h> +#include <primitives/transaction.h> #include <rpc/mempool.h> +#include <script/script.h> +#include <sync.h> #include <test/util/setup_common.h> #include <txmempool.h> -#include <util/chaintype.h> - #include <univalue.h> +#include <util/check.h> + +#include <memory> +#include <vector> static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) diff --git a/src/bench/sign_transaction.cpp b/src/bench/sign_transaction.cpp new file mode 100644 index 0000000000..3f0635711d --- /dev/null +++ b/src/bench/sign_transaction.cpp @@ -0,0 +1,106 @@ +// 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 <addresstype.h> +#include <bench/bench.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 <script/signingprovider.h> +#include <span.h> +#include <test/util/random.h> +#include <uint256.h> +#include <util/translation.h> + +#include <cassert> +#include <map> +#include <vector> + +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) +{ + FastRandomContext rng; + ECC_Context ecc_context{}; + + auto key = GenerateRandomKey(); + auto msg = rng.rand256(); + auto merkle_root = use_null_merkle_root ? uint256() : rng.rand256(); + auto aux = rng.rand256(); + 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/streams_findbyte.cpp b/src/bench/streams_findbyte.cpp index 5098262e9a..004bf8ffc9 100644 --- a/src/bench/streams_findbyte.cpp +++ b/src/bench/streams_findbyte.cpp @@ -19,7 +19,7 @@ static void FindByte(benchmark::Bench& bench) uint8_t data[file_size] = {0}; data[file_size-1] = 1; file << data; - std::rewind(file.Get()); + file.seek(0, SEEK_SET); BufferedFile bf{file, /*nBufSize=*/file_size + 1, /*nRewindIn=*/file_size}; bench.run([&] { diff --git a/src/bench/strencodings.cpp b/src/bench/strencodings.cpp index 16d14278a7..dd5829caf2 100644 --- a/src/bench/strencodings.cpp +++ b/src/bench/strencodings.cpp @@ -3,9 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> -#include <bench/data.h> +#include <bench/data/block413567.raw.h> +#include <span.h> #include <util/strencodings.h> +#include <vector> + static void HexStrBench(benchmark::Bench& bench) { auto const& data = benchmark::data::block413567; diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index f38aa49a23..8d7e92a055 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -3,13 +3,20 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> +#include <hash.h> #include <key.h> -#include <script/script.h> +#include <primitives/transaction.h> +#include <pubkey.h> #include <script/interpreter.h> -#include <streams.h> +#include <script/script.h> +#include <span.h> #include <test/util/transaction_utils.h> +#include <uint256.h> #include <array> +#include <cassert> +#include <cstdint> +#include <vector> // Microbenchmark for verification of a basic P2WPKH script. Can be easily // modified to measure performance of other types of scripts. diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp index 7a10b167a6..8d3f7f9673 100644 --- a/src/bench/wallet_balance.cpp +++ b/src/bench/wallet_balance.cpp @@ -4,16 +4,24 @@ #include <bench/bench.h> #include <interfaces/chain.h> -#include <node/chainstate.h> -#include <node/context.h> +#include <kernel/chainparams.h> +#include <primitives/block.h> +#include <primitives/transaction.h> +#include <sync.h> #include <test/util/mining.h> #include <test/util/setup_common.h> -#include <wallet/test/util.h> -#include <validationinterface.h> +#include <uint256.h> +#include <util/time.h> +#include <validation.h> #include <wallet/receive.h> +#include <wallet/test/util.h> #include <wallet/wallet.h> +#include <wallet/walletutil.h> +#include <cassert> +#include <memory> #include <optional> +#include <string> namespace wallet { static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_mine) diff --git a/src/bench/wallet_create.cpp b/src/bench/wallet_create.cpp index 5c0557bf6f..3b916d7c39 100644 --- a/src/bench/wallet_create.cpp +++ b/src/bench/wallet_create.cpp @@ -2,14 +2,25 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php. -#include <config/bitcoin-config.h> // IWYU pragma: keep - #include <bench/bench.h> -#include <node/context.h> +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <random.h> +#include <support/allocators/secure.h> #include <test/util/setup_common.h> +#include <uint256.h> +#include <util/fs.h> +#include <util/translation.h> #include <wallet/context.h> +#include <wallet/db.h> #include <wallet/wallet.h> +#include <wallet/walletutil.h> + +#include <cassert> +#include <memory> +#include <optional> +#include <string> +#include <utility> +#include <vector> namespace wallet { static void WalletCreate(benchmark::Bench& bench, bool encrypted) @@ -42,7 +53,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/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp index 84e02d2a26..3c4b2f4f83 100644 --- a/src/bench/wallet_create_tx.cpp +++ b/src/bench/wallet_create_tx.cpp @@ -2,17 +2,42 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php. +#include <addresstype.h> #include <bench/bench.h> +#include <chain.h> #include <chainparams.h> -#include <wallet/coincontrol.h> +#include <consensus/amount.h> +#include <consensus/consensus.h> #include <consensus/merkle.h> +#include <interfaces/chain.h> #include <kernel/chain.h> -#include <node/context.h> +#include <node/blockstorage.h> +#include <outputtype.h> +#include <policy/feerate.h> +#include <primitives/block.h> +#include <primitives/transaction.h> +#include <script/script.h> +#include <sync.h> #include <test/util/setup_common.h> +#include <uint256.h> +#include <util/result.h> +#include <util/time.h> #include <validation.h> +#include <versionbits.h> +#include <wallet/coincontrol.h> +#include <wallet/coinselection.h> #include <wallet/spend.h> #include <wallet/test/util.h> #include <wallet/wallet.h> +#include <wallet/walletutil.h> + +#include <cassert> +#include <cstdint> +#include <map> +#include <memory> +#include <optional> +#include <utility> +#include <vector> using wallet::CWallet; using wallet::CreateMockableWalletDatabase; diff --git a/src/bench/wallet_ismine.cpp b/src/bench/wallet_ismine.cpp index 753404b526..5343814ab2 100644 --- a/src/bench/wallet_ismine.cpp +++ b/src/bench/wallet_ismine.cpp @@ -2,20 +2,29 @@ // 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 <addresstype.h> #include <bench/bench.h> -#include <interfaces/chain.h> +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <key.h> #include <key_io.h> -#include <node/context.h> +#include <script/descriptor.h> +#include <script/script.h> +#include <script/signingprovider.h> +#include <sync.h> #include <test/util/setup_common.h> -#include <util/translation.h> -#include <validationinterface.h> #include <wallet/context.h> +#include <wallet/db.h> #include <wallet/test/util.h> +#include <wallet/types.h> #include <wallet/wallet.h> #include <wallet/walletutil.h> +#include <cassert> +#include <cstdint> +#include <memory> +#include <string> +#include <utility> + namespace wallet { static void WalletIsMine(benchmark::Bench& bench, bool legacy_wallet, int num_combo = 0) { @@ -43,8 +52,8 @@ static void WalletIsMine(benchmark::Bench& bench, bool legacy_wallet, int num_co key.MakeNewKey(/*fCompressed=*/true); FlatSigningProvider keys; std::string error; - std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", keys, error, /*require_checksum=*/false); - WalletDescriptor w_desc(std::move(desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/0, /*next_index=*/0); + std::vector<std::unique_ptr<Descriptor>> desc = Parse("combo(" + EncodeSecret(key) + ")", keys, error, /*require_checksum=*/false); + WalletDescriptor w_desc(std::move(desc.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/0, /*next_index=*/0); auto spkm = wallet->AddWalletDescriptor(w_desc, keys, /*label=*/"", /*internal=*/false); assert(spkm); } diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 02582deda4..5d92cfa0de 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -2,21 +2,25 @@ // 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 <addresstype.h> #include <bench/bench.h> -#include <interfaces/chain.h> -#include <node/context.h> -#include <test/util/mining.h> +#include <bitcoin-build-config.h> // IWYU pragma: keep +#include <consensus/amount.h> +#include <outputtype.h> +#include <primitives/transaction.h> #include <test/util/setup_common.h> -#include <wallet/test/util.h> -#include <util/translation.h> -#include <validationinterface.h> +#include <util/check.h> #include <wallet/context.h> -#include <wallet/receive.h> +#include <wallet/db.h> +#include <wallet/test/util.h> +#include <wallet/transaction.h> #include <wallet/wallet.h> +#include <wallet/walletutil.h> -#include <optional> +#include <cstdint> +#include <memory> +#include <utility> +#include <vector> namespace wallet{ static void AddTx(CWallet& wallet) diff --git a/src/bench/xor.cpp b/src/bench/xor.cpp index edda74214a..fc9dc5d172 100644 --- a/src/bench/xor.cpp +++ b/src/bench/xor.cpp @@ -3,8 +3,8 @@ // file COPYING or https://opensource.org/license/mit/. #include <bench/bench.h> - #include <random.h> +#include <span.h> #include <streams.h> #include <cstddef> diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index 4d2a6f0c2a..9cbafa233d 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -15,10 +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> @@ -28,6 +29,7 @@ #include <util/fs.h> #include <util/signalinterrupt.h> #include <util/task_runner.h> +#include <util/translation.h> #include <validation.h> #include <validationinterface.h> @@ -40,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 @@ -61,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 @@ -86,9 +87,13 @@ int main(int argc, char* argv[]) { std::cout << "Progress: " << title.original << ", " << progress_percent << ", " << resume_possible << std::endl; } - void warning(const bilingual_str& warning) override + void warningSet(kernel::Warning id, const bilingual_str& message) override { - std::cout << "Warning: " << warning.original << std::endl; + std::cout << "Warning " << static_cast<int>(id) << " set: " << message.original << std::endl; + } + void warningUnset(kernel::Warning id) override + { + std::cout << "Warning " << static_cast<int>(id) << " unset" << std::endl; } void flushError(const bilingual_str& message) override { @@ -151,7 +156,7 @@ int main(int argc, char* argv[]) { LOCK(chainman.GetMutex()); std::cout - << "\t" << "Reindexing: " << std::boolalpha << chainman.m_blockman.m_reindexing.load() << std::noboolalpha << std::endl + << "\t" << "Blockfiles Indexed: " << std::boolalpha << chainman.m_blockman.m_blockfiles_indexed.load() << std::noboolalpha << std::endl << "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl << "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl << "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl; @@ -278,8 +283,6 @@ int main(int argc, char* argv[]) epilogue: // Without this precise shutdown sequence, there will be a lot of nullptr // dereferencing and UB. - if (chainman.m_thread_load.joinable()) chainman.m_thread_load.join(); - validation_signals.FlushBackgroundCallbacks(); { LOCK(cs_main); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index cc639d8793..38fd740b71 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chainparamsbase.h> #include <clientversion.h> @@ -42,6 +42,9 @@ #include <event2/keyvalq_struct.h> #include <support/events.h> +using util::Join; +using util::ToString; + // The server returns time values from a mockable system clock, but it is not // trivial to get the mocked time from the server, nor is it needed for now, so // just use a plain system_clock. @@ -72,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); @@ -83,10 +87,10 @@ static void SetupCliArgs(ArgsManager& argsman) "arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to " "RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), - ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total, after filtering for quality and recency. The total number of addresses known to the node may be higher.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the output of -getinfo is the result of multiple non-atomic requests. Some entries in the output may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); + argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total, after filtering for quality and recency. The total number of addresses known to the node may be higher.", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); + argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the output of -getinfo is the result of multiple non-atomic requests. Some entries in the output may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); + argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); SetupChainParamsBaseOptions(argsman); argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS); @@ -95,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); @@ -298,7 +302,7 @@ public: } addresses.pushKV("total", total); result.pushKV("addresses_known", std::move(addresses)); - return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V1_LEGACY); + return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V2); } }; @@ -367,7 +371,7 @@ public: } result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]); result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]); - return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V1_LEGACY); + return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V2); } }; @@ -425,6 +429,8 @@ private: std::string ChainToString() const { switch (gArgs.GetChainType()) { + case ChainType::TESTNET4: + return " testnet4"; case ChainType::TESTNET: return " testnet"; case ChainType::SIGNET: @@ -622,7 +628,7 @@ public: } } - return JSONRPCReplyObj(UniValue{result}, NullUniValue, /*id=*/1, JSONRPCVersion::V1_LEGACY); + return JSONRPCReplyObj(UniValue{result}, NullUniValue, /*id=*/1, JSONRPCVersion::V2); } const std::string m_help_doc{ @@ -672,7 +678,7 @@ public: " \".\" - we do not relay addresses to this peer (addr_relay_enabled is false)\n" " addrl Total number of addresses dropped due to rate limiting\n" " age Duration of connection to the peer, in minutes\n" - " asmap Mapped AS (Autonomous System) number in the BGP route to the peer, used for diversifying\n" + " asmap Mapped AS (Autonomous System) number at the end of the BGP route to the peer, used for diversifying\n" " peer selection (only displayed if the -asmap config option is set)\n" " id Peer index, in increasing order of peer connections since node startup\n" " address IP address and port of the peer\n" @@ -709,7 +715,7 @@ public: UniValue result(UniValue::VOBJ); result.pushKV("address", address_str); result.pushKV("blocks", reply.get_obj()["result"]); - return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V1_LEGACY); + return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V2); } protected: std::string address_str; @@ -743,8 +749,41 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6) // 3. default port for chain uint16_t port{BaseParams().RPCPort()}; - SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host); - port = static_cast<uint16_t>(gArgs.GetIntArg("-rpcport", port)); + { + uint16_t rpcconnect_port{0}; + const std::string rpcconnect_str = gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT); + if (!SplitHostPort(rpcconnect_str, rpcconnect_port, host)) { + // Uses argument provided as-is + // (rather than value parsed) + // to aid the user in troubleshooting + throw std::runtime_error(strprintf("Invalid port provided in -rpcconnect: %s", rpcconnect_str)); + } else { + if (rpcconnect_port != 0) { + // Use the valid port provided in rpcconnect + port = rpcconnect_port; + } // else, no port was provided in rpcconnect (continue using default one) + } + + if (std::optional<std::string> rpcport_arg = gArgs.GetArg("-rpcport")) { + // -rpcport was specified + const uint16_t rpcport_int{ToIntegral<uint16_t>(rpcport_arg.value()).value_or(0)}; + if (rpcport_int == 0) { + // Uses argument provided as-is + // (rather than value parsed) + // to aid the user in troubleshooting + throw std::runtime_error(strprintf("Invalid port provided in -rpcport: %s", rpcport_arg.value())); + } + + // Use the valid port provided + port = rpcport_int; + + // If there was a valid port provided in rpcconnect, + // rpcconnect_port is non-zero. + if (rpcconnect_port != 0) { + tfm::format(std::cerr, "Warning: Port specified in both -rpcconnect and -rpcport. Using -rpcport %u\n", port); + } + } + } // Obtain event base raii_event_base base = obtain_event_base(); @@ -911,7 +950,8 @@ static void ParseError(const UniValue& error, std::string& strPrint, int& nRet) strPrint += ("error message:\n" + err_msg.get_str()); } if (err_code.isNum() && err_code.getInt<int>() == RPC_WALLET_NOT_SPECIFIED) { - strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line."; + strPrint += " Or for the CLI, specify the \"-rpcwallet=<walletname>\" option before the command"; + strPrint += " (run \"bitcoin-cli -h\" for help or \"bitcoin-cli listwallets\" to see which wallets are currently loaded)."; } } else { strPrint = "error: " + error.write(); @@ -1173,6 +1213,7 @@ static int CommandLineRPC(int argc, char *argv[]) fputc('\n', stdout); } } + gArgs.CheckMultipleCLIArgs(); std::unique_ptr<BaseRequestHandler> rh; std::string method; if (gArgs.IsArgSet("-getinfo")) { diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index cfac50e090..b3329afba4 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chainparamsbase.h> #include <clientversion.h> @@ -32,6 +32,11 @@ #include <functional> #include <memory> +using util::SplitString; +using util::ToString; +using util::TrimString; +using util::TrimStringView; + static bool fCreateBlank; static std::map<std::string,UniValue> registers; static const int CONTINUE_EXECUTION=-1; @@ -203,12 +208,12 @@ static CAmount ExtractAndValidateValue(const std::string& strValue) static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) { - int64_t newVersion; - if (!ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion > TX_MAX_STANDARD_VERSION) { + uint32_t newVersion; + if (!ParseUInt32(cmdVal, &newVersion) || newVersion < 1 || newVersion > TX_MAX_STANDARD_VERSION) { throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'"); } - tx.nVersion = (int) newVersion; + tx.version = newVersion; } static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal) @@ -259,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"); } @@ -280,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); } @@ -620,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() + "')"); } @@ -629,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-util.cpp b/src/bitcoin-util.cpp index c8f5bc5026..46ba136d81 100644 --- a/src/bitcoin-util.cpp +++ b/src/bitcoin-util.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <arith_uint256.h> #include <chain.h> diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 87af347473..00f39be794 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chainparams.h> #include <chainparamsbase.h> @@ -24,6 +24,8 @@ #include <string> #include <tuple> +using util::Join; + const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; static void SetupWalletToolArgs(ArgsManager& argsman) @@ -67,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/bitcoind.cpp b/src/bitcoind.cpp index 0b89aa42af..192676a10b 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chainparams.h> #include <clientversion.h> @@ -17,6 +17,7 @@ #include <kernel/context.h> #include <node/context.h> #include <node/interface_ui.h> +#include <node/warnings.h> #include <noui.h> #include <util/check.h> #include <util/exception.h> @@ -108,10 +109,11 @@ int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint) #endif -static bool ParseArgs(ArgsManager& args, int argc, char* argv[]) +static bool ParseArgs(NodeContext& node, int argc, char* argv[]) { + ArgsManager& args{*Assert(node.args)}; // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main() - SetupServerArgs(args); + SetupServerArgs(args, node.init->canListenIpc()); std::string error; if (!args.ParseParameters(argc, argv, error)) { return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error))); @@ -181,6 +183,8 @@ static bool AppInit(NodeContext& node) return false; } + node.warnings = std::make_unique<node::Warnings>(); + node.kernel = std::make_unique<kernel::Context>(); node.ecc_context = std::make_unique<ECC_Context>(); if (!AppInitSanityChecks(*node.kernel)) @@ -265,12 +269,12 @@ MAIN_FUNCTION // Interpret command line arguments ArgsManager& args = *Assert(node.args); - if (!ParseArgs(args, argc, argv)) return EXIT_FAILURE; + if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE; // Process early info return commands such as -help or -version if (ProcessInitCommands(args)) return EXIT_SUCCESS; // Start application - if (!AppInit(node) || !Assert(node.shutdown)->wait()) { + if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) { node.exit_status = EXIT_FAILURE; } Interrupt(node); diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index 5a4513d281..5f4061a71d 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -17,8 +17,8 @@ #include <unordered_map> -CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block) : - nonce(GetRand<uint64_t>()), +CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, const uint64_t nonce) : + nonce(nonce), shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) { FillShortTxIDSelector(); //TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase @@ -167,7 +167,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c break; } - LogPrint(BCLog::CMPCTBLOCK, "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock)); + LogDebug(BCLog::CMPCTBLOCK, "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock)); return READ_STATUS_OK; } @@ -217,10 +217,10 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector< return READ_STATUS_CHECKBLOCK_FAILED; } - LogPrint(BCLog::CMPCTBLOCK, "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool (incl at least %lu from extra pool) and %lu txn requested\n", hash.ToString(), prefilled_count, mempool_count, extra_count, vtx_missing.size()); + LogDebug(BCLog::CMPCTBLOCK, "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool (incl at least %lu from extra pool) and %lu txn requested\n", hash.ToString(), prefilled_count, mempool_count, extra_count, vtx_missing.size()); if (vtx_missing.size() < 5) { for (const auto& tx : vtx_missing) { - LogPrint(BCLog::CMPCTBLOCK, "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString()); + LogDebug(BCLog::CMPCTBLOCK, "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString()); } } diff --git a/src/blockencodings.h b/src/blockencodings.h index 2b1fabadd6..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()) {} @@ -106,10 +106,15 @@ public: CBlockHeader header; - // Dummy for deserialization - CBlockHeaderAndShortTxIDs() {} + /** + * Dummy for deserialization + */ + CBlockHeaderAndShortTxIDs() = default; - CBlockHeaderAndShortTxIDs(const CBlock& block); + /** + * @param[in] nonce This should be randomly generated, and is used for the siphash secret key + */ + CBlockHeaderAndShortTxIDs(const CBlock& block, const uint64_t nonce); uint64_t GetShortID(const Wtxid& wtxid) const; @@ -141,7 +146,7 @@ public: explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {} - // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form + // extra_txn is a list of extra orphan/conflicted/etc transactions to look at ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn); bool IsTxAvailable(size_t index) const; ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing); diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index e045b88513..5e6702ccc3 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -16,6 +16,8 @@ #include <util/golombrice.h> #include <util/string.h> +using util::Join; + static const std::map<BlockFilterType, std::string> g_filter_types = { {BlockFilterType::BASIC, "basic"}, }; diff --git a/src/chain.h b/src/chain.h index bb70dbd8bc..13f7582385 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,13 +173,12 @@ 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 //! //! Note: this value is modified to show BLOCK_OPT_WITNESS during UTXO snapshot - //! load to avoid the block index being spuriously rewound. + //! load to avoid a spurious startup failure requiring -reindex. //! @sa NeedsRedownload //! @sa ActivateSnapshot uint32_t nStatus GUARDED_BY(::cs_main){0}; @@ -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 539578085b..68319e8e8b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -21,6 +21,8 @@ #include <stdexcept> #include <vector> +using util::SplitString; + void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& options) { if (args.IsArgSet("-signetseednode")) { @@ -113,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..ecab817ba1 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -7,537 +7,1072 @@ * Each line contains a BIP155 serialized (networkID, addr, port) tuple. */ static const uint8_t chainparams_seed_main[] = { - 0x01,0x04,0x01,0xfd,0x9f,0x13,0x20,0x8d, - 0x01,0x04,0x02,0x98,0x4a,0xd3,0x20,0x8d, + 0x06,0x10,0xfc,0x1f,0x22,0xc3,0x95,0xdc,0xa3,0xaf,0x4a,0x93,0x82,0x51,0xbe,0xb9,0x18,0x58,0x20,0x8d, + 0x06,0x10,0xfc,0x6d,0xf5,0x62,0x86,0xa0,0x79,0x1d,0x8a,0x20,0x7a,0xa2,0x88,0x79,0x21,0x76,0x20,0x8d, + 0x06,0x10,0xfc,0x70,0xde,0x9d,0x7f,0xe2,0x0b,0x32,0x58,0x28,0x1a,0x3c,0x0d,0x0f,0x83,0xec,0x20,0x8d, + 0x06,0x10,0xfc,0x95,0x6e,0xdb,0xaf,0x65,0x9e,0xa3,0xcd,0x27,0x21,0xef,0xf5,0xe2,0x29,0xc6,0x20,0x8d, + 0x06,0x10,0xfc,0xa0,0x01,0x51,0x79,0xac,0x89,0x92,0xb5,0x1e,0xbd,0xc4,0x6e,0xd9,0x41,0xbe,0x20,0x8d, + 0x06,0x10,0xfc,0xc7,0xbe,0x49,0xcc,0xd1,0xdc,0x91,0x31,0x25,0xf0,0xda,0x45,0x7d,0x08,0xce,0x20,0x8d, + 0x06,0x10,0xfc,0xcb,0x02,0x48,0x11,0xa6,0x10,0x42,0x0b,0xca,0x12,0x18,0xf7,0xce,0x7d,0x3d,0x20,0x8d, + 0x06,0x10,0xfc,0xf1,0x22,0xff,0x30,0x70,0x58,0x2f,0xa8,0x73,0x61,0xbc,0x4b,0xc1,0x81,0xbf,0x20,0x8d, + 0x05,0x20,0xd6,0xf3,0x0c,0x53,0xa3,0xbc,0x36,0x64,0x2e,0xfd,0x1a,0x0e,0xbc,0x24,0xfe,0x98,0x55,0x67,0x30,0x38,0x02,0xa5,0xc7,0x84,0x98,0x36,0x9f,0x04,0xd6,0xbf,0x7d,0x27,0x00,0x00, + 0x05,0x20,0xd7,0xad,0x8b,0xe2,0x42,0x70,0x24,0xd9,0x88,0x4f,0xf2,0xb6,0x40,0x44,0x48,0x5c,0x70,0xa5,0x1b,0x25,0x88,0xd1,0x3d,0x64,0xb6,0xeb,0x38,0xf0,0x4d,0xc2,0xad,0x21,0x00,0x00, + 0x05,0x20,0xd7,0xae,0xef,0x3a,0x88,0x82,0x06,0x0f,0x15,0x15,0x57,0xc4,0x54,0x46,0xb8,0x94,0xb8,0x48,0x39,0x04,0x2b,0x90,0xcf,0x3c,0x82,0x1c,0x10,0x49,0x96,0xd7,0x6d,0x17,0x00,0x00, + 0x05,0x20,0xd0,0xe5,0x8b,0xb6,0xf9,0xb3,0xbc,0xb9,0xd1,0xdb,0x3b,0x46,0xd7,0x39,0xfa,0x80,0xb4,0xf4,0xe8,0x59,0x29,0x98,0x90,0xa5,0xb0,0x8b,0x5b,0x72,0x95,0x91,0xd3,0x80,0x00,0x00, + 0x05,0x20,0xd1,0x24,0x72,0x32,0xb4,0xae,0x00,0x73,0x48,0xe4,0x2c,0xb9,0xfb,0x4f,0x64,0x81,0xb7,0x5a,0xde,0xdd,0x4e,0x57,0x76,0x79,0x68,0x1e,0x09,0xd1,0xfb,0x26,0x12,0xd2,0x00,0x00, + 0x05,0x20,0xd1,0x54,0x90,0xe9,0xdf,0x7f,0x0c,0x34,0xf8,0xe9,0x46,0x26,0x65,0x1e,0xa8,0x9c,0x2c,0x98,0xb7,0xea,0x60,0xef,0x91,0xd2,0xc8,0x92,0x9f,0x81,0x37,0x27,0xaa,0xac,0x00,0x00, + 0x05,0x20,0xd1,0xd3,0x69,0xb9,0x56,0xe3,0x2f,0x59,0xa9,0x9d,0x7b,0xbd,0xb5,0x24,0xf8,0x77,0xd6,0x59,0x02,0x25,0x11,0xa0,0xfd,0x1d,0xfd,0x47,0x08,0xfb,0xee,0x15,0x9b,0x68,0x00,0x00, + 0x05,0x20,0xd2,0x4c,0x5b,0xdf,0x33,0x97,0xa2,0x58,0xf5,0x9a,0x45,0x94,0xb5,0xcf,0x00,0xd2,0x99,0x42,0x25,0xaa,0xa1,0x5f,0x3e,0x04,0x15,0xb2,0x4e,0x8d,0x27,0xe5,0x66,0x18,0x00,0x00, + 0x05,0x20,0xd2,0x67,0xd0,0x51,0x50,0xda,0x15,0xf0,0xd3,0x85,0x8d,0x0c,0x8e,0xd0,0x6a,0xb2,0xc4,0xa3,0x9c,0xd7,0x8e,0x52,0x74,0xd4,0xb9,0x41,0x1c,0xc5,0x5f,0x80,0x35,0xe1,0x00,0x00, + 0x05,0x20,0xd2,0xb6,0xbc,0xcf,0x25,0x02,0xf6,0xaf,0x0d,0x7f,0xc4,0x4f,0xa4,0xe1,0x45,0x06,0xee,0xf6,0x3a,0x9a,0x17,0xc4,0xcd,0x12,0xce,0xe4,0x05,0x35,0x2a,0xa1,0x39,0x6b,0x00,0x00, + 0x05,0x20,0xd2,0x83,0xb0,0x24,0x1e,0x5b,0xbc,0xfa,0x68,0x3a,0xfc,0xdd,0x2f,0x72,0x66,0x77,0x15,0x7c,0x82,0x64,0xd6,0x78,0x4b,0x6d,0x8f,0x62,0xa5,0x03,0xfa,0xd9,0x4c,0xa6,0x00,0x00, + 0x05,0x20,0xd3,0x28,0xae,0xff,0x5d,0xec,0xc6,0xce,0x1b,0x5f,0xd9,0x71,0xf0,0x22,0x71,0x64,0x1b,0x3a,0x46,0x93,0xf2,0xa3,0x07,0x26,0xf9,0xff,0x93,0x29,0x46,0x0c,0xd4,0x64,0x00,0x00, + 0x05,0x20,0xd3,0xb9,0x97,0x12,0xfa,0x7c,0x21,0x80,0x8f,0x17,0xa5,0x9c,0x86,0x37,0x6a,0x26,0xb6,0x08,0x3b,0x85,0x68,0x0c,0xb6,0x47,0x87,0xb1,0xc1,0x40,0x9d,0xa4,0x7b,0xdd,0x00,0x00, + 0x05,0x20,0xd3,0x87,0xc3,0x49,0x01,0xea,0x9a,0xa8,0x74,0xa7,0x0b,0x31,0x27,0xed,0xa1,0x21,0xe7,0x2f,0x7d,0xa5,0x06,0xbc,0x9a,0xf8,0xca,0x24,0x88,0x7b,0x60,0x55,0xfc,0xca,0x00,0x00, + 0x05,0x20,0xd3,0xa7,0xf2,0x20,0x00,0x90,0x6e,0x73,0x83,0x53,0xb9,0xa4,0x91,0xf0,0x9e,0x43,0x68,0x64,0x0c,0xfe,0xc4,0x5c,0xd4,0x8d,0x48,0xc0,0x41,0xd9,0x4b,0x6a,0x9e,0x35,0x00,0x00, + 0x05,0x20,0xd4,0x42,0xca,0xec,0xf8,0x8f,0x17,0xcd,0x62,0x55,0x4f,0xb4,0x33,0x3b,0x2b,0x63,0xa4,0x39,0x47,0xdd,0xbf,0x07,0x03,0x56,0xfb,0x05,0xcb,0x9c,0x5b,0x54,0xc4,0xdb,0x00,0x00, + 0x05,0x20,0xd5,0x7a,0xd8,0xee,0x9b,0x90,0x83,0x8b,0x8f,0x6d,0x54,0x2e,0x86,0xdb,0x4f,0xac,0x20,0x4f,0x7b,0x1c,0x38,0xb7,0x4f,0x19,0xd3,0x42,0xf5,0x23,0x07,0x08,0xac,0x69,0x00,0x00, + 0x05,0x20,0xd5,0x64,0xb2,0x2c,0x56,0xce,0x2f,0x5a,0xb3,0x71,0xcc,0x74,0x88,0x86,0xa0,0xb7,0xc9,0x84,0x2d,0x79,0x9d,0x8b,0x11,0x8f,0x5c,0xcc,0x8e,0x7b,0x1c,0xbd,0x8b,0x13,0x00,0x00, + 0x05,0x20,0xd5,0x6c,0xb6,0x58,0x32,0x6b,0x3c,0x54,0x14,0xa2,0x5f,0x5a,0x6c,0xf0,0xdf,0x8f,0x27,0x84,0x12,0x9f,0x4f,0x2e,0xc7,0xd9,0x6c,0x16,0xaf,0x75,0xe9,0x98,0x1e,0xb3,0x00,0x00, + 0x05,0x20,0xd5,0xdb,0x6a,0xc3,0x8c,0x90,0x30,0xba,0xe8,0x0e,0x67,0xda,0x7a,0x16,0x49,0xc4,0x0e,0xef,0xc0,0xfb,0x33,0xd0,0x44,0xea,0xc1,0x5f,0x90,0xc1,0x94,0x0b,0xc4,0x5d,0x00,0x00, + 0x05,0x20,0xd6,0x79,0x01,0x2a,0x09,0x56,0x75,0x74,0xda,0x2e,0x3a,0x13,0xef,0x72,0x0b,0x04,0x41,0x77,0x6a,0x38,0x04,0x85,0x25,0xdb,0x84,0x39,0x53,0x79,0xae,0x76,0x72,0xf3,0x00,0x00, + 0x05,0x20,0xdf,0xe6,0xcb,0x43,0x43,0xc7,0x24,0xc8,0x1b,0x9e,0x82,0x8d,0x59,0x75,0xee,0x10,0x36,0x71,0x11,0xc4,0x79,0xcc,0xae,0xb9,0xa9,0x89,0x93,0x7c,0x3c,0xfc,0x18,0xd7,0x00,0x00, + 0x05,0x20,0xd8,0xa7,0x0e,0xa6,0x82,0x65,0x0d,0x74,0xd1,0x9a,0xb8,0x18,0xc2,0x87,0x26,0x1b,0x25,0x7d,0x6c,0x0a,0xdb,0xc9,0x45,0x7b,0x81,0xfd,0x4d,0x0e,0xdb,0x99,0xf9,0xe1,0x00,0x00, + 0x05,0x20,0xd8,0xfa,0x75,0x9a,0x8e,0xde,0x32,0x1c,0xd8,0x3f,0x22,0xb9,0xea,0x09,0x5a,0x67,0xbf,0x4e,0x62,0x94,0x7f,0x3b,0xeb,0x62,0xc3,0xae,0x4f,0x90,0x64,0x54,0xe6,0xeb,0x00,0x00, + 0x05,0x20,0xd9,0x9c,0x20,0xfe,0xc2,0xe6,0x6a,0x16,0x30,0x81,0x54,0xc9,0x3f,0x9a,0x89,0x10,0xa9,0x4b,0xf1,0x05,0x56,0xd5,0x04,0x2d,0xb7,0x6a,0x7b,0x67,0x8d,0xf0,0xbe,0x8f,0x00,0x00, + 0x05,0x20,0xd9,0xf2,0x84,0x0e,0x2f,0xcc,0x2a,0xd9,0x71,0x36,0x2c,0x0f,0x90,0xfd,0xb8,0x1d,0xb8,0xc9,0xb5,0xaa,0x05,0x9e,0x48,0x96,0xad,0x04,0x69,0xbc,0xbe,0x8f,0xd2,0x0f,0x00,0x00, + 0x05,0x20,0xda,0x11,0x7a,0xe2,0xd7,0x85,0x9b,0x2e,0x7f,0xf1,0xf0,0x2e,0x7c,0x2c,0xa2,0x99,0x21,0xd0,0xd8,0xc6,0xc7,0xc4,0xc8,0x86,0x93,0x84,0x48,0x3e,0xf1,0x48,0x35,0x9c,0x00,0x00, + 0x05,0x20,0xda,0x60,0x9c,0x4c,0x9a,0x57,0xae,0xd7,0x12,0x78,0x33,0x3c,0x62,0x81,0x48,0x95,0x33,0xb2,0x42,0xf1,0xd9,0x45,0x4e,0x2f,0xaa,0x65,0x37,0x94,0x15,0xed,0x51,0xeb,0x00,0x00, + 0x05,0x20,0xdb,0x81,0xd2,0xe0,0x57,0xdc,0xf0,0x41,0x1c,0x65,0x33,0x9d,0x3b,0x89,0xe0,0x7f,0xe5,0x7f,0xbf,0x72,0x05,0x88,0xd8,0x87,0x38,0xc5,0xe3,0x3c,0x7f,0x91,0x9f,0xf3,0x00,0x00, + 0x05,0x20,0xdc,0x7e,0xce,0xb0,0x24,0x71,0x95,0x1f,0x4b,0x1e,0xf1,0x7c,0x6d,0xeb,0xad,0x91,0x74,0x94,0x21,0x93,0x28,0xdb,0xda,0xfa,0xcf,0xbe,0x7d,0x48,0x32,0x58,0x0c,0x12,0x00,0x00, + 0x05,0x20,0xdc,0xbf,0x96,0x01,0x86,0x2b,0x16,0x7b,0x56,0x2d,0xeb,0xab,0xbd,0x52,0x86,0x0a,0xc6,0xe5,0x03,0xe9,0xb8,0x49,0x3a,0x7a,0x69,0x94,0x36,0x1c,0xaa,0x21,0xe8,0xc4,0x00,0x00, + 0x05,0x20,0xdd,0x28,0x34,0xf9,0x65,0xc5,0x93,0x08,0x85,0x0f,0x59,0xac,0xe0,0x5d,0xe4,0x0e,0x95,0xc6,0x03,0xfd,0x62,0xd8,0xf4,0x43,0xee,0xb5,0x76,0x17,0x16,0xcb,0xa8,0x07,0x00,0x00, + 0x05,0x20,0xde,0x38,0xe4,0x5b,0xe2,0x32,0xf3,0x99,0x1c,0x12,0x03,0xca,0xc5,0xcc,0x9f,0x45,0xc2,0x67,0xaf,0x89,0x97,0xed,0xa0,0x16,0x43,0xe6,0x5a,0x46,0x53,0x83,0x19,0x0a,0x00,0x00, + 0x05,0x20,0xe6,0x8d,0x48,0x4a,0xa3,0x21,0x39,0x36,0x43,0x70,0x07,0x58,0x9b,0x76,0xa9,0x56,0x54,0xaa,0x2b,0xa4,0x02,0x1a,0x41,0x4a,0x32,0x19,0x49,0x7d,0xdb,0x05,0xfc,0xed,0x00,0x00, + 0x05,0x20,0xe7,0x20,0x1d,0xb4,0xb2,0x89,0x23,0xa2,0xf0,0x98,0x3f,0x79,0x2f,0xc0,0x75,0xb5,0xd1,0x85,0x26,0x24,0x8f,0xfc,0x94,0x92,0xa2,0x0b,0xc6,0xdd,0xa3,0xd4,0x06,0x02,0x00,0x00, + 0x05,0x20,0xe7,0x2a,0xd2,0x00,0x8c,0x40,0xff,0xd1,0x3b,0xb3,0xfc,0x52,0xd7,0xed,0xc5,0x78,0x23,0xdd,0x18,0xda,0x38,0x61,0x8f,0x89,0x8e,0x59,0x5a,0xbd,0x60,0xe9,0x13,0x1f,0x00,0x00, + 0x05,0x20,0xe7,0x48,0x7f,0x46,0xe1,0x2a,0xd1,0xc4,0xd3,0x5e,0x14,0x00,0x5f,0x6e,0xa5,0x97,0x6f,0x7f,0x64,0xd3,0xf9,0xdb,0xba,0x67,0x39,0xdb,0x48,0xce,0x74,0x7c,0x7c,0xbd,0x00,0x00, + 0x05,0x20,0xe7,0xae,0xe8,0xe3,0xde,0x78,0xbd,0x0b,0x8f,0xc6,0x58,0x1e,0xc1,0x46,0xf4,0x4b,0xfd,0x61,0x76,0x56,0x31,0xce,0x16,0x9f,0x01,0xa9,0x2d,0x72,0x95,0xdb,0xf9,0x81,0x00,0x00, + 0x05,0x20,0xe7,0xd3,0x15,0xc1,0x63,0xf3,0x3e,0x00,0x82,0xfe,0x63,0x17,0x8d,0x6d,0xe6,0xe1,0xf0,0x07,0x89,0x4c,0xbf,0x0e,0x7c,0xe6,0x4e,0xca,0x8c,0x09,0x5a,0x14,0xdb,0x43,0x00,0x00, + 0x05,0x20,0xe0,0x7e,0xc1,0x3a,0x9f,0xb4,0xc1,0x97,0x5e,0xd7,0x7b,0x3b,0x35,0xf2,0x6a,0xfc,0x00,0x05,0xb4,0x01,0x1f,0x91,0xfb,0x55,0xac,0x7d,0x7a,0xe6,0x55,0xdf,0x71,0x96,0x00,0x00, + 0x05,0x20,0xe0,0xc7,0x44,0x62,0x6e,0x7e,0xe0,0x94,0x38,0x61,0xd2,0x5b,0x6a,0x9e,0xad,0xc4,0x7d,0x6d,0xe3,0xa0,0xbe,0x77,0x5c,0xab,0xb0,0x89,0x48,0x5a,0x47,0x85,0x37,0xa1,0x00,0x00, + 0x05,0x20,0xe0,0xd1,0x79,0x18,0x6b,0xd8,0x5e,0xd5,0x20,0x07,0x67,0xe8,0x06,0xd1,0xf8,0x13,0xca,0x6e,0xec,0xf7,0x70,0x6e,0x66,0x74,0xb2,0x6c,0xaa,0xf9,0xeb,0x07,0x02,0xe0,0x00,0x00, + 0x05,0x20,0xe2,0xcb,0x45,0x57,0x29,0x15,0x1f,0x2a,0xa4,0x73,0x76,0x08,0x05,0x80,0x39,0x08,0xe4,0xfd,0x82,0x3c,0x9a,0x42,0x7b,0xce,0xd8,0x78,0x43,0xa5,0xfd,0x9a,0x13,0xed,0x00,0x00, + 0x05,0x20,0xe2,0xd8,0x76,0xea,0xf0,0x2a,0x1a,0x42,0x62,0x14,0xbd,0xeb,0xd4,0x5d,0xd9,0x82,0x9b,0xc2,0x62,0x99,0x10,0x96,0xaf,0x6b,0xd0,0xf7,0xd0,0xc7,0xdf,0xa7,0x6b,0x4f,0x00,0x00, + 0x05,0x20,0xe2,0xdc,0xc6,0x36,0xe0,0xce,0x3c,0x2f,0xef,0x98,0xc0,0x82,0xcc,0xc1,0x4e,0x1a,0xf2,0x2b,0xbe,0xd2,0x0e,0x3b,0x65,0xb0,0xed,0x38,0x83,0x83,0x01,0x86,0xb4,0x6e,0x00,0x00, + 0x05,0x20,0xe3,0x10,0xf5,0xda,0xed,0xb1,0xf6,0xb6,0x80,0x06,0xd3,0xd2,0x43,0x8f,0x17,0xc6,0x4d,0x12,0xe7,0xd8,0x17,0xab,0x6a,0x2c,0x34,0x37,0x93,0x1e,0x45,0xa4,0x9e,0x53,0x00,0x00, + 0x05,0x20,0xe3,0x6e,0x3c,0x2e,0x66,0x1d,0x9e,0x55,0x02,0x93,0x7c,0x40,0xb0,0x08,0x6b,0x72,0xf2,0xb7,0xda,0x3c,0xd8,0x93,0xc4,0x1b,0x86,0x76,0x5b,0xdc,0x73,0x66,0x57,0x9b,0x00,0x00, + 0x05,0x20,0xe4,0x50,0xf4,0x5f,0x52,0x23,0xba,0x01,0x6c,0x29,0x0f,0x01,0xd5,0xba,0x87,0x98,0x70,0x23,0x1f,0x05,0xda,0xc9,0x89,0x20,0x78,0xd6,0xac,0xd0,0x81,0x5f,0x9e,0x53,0x00,0x00, + 0x05,0x20,0xe4,0x5d,0xe7,0x28,0x3b,0xbf,0xb8,0x6f,0xd3,0x8a,0x39,0xc5,0xf8,0xc0,0x0b,0x62,0xac,0xa5,0x51,0x81,0x05,0x54,0x2b,0xfe,0xb0,0x78,0xaa,0xa4,0x6a,0x8d,0x07,0xf4,0x00,0x00, + 0x05,0x20,0xe4,0xb7,0xf2,0x63,0x76,0xe2,0xda,0x29,0x7a,0xf7,0xc0,0x9b,0x75,0x48,0x27,0x04,0xcb,0x5b,0xea,0x73,0x30,0xb6,0xe0,0x8e,0xaf,0x44,0x51,0x1e,0x67,0x29,0x04,0xa5,0x00,0x00, + 0x05,0x20,0xef,0xe4,0x71,0x17,0x28,0x07,0xfa,0xa2,0x4d,0x71,0x84,0x5b,0x53,0x5e,0xa0,0x42,0x4e,0x19,0xb7,0x72,0x6c,0x53,0x6f,0x7b,0x60,0x6a,0xba,0x10,0x27,0xf0,0x8e,0xba,0x00,0x00, + 0x05,0x20,0xe8,0x0d,0x85,0x84,0xaa,0xa5,0xad,0x06,0xe1,0x10,0xb4,0xcd,0x73,0x41,0x78,0x0b,0x94,0xa8,0x16,0xae,0xbd,0x92,0x15,0x0b,0xfb,0xd0,0x82,0xe9,0xf4,0xba,0xcf,0x1b,0x00,0x00, + 0x05,0x20,0xe8,0x60,0xd7,0xb3,0x73,0x82,0xd5,0x83,0x40,0xd4,0xea,0xdb,0x9b,0xde,0x96,0xf0,0x42,0x91,0xe6,0x0a,0x18,0x42,0xc5,0x94,0x39,0x6f,0x37,0xc8,0x3f,0x09,0xfb,0x27,0x00,0x00, + 0x05,0x20,0xe9,0x19,0x33,0xb3,0xeb,0xa2,0x92,0x03,0xe9,0xed,0x83,0xa9,0x16,0x34,0xe9,0x57,0xb2,0x7a,0x26,0x26,0xca,0x60,0x32,0x54,0x99,0x19,0x7c,0x3f,0x54,0x0b,0x12,0xd0,0x00,0x00, + 0x05,0x20,0xe9,0x75,0x2b,0xf5,0xa4,0xd0,0x87,0xd6,0x4d,0xc1,0x8e,0x80,0x12,0x19,0x99,0xb1,0xf4,0xef,0x21,0x04,0xde,0x17,0x13,0x99,0x23,0x50,0x51,0x54,0xc0,0x23,0x63,0xc9,0x00,0x00, + 0x05,0x20,0xea,0x14,0x9c,0x75,0xf9,0x32,0x55,0xbf,0x9c,0xff,0x28,0x94,0xdc,0x60,0xf7,0xed,0x7a,0xb5,0x08,0xe9,0x82,0x9b,0x7f,0x9f,0x11,0x29,0x62,0x9f,0x9e,0xbf,0x5e,0x03,0x00,0x00, + 0x05,0x20,0xea,0x9c,0x6f,0xee,0x96,0x99,0xe5,0xae,0xf6,0x63,0x8d,0x88,0x4f,0x8c,0x5a,0x7c,0x8f,0x0f,0x5d,0x74,0x50,0x6f,0x37,0x99,0xbb,0x08,0x6d,0x46,0xb3,0xba,0x4d,0x87,0x00,0x00, + 0x05,0x20,0xeb,0x05,0x75,0xe2,0x79,0xbf,0x78,0x21,0xf6,0xde,0x75,0x18,0xe9,0x6c,0x01,0xfe,0x30,0x0d,0xda,0xe0,0xcc,0x60,0x29,0xf2,0x82,0xf6,0x8b,0xa1,0xea,0x72,0xde,0x41,0x00,0x00, + 0x05,0x20,0xeb,0x6a,0xb2,0x0d,0xb5,0x92,0x4e,0xff,0xf4,0xbf,0xeb,0xd8,0xbc,0x64,0x14,0x4a,0xb3,0x2a,0xd8,0x4a,0xad,0x65,0x8a,0x02,0xb1,0x92,0xca,0x28,0x77,0x26,0x4e,0xe6,0x00,0x00, + 0x05,0x20,0xeb,0xd2,0x00,0x12,0xe8,0x53,0x17,0x83,0xaf,0xa3,0x41,0xf3,0x58,0x07,0x0a,0xa1,0x05,0xea,0x65,0x58,0xa2,0x6b,0x59,0x74,0x29,0x72,0x3c,0x79,0xac,0x3b,0x75,0xf3,0x00,0x00, + 0x05,0x20,0xeb,0xe9,0x5a,0xab,0x15,0xf4,0x23,0xa5,0x02,0x01,0xd0,0x2a,0x18,0x5f,0x27,0x1e,0x11,0x0a,0x1d,0x5a,0xff,0xbe,0xe6,0x1d,0xc0,0xd4,0xbb,0xa3,0x09,0xa5,0x15,0xf9,0x00,0x00, + 0x05,0x20,0xec,0x5c,0x93,0x49,0x55,0x12,0x19,0x49,0x10,0x80,0xbb,0xd2,0x87,0x1d,0x81,0xf0,0x7b,0x1e,0xd6,0x5e,0xaf,0x8e,0x72,0x03,0x1b,0x51,0x19,0x10,0x42,0xac,0x37,0x91,0x00,0x00, + 0x05,0x20,0xed,0x1b,0x4a,0x0e,0x2d,0xbc,0x14,0x33,0x42,0x51,0x28,0x64,0xcb,0xed,0x1e,0x45,0xad,0x33,0xa2,0xad,0x34,0xca,0xcf,0xc8,0x63,0x7c,0xd2,0x8c,0xbe,0x17,0x79,0xc3,0x00,0x00, + 0x05,0x20,0xed,0xe5,0x4a,0x22,0x85,0x0b,0x1c,0xd1,0x0e,0xb6,0x57,0x7b,0x11,0xf2,0x12,0xd7,0x1c,0x46,0x3a,0x93,0x38,0x22,0x7e,0x9d,0xbe,0xd6,0x3e,0xf6,0xfa,0x39,0x57,0x88,0x00,0x00, + 0x05,0x20,0xf6,0xa5,0x1b,0x6b,0x65,0xe4,0x63,0x7c,0xcb,0x7a,0xee,0xcd,0xf6,0x07,0x4b,0x0b,0x9f,0xb7,0x95,0xf2,0xa7,0x7c,0x6e,0xa1,0x0f,0x9c,0x40,0xed,0xc1,0xc0,0x90,0xf8,0x00,0x00, + 0x05,0x20,0xf0,0xd5,0x53,0xac,0xf6,0x72,0x2c,0xf1,0xa5,0xe4,0x0d,0x08,0xcb,0xc3,0xde,0x93,0x8f,0xe7,0x4b,0xd7,0x06,0xa5,0x0e,0x68,0x76,0x39,0x42,0xfd,0x8f,0x92,0x1e,0x4c,0x00,0x00, + 0x05,0x20,0xf1,0x36,0x14,0x1b,0x0f,0x04,0xd9,0x51,0x52,0x65,0x6c,0xd6,0xe6,0x9e,0x27,0x79,0x45,0xdc,0x70,0xe1,0x5f,0x05,0x80,0x04,0xc9,0xae,0xad,0x3f,0x14,0xf6,0x4d,0xf7,0x00,0x00, + 0x05,0x20,0xf1,0xe0,0xe1,0xe1,0xb5,0xa9,0x41,0xbc,0x15,0x71,0x15,0x58,0xf6,0xa3,0x0d,0xed,0x76,0x81,0xcd,0x42,0x9d,0xfe,0x64,0x24,0x6b,0xaf,0x6c,0x31,0xef,0xf7,0x6c,0x38,0x00,0x00, + 0x05,0x20,0xf2,0x4f,0xcb,0x8e,0x12,0xdf,0x56,0xa3,0xc1,0xb8,0x6d,0xc5,0x3c,0x1e,0x08,0x50,0x9b,0x87,0xae,0xb2,0xe2,0x69,0x53,0x05,0x33,0xe6,0x46,0xbc,0xc6,0x7c,0xa3,0xcf,0x00,0x00, + 0x05,0x20,0xf3,0x0e,0xb5,0x13,0x8e,0x6b,0xc7,0x01,0x15,0x40,0x27,0xb0,0x8d,0x6d,0x84,0x2b,0x67,0xae,0x5c,0xd5,0x43,0xc2,0xed,0x71,0x50,0x5d,0x33,0xac,0x5f,0xc5,0x15,0x1d,0x00,0x00, + 0x05,0x20,0xf3,0x22,0xe3,0x03,0xff,0x21,0x8b,0xa2,0xe6,0x5f,0xc7,0x3c,0x7a,0x1e,0xf6,0x24,0x9e,0xfb,0xdf,0xca,0xfe,0x92,0x2f,0x9f,0x42,0xcb,0x61,0xa2,0xb0,0x40,0x22,0xe5,0x00,0x00, + 0x05,0x20,0xf3,0x4e,0x57,0xa4,0xdd,0xe1,0x87,0x6c,0xe9,0x2b,0x7e,0xe1,0x99,0xf9,0x83,0xaa,0x95,0xd2,0xbf,0xe9,0x8f,0x02,0x2d,0xf5,0xe7,0xda,0xbb,0x0f,0x8d,0xbe,0x13,0x4b,0x00,0x00, + 0x05,0x20,0xf3,0x4e,0x60,0x0b,0xd6,0x7b,0x04,0x73,0x89,0x8e,0xc6,0xfd,0x87,0x80,0x94,0xf5,0x02,0x2f,0x96,0x1c,0x95,0x11,0xe7,0x9d,0x0d,0xe6,0x5e,0x05,0x27,0x6c,0x60,0x6e,0x00,0x00, + 0x05,0x20,0xf3,0x6e,0xe0,0x31,0x29,0x92,0x8a,0x59,0x96,0x8b,0x8d,0xe5,0x2e,0xb2,0xae,0x0f,0x7d,0x8a,0x20,0xbc,0x2d,0xce,0x8b,0xfa,0xf2,0xb6,0xba,0x83,0x53,0x87,0xf9,0x08,0x00,0x00, + 0x05,0x20,0xf4,0x43,0xc6,0xb5,0xab,0x00,0x26,0x99,0x3c,0x8e,0x85,0xfb,0xb3,0x23,0xef,0xd6,0x38,0x50,0x1a,0xd3,0xa0,0x8e,0xbd,0x33,0x4b,0xde,0x8e,0x72,0x45,0x26,0x50,0x30,0x00,0x00, + 0x05,0x20,0xf5,0x6b,0x74,0x22,0x0c,0x78,0x80,0x0c,0xe4,0xb7,0xe9,0xf5,0xb0,0x78,0xef,0x79,0xa6,0xc9,0x03,0xfd,0x36,0xdc,0x44,0x21,0x7d,0x2f,0x4f,0x8a,0x99,0xa4,0x86,0x8e,0x00,0x00, + 0x05,0x20,0xf5,0x6e,0x0b,0x70,0x63,0xa6,0x36,0x72,0xb8,0xa5,0xe0,0x27,0x02,0xaa,0x7c,0x18,0xb7,0x81,0xff,0x76,0x43,0x16,0x32,0x11,0x8f,0x2c,0x4b,0x13,0xfa,0x18,0x28,0xee,0x00,0x00, + 0x05,0x20,0xf5,0xa7,0x22,0x0d,0xcd,0x98,0x3b,0x87,0x24,0x38,0xff,0xc1,0x32,0x41,0x5a,0x73,0xc1,0x95,0x0e,0x99,0xf8,0x69,0x1f,0xad,0xce,0xf8,0xe5,0xb8,0xea,0x9e,0xbd,0x41,0x00,0x00, + 0x05,0x20,0xf5,0xae,0x46,0xae,0xb3,0x4e,0x78,0x4f,0xf0,0x4f,0xe8,0xc5,0x8f,0x12,0xda,0x95,0x93,0xc5,0x98,0x56,0xe5,0xa1,0x3e,0x7a,0xe1,0x26,0x32,0x43,0x58,0xb2,0xd1,0x01,0x00,0x00, + 0x05,0x20,0xf6,0x04,0x38,0xc5,0x3c,0x91,0xe7,0x57,0xf7,0x1d,0x77,0x5a,0x03,0x5e,0x67,0xf1,0x3f,0xd6,0xc5,0x6f,0x69,0x89,0x2b,0x3e,0x77,0x5e,0x41,0x70,0x43,0xb3,0x9c,0x12,0x00,0x00, + 0x05,0x20,0xff,0x9c,0x14,0x9c,0x71,0xb7,0xa5,0x65,0x2e,0xb9,0xf6,0x83,0x8e,0xd4,0xa3,0x58,0xe8,0x61,0xb1,0x39,0xfc,0x50,0x50,0xa8,0x34,0x01,0x3f,0xa9,0x08,0x23,0x72,0x7d,0x00,0x00, + 0x05,0x20,0xff,0xfd,0xfc,0x62,0xd7,0x6e,0xb4,0xe6,0xf2,0xb3,0xf1,0x17,0x6f,0x79,0xcd,0x19,0xc4,0x25,0x7d,0x70,0x10,0x06,0xfd,0xf0,0x3a,0xd3,0x28,0x52,0x09,0x3a,0xb6,0x18,0x00,0x00, + 0x05,0x20,0xff,0xc6,0x05,0xc8,0xd1,0xe5,0x42,0x95,0x0d,0xbb,0x2c,0x4e,0x85,0x2e,0xa4,0x35,0x03,0xe0,0x04,0xcb,0x90,0x81,0x08,0x81,0x14,0x85,0x9b,0xbd,0x8b,0x75,0x9d,0xbe,0x00,0x00, + 0x05,0x20,0xf8,0x84,0x13,0xdc,0x9b,0x72,0x41,0x2e,0x91,0x5e,0x34,0xf1,0x03,0x7b,0x8c,0x80,0x86,0x28,0x2a,0x39,0x27,0x36,0xda,0x58,0x6b,0x71,0x48,0x7e,0xcf,0x65,0x88,0xdd,0x00,0x00, + 0x05,0x20,0xf8,0xf6,0xc2,0xd5,0x89,0x0e,0x2b,0x79,0x81,0x06,0x9e,0x75,0xdb,0x7e,0x21,0x68,0x61,0x2c,0xd2,0x62,0x35,0x5c,0x04,0x70,0xcb,0x3e,0xf3,0x4a,0xef,0x86,0x5b,0xee,0x00,0x00, + 0x05,0x20,0xf8,0xe0,0x92,0x68,0x43,0xa3,0x15,0xdc,0x10,0xbb,0xe7,0xad,0x2f,0xdb,0xb3,0xf6,0xc4,0xcd,0xa5,0x28,0x40,0x77,0x96,0x4c,0x77,0xba,0x9a,0x08,0x57,0xa0,0xbc,0xa8,0x00,0x00, + 0x05,0x20,0xf9,0x3d,0x7c,0xf5,0xe5,0x6d,0xa4,0xd9,0x73,0x62,0xba,0x3f,0x0c,0x1b,0x00,0x96,0x2a,0xb2,0xc5,0x5f,0x32,0x49,0x05,0xb3,0xc0,0x92,0xfc,0xf0,0xb7,0x97,0x2e,0xd5,0x00,0x00, + 0x05,0x20,0xf9,0x26,0xfc,0x6f,0x75,0xaf,0x17,0x9f,0x59,0x8c,0x6f,0x1d,0xb7,0x7c,0xf4,0x09,0x8d,0x24,0x1a,0xed,0x58,0x36,0x47,0x0b,0x98,0x60,0xb1,0xe1,0x91,0xc2,0x9d,0x8f,0x00,0x00, + 0x05,0x20,0xf9,0x46,0x37,0xd1,0xac,0x9e,0x3e,0x48,0xd0,0xf4,0x64,0x34,0x88,0x03,0x58,0xb7,0x44,0xa1,0x37,0xd7,0x7c,0xad,0xaf,0x3d,0x3e,0x14,0x9a,0x76,0xcf,0x1b,0x48,0xa0,0x00,0x00, + 0x05,0x20,0xf9,0x61,0xe8,0x1d,0x77,0x55,0xc5,0xac,0x86,0x72,0x3a,0xce,0x42,0xec,0xb5,0xf4,0x9c,0x38,0x22,0x5c,0x90,0x38,0xe4,0x97,0xa4,0x3a,0x16,0x77,0x78,0x7b,0x55,0x5b,0x00,0x00, + 0x05,0x20,0xf9,0xbc,0xd0,0x0c,0xd2,0xa8,0xd5,0xe3,0x91,0x63,0x1d,0x3e,0xd1,0x64,0xe7,0x93,0xea,0x1e,0xf2,0xc6,0x75,0x4f,0x70,0xec,0x69,0x53,0xc7,0xca,0x86,0x6a,0xc0,0xe7,0x00,0x00, + 0x05,0x20,0xf9,0xdf,0x58,0x87,0xe2,0x5a,0x15,0xee,0xe9,0xa5,0xdc,0xbd,0x63,0xad,0x57,0xe3,0xd3,0x77,0x5a,0x6f,0x40,0xd7,0x9d,0x7f,0x74,0xcb,0x75,0x29,0xf4,0x38,0x66,0x5e,0x00,0x00, + 0x05,0x20,0xfa,0x10,0x81,0x69,0x0a,0x8d,0x98,0x23,0xc9,0xab,0xad,0xbc,0x96,0xff,0xb5,0x7d,0x67,0x4a,0x1a,0xff,0x64,0x08,0x10,0xaf,0xd8,0x6a,0xf9,0x84,0x4f,0xe0,0xf2,0x57,0x00,0x00, + 0x05,0x20,0xfa,0x6d,0x5b,0xfc,0x86,0x20,0xf7,0xc1,0x4e,0x26,0xc4,0x67,0xdc,0x7a,0xfd,0x7f,0xef,0x95,0x15,0xe8,0x1d,0x6d,0x1b,0xa5,0xeb,0x86,0x2d,0x00,0x74,0x70,0x59,0xb6,0x00,0x00, + 0x05,0x20,0xfa,0xfc,0xbe,0x7d,0x7f,0x7d,0x91,0xfa,0x94,0x9f,0x8b,0x98,0xb5,0x3d,0xae,0x85,0x3f,0xe1,0xc7,0x86,0x79,0xe2,0x36,0x20,0x5c,0x9e,0x46,0xa3,0x21,0x05,0x36,0x7b,0x00,0x00, + 0x05,0x20,0xfb,0xad,0x4b,0xf4,0x1b,0xdf,0x60,0x6c,0x77,0xf9,0xfa,0xc9,0x56,0xfc,0x85,0x77,0x5e,0xdc,0xd5,0x75,0x60,0x4f,0x3e,0x7a,0x80,0xf8,0xac,0x8e,0xa6,0x1e,0x89,0xec,0x00,0x00, + 0x05,0x20,0xfc,0x34,0xfd,0xce,0xb8,0xe1,0x6d,0xbd,0xf5,0xed,0x63,0xc5,0x85,0x0e,0x89,0x6a,0x8d,0xaf,0xed,0x87,0x80,0xb8,0xea,0x69,0x14,0x6c,0x24,0x80,0x77,0x41,0x32,0x5c,0x00,0x00, + 0x05,0x20,0xfc,0x25,0x6f,0x00,0x55,0xff,0xb4,0xe2,0xe1,0xac,0x97,0x73,0xa2,0x6f,0xbc,0x9d,0x5f,0xa5,0x73,0xba,0xfa,0xfc,0x82,0xba,0x3f,0xb6,0xe8,0xa5,0xe4,0x08,0x98,0xf7,0x00,0x00, + 0x05,0x20,0xfc,0x78,0x60,0x5d,0x41,0xd2,0x2c,0xd1,0x80,0xa8,0x96,0x86,0x2c,0x80,0x5b,0x06,0x98,0x59,0x4a,0xe4,0x51,0x2e,0x5a,0x97,0xbb,0x7f,0xe4,0x84,0x66,0x86,0x36,0xac,0x00,0x00, + 0x05,0x20,0xfc,0x79,0x14,0x77,0x6b,0x0e,0x34,0x8d,0xde,0x01,0x33,0xed,0xb4,0x0e,0xa7,0xc9,0x15,0x4f,0xd0,0x27,0x2c,0xd6,0x5f,0xe9,0x63,0x82,0x8d,0xd5,0x0c,0x9e,0x18,0x29,0x00,0x00, + 0x05,0x20,0xfc,0x43,0x09,0xcf,0x99,0x05,0x09,0x60,0xb9,0xa1,0x15,0x40,0x84,0x30,0xab,0xad,0xd2,0xa4,0x3c,0x3d,0x9f,0xcd,0x49,0x61,0xff,0x61,0x47,0x05,0x91,0xed,0x50,0x47,0x00,0x00, + 0x05,0x20,0xfc,0xe3,0x81,0xe6,0xe0,0xbf,0xdc,0x7d,0xf1,0xfb,0x9b,0xa7,0x74,0x13,0xbf,0x56,0xee,0x88,0x54,0x23,0x16,0xc3,0xa3,0x05,0xe9,0xa0,0xc1,0xf7,0x60,0x90,0x77,0x50,0x00,0x00, + 0x05,0x20,0xfc,0xe6,0x95,0xac,0xee,0x23,0x2a,0x24,0xd8,0xdc,0x86,0x4d,0x11,0x46,0x1a,0xa6,0x36,0x2e,0x6e,0x8d,0x33,0x46,0xe6,0x07,0x84,0x01,0xc5,0x24,0xe3,0x5d,0x25,0x31,0x00,0x00, + 0x05,0x20,0xfd,0x26,0x2f,0x66,0x79,0x80,0x16,0x99,0xa2,0x20,0x09,0x76,0xbe,0xe1,0xb5,0x2e,0xc0,0xa6,0x65,0xc5,0x06,0x10,0x3e,0x08,0x08,0x07,0x9a,0x3f,0x67,0xc0,0xd1,0x03,0x00,0x00, + 0x05,0x20,0xfd,0x8d,0x1c,0x58,0xf2,0x50,0xf5,0xc5,0x42,0x09,0xab,0x87,0x7f,0x06,0xed,0x4b,0x6b,0xbf,0xf2,0xeb,0x6c,0x6d,0x29,0x63,0xf9,0x80,0xf9,0x6c,0x83,0xa3,0x8c,0x19,0x00,0x00, + 0x05,0x20,0xfd,0x9f,0xc8,0xc4,0xa5,0xd9,0x43,0x1a,0x0e,0x29,0xed,0x33,0x2a,0xc3,0x97,0x71,0x55,0x34,0xf6,0x69,0xfb,0x98,0xd7,0x8a,0x16,0xe3,0x3f,0x11,0x26,0x47,0x96,0xf2,0x00,0x00, + 0x05,0x20,0x06,0xb2,0x87,0x38,0x58,0xe6,0x76,0x94,0x25,0xbe,0x86,0x57,0xa3,0x45,0x05,0x80,0xfe,0x7a,0xd1,0x5e,0x50,0x0c,0x9a,0xf5,0x80,0x74,0x22,0xdb,0xd9,0xd4,0x10,0xdd,0x00,0x00, + 0x05,0x20,0x07,0x7f,0x41,0x73,0xa2,0x89,0xb1,0x39,0x96,0x5e,0x42,0x76,0x58,0xf3,0x90,0xe5,0xba,0x84,0xfb,0x18,0xf1,0x58,0x70,0xab,0x1b,0xff,0x01,0x4f,0xc6,0x70,0xe4,0xb4,0x00,0x00, + 0x05,0x20,0x00,0x6e,0xc6,0x41,0x43,0xa3,0x51,0xfd,0xa9,0x1e,0x00,0x33,0x85,0xf7,0x3b,0x0f,0x88,0x13,0xfb,0x62,0x2c,0x89,0xcd,0xe5,0xda,0x29,0xaa,0xf8,0x3b,0xfd,0x5f,0xe3,0x00,0x00, + 0x05,0x20,0x00,0xd8,0x53,0x8f,0x43,0xd9,0xa9,0xba,0x92,0xa0,0x8a,0x47,0xe9,0x86,0x78,0xfc,0x61,0xf2,0x86,0x91,0x3a,0x93,0xfe,0x5f,0xb4,0x01,0x85,0xc7,0x1a,0x95,0x64,0xf3,0x00,0x00, + 0x05,0x20,0x01,0xdd,0xa8,0xa5,0xcf,0x48,0xc8,0x7d,0xec,0xa8,0xf7,0xde,0x15,0x6f,0x0b,0x89,0x7e,0x6c,0x36,0xb7,0xcb,0x2d,0xe6,0x3e,0x96,0xa1,0x45,0x0c,0x67,0x17,0x36,0x42,0x00,0x00, + 0x05,0x20,0x02,0x5c,0xbf,0xf0,0x5c,0xf2,0x0c,0x01,0xac,0x99,0x23,0x46,0x7a,0xda,0x7d,0xf1,0x84,0xc8,0x8c,0x40,0x3d,0x38,0x91,0x80,0x33,0xfb,0xbc,0xde,0x55,0xba,0xbd,0x7d,0x00,0x00, + 0x05,0x20,0x03,0x9c,0xfe,0xb7,0x8a,0x3c,0x02,0xe0,0xf8,0xb5,0x16,0x9b,0x7c,0x61,0xcb,0x21,0x1a,0x42,0xc7,0x0a,0xa0,0xe7,0x10,0xcd,0x32,0x3e,0xc0,0x29,0x41,0x29,0x50,0xe0,0x00,0x00, + 0x05,0x20,0x03,0x9e,0xd8,0x8c,0xbc,0xef,0x01,0xcf,0x56,0x0d,0xa9,0x85,0x7f,0x99,0x5b,0x57,0x68,0x0e,0x9a,0xac,0x3c,0xdd,0x58,0x38,0x6d,0x81,0xb2,0x21,0x7b,0xa7,0x2f,0xce,0x00,0x00, + 0x05,0x20,0x03,0xa2,0x14,0x41,0x78,0x2e,0xcd,0x6a,0x2a,0x68,0xfd,0xb4,0x27,0x93,0x6c,0x93,0xf4,0x05,0x78,0x7c,0x81,0x17,0x80,0x6a,0x8c,0x3b,0xcf,0xa3,0x14,0x1c,0x1f,0x76,0x00,0x00, + 0x05,0x20,0x04,0x13,0xa1,0xf6,0xd8,0x50,0x4f,0x48,0x93,0xb8,0x28,0x28,0x32,0x10,0x6e,0x65,0x8e,0xee,0x18,0x39,0xd2,0xcd,0xb5,0x9c,0x2c,0x1f,0x9c,0x33,0xe3,0x9f,0x20,0xe6,0x00,0x00, + 0x05,0x20,0x04,0x27,0x06,0x27,0x2c,0xf4,0xeb,0x17,0x0e,0xac,0x6a,0x12,0x5b,0x09,0xbf,0x35,0x2c,0xc3,0x48,0xe1,0xf6,0x04,0x22,0xad,0x4f,0x2a,0x3e,0xd0,0x08,0xab,0xe9,0x60,0x00,0x00, + 0x05,0x20,0x04,0x91,0x20,0xe1,0x68,0x81,0x9e,0xdc,0x72,0x72,0x30,0xdd,0x5f,0x4e,0xac,0x5d,0x09,0x9c,0xfe,0xb4,0x55,0x27,0xcc,0x41,0x4f,0x33,0xee,0xa8,0xaf,0xa3,0x07,0xd2,0x00,0x00, + 0x05,0x20,0x05,0x04,0x43,0xf6,0x14,0x9f,0x4e,0x25,0x70,0xd9,0x59,0xf5,0x74,0xce,0xdd,0x83,0x86,0x64,0x36,0x08,0xb9,0x2d,0xc7,0x4c,0x90,0x76,0x51,0x69,0x9b,0x8e,0x17,0x38,0x00,0x00, + 0x05,0x20,0x05,0x09,0xd5,0x8d,0xd5,0xb7,0x32,0x1d,0x01,0x1b,0x6c,0x92,0x82,0x48,0x67,0x49,0xc6,0xd3,0x18,0x1a,0x4b,0x8a,0xf9,0xbe,0x60,0x76,0xcc,0x34,0x51,0x22,0x80,0xcb,0x00,0x00, + 0x05,0x20,0x05,0xac,0x7c,0x5e,0xf7,0x97,0xd4,0xa0,0xe9,0xf5,0x34,0x7b,0xed,0x8b,0x8d,0xe3,0x01,0x98,0xa2,0xb1,0x63,0x8b,0x6f,0xc4,0x77,0xd6,0x47,0x4d,0xf1,0x76,0xcc,0xac,0x00,0x00, + 0x05,0x20,0x06,0x38,0x23,0x93,0x67,0x08,0xf4,0xff,0x30,0x1d,0x81,0x1d,0xe5,0x07,0xa6,0x3a,0x1b,0xc1,0xcf,0x4d,0x3f,0x03,0x27,0xbc,0x44,0x55,0x53,0x68,0x14,0x4a,0x6f,0xf0,0x00,0x00, + 0x05,0x20,0x06,0x1b,0xf8,0xed,0x23,0x42,0x4e,0x25,0xfa,0x7e,0x31,0x2e,0xc8,0x73,0xa3,0xb6,0xa6,0x07,0xe9,0x7e,0xfc,0x5b,0xfb,0x99,0xc8,0x90,0x08,0xd5,0x11,0x7f,0xe5,0x8e,0x00,0x00, + 0x05,0x20,0x06,0x4b,0x30,0x2e,0x0e,0xb6,0x65,0x17,0x0c,0xc8,0x57,0x2e,0x2d,0x9d,0x25,0x32,0xca,0x5e,0x9a,0x17,0xc8,0xba,0xc4,0x0c,0xd5,0xb1,0x31,0x5e,0x3e,0x34,0xc2,0xb6,0x00,0x00, + 0x05,0x20,0x0f,0xbd,0x2d,0x45,0xf3,0xf7,0xc6,0x56,0x1e,0xcb,0x90,0x4e,0xa4,0x3d,0xbe,0xcb,0x54,0x2d,0x7c,0x65,0x99,0xfa,0x9d,0xf4,0xbb,0x8e,0x9f,0x2d,0xb4,0x9e,0xe8,0x2d,0x00,0x00, + 0x05,0x20,0x08,0x25,0x81,0x5e,0x4b,0xb0,0x17,0xf2,0xcc,0x9b,0xf1,0x25,0x21,0x72,0x2f,0xf4,0x9c,0xa9,0x60,0x9f,0x22,0xd0,0x8f,0x12,0x2f,0x98,0x74,0xb2,0xc5,0xa3,0xd6,0x25,0x00,0x00, + 0x05,0x20,0x08,0x56,0xf6,0x2f,0xd8,0x47,0xa4,0x5c,0xb9,0xf8,0xd1,0x63,0xae,0xae,0x53,0x24,0xbe,0x5d,0xf1,0x68,0x33,0x55,0x6a,0x13,0x60,0xa3,0x7a,0xa6,0x79,0x14,0x0d,0xb9,0x00,0x00, + 0x05,0x20,0x09,0x5e,0x43,0x76,0x0f,0x50,0x49,0x1e,0x0f,0x3d,0x5c,0xe6,0x30,0xe2,0x6e,0xff,0x9b,0x23,0x15,0xae,0xda,0x88,0xec,0xd8,0xcc,0xf4,0xdd,0x90,0x65,0x53,0x04,0x5d,0x00,0x00, + 0x05,0x20,0x09,0xfb,0xc4,0x8c,0xa5,0x37,0xb3,0x2d,0x9f,0xa2,0xc1,0x21,0x24,0xfb,0x59,0x3a,0x3b,0x33,0xdd,0xf0,0x6e,0x6b,0xaa,0xc4,0xf2,0x58,0xe3,0xc9,0x04,0x4a,0x91,0xdc,0x00,0x00, + 0x05,0x20,0x0a,0x1a,0xd9,0xea,0xc1,0x2a,0xcf,0x8b,0x6b,0x02,0x9b,0xe8,0x3c,0xeb,0xe3,0x3b,0x6e,0x73,0x79,0x8e,0xb3,0x03,0x4b,0xdf,0x53,0x09,0xf8,0x10,0xbe,0x01,0xce,0x6c,0x00,0x00, + 0x05,0x20,0x0a,0x53,0x94,0xf5,0x2d,0xf1,0x03,0xb9,0x4a,0x36,0xfe,0xdf,0xdd,0x0c,0x5f,0xc3,0xe3,0xca,0xb2,0xa2,0x2f,0x30,0x4c,0xb2,0xce,0x4d,0x98,0xa4,0x45,0x7f,0xd2,0x71,0x00,0x00, + 0x05,0x20,0x0b,0x23,0x87,0xad,0x9d,0x46,0x11,0x14,0xd5,0xe6,0x82,0xbe,0x82,0x9d,0x87,0x0b,0xcc,0x9b,0x6e,0x08,0x2b,0x56,0xf8,0xc1,0x95,0x41,0xe6,0x86,0x37,0x48,0x75,0x4f,0x00,0x00, + 0x05,0x20,0x0b,0xbd,0x01,0x2f,0xc2,0x71,0x65,0xb1,0x47,0xc8,0x58,0x6e,0x4a,0x49,0x51,0x71,0x46,0x9d,0x2a,0x41,0x3d,0x0d,0x37,0x0a,0x24,0x08,0x1e,0x58,0xed,0x61,0x84,0xb6,0x00,0x00, + 0x05,0x20,0x0c,0x50,0x55,0x46,0x87,0x5a,0x8d,0x14,0xfb,0xa7,0x29,0x70,0x18,0xa6,0x29,0x80,0x8c,0x33,0x42,0x5a,0x8f,0xe4,0x84,0x64,0x3d,0x0e,0xb5,0xbd,0x36,0x34,0x42,0xb6,0x00,0x00, + 0x05,0x20,0x0c,0x9b,0xd8,0xae,0x9c,0x3e,0xc1,0xcb,0xbd,0x4b,0x39,0xf0,0xcb,0xba,0x2e,0x35,0xde,0x33,0x50,0x72,0x9a,0xdc,0x25,0xe6,0x47,0x31,0xc3,0xc1,0x91,0x14,0x46,0xe3,0x00,0x00, + 0x05,0x20,0x0c,0xc7,0x52,0xda,0xec,0x89,0x9b,0x05,0x1c,0xfb,0x8b,0xe4,0x27,0xfe,0x59,0x4f,0xb1,0x80,0xb3,0xd6,0xfd,0x8f,0x70,0x7b,0xfe,0x8c,0xae,0x80,0x71,0x93,0x07,0xe6,0x00,0x00, + 0x05,0x20,0x0d,0x12,0x27,0x98,0x6f,0xf8,0xb7,0xdb,0xde,0x03,0x62,0xf1,0xc1,0xe2,0xf8,0xb0,0x1d,0x5b,0x95,0xc8,0x2f,0xc5,0xdd,0x27,0x7a,0x8d,0x45,0x2d,0xec,0xc4,0x29,0x31,0x00,0x00, + 0x05,0x20,0x0d,0x8d,0xe6,0x70,0x06,0xbd,0x34,0x54,0x57,0x63,0x57,0x71,0x2e,0x6b,0x81,0xd7,0xec,0x9c,0x84,0xfa,0xe0,0xf6,0x4b,0x4e,0x41,0xe1,0x07,0xd0,0x2c,0x2c,0x57,0x5e,0x00,0x00, + 0x05,0x20,0x0e,0x1d,0x41,0x12,0x28,0x1f,0x62,0x1d,0x0c,0x74,0x10,0x21,0x62,0x3c,0x18,0x9d,0x55,0x6e,0x07,0x8b,0xd5,0x98,0x12,0xa8,0x25,0x32,0x04,0x55,0x94,0x43,0xe0,0xe6,0x00,0x00, + 0x05,0x20,0x16,0xec,0xa2,0x72,0x87,0xf5,0x82,0x67,0xdb,0x2e,0xd6,0x65,0xb5,0xee,0x25,0x94,0x74,0x80,0xc8,0xb7,0x24,0x5a,0xb3,0xdc,0xd8,0x8d,0xe4,0x4a,0x19,0x71,0x1f,0x72,0x00,0x00, + 0x05,0x20,0x16,0xf2,0x13,0x4f,0x7a,0x77,0x0a,0xe4,0x03,0xf6,0x1d,0xcc,0x2d,0xbb,0x9a,0x65,0x26,0xc2,0x18,0xe7,0x26,0xfc,0x65,0xb1,0x8d,0xc6,0x65,0xae,0xf8,0xdf,0xfa,0xef,0x00,0x00, + 0x05,0x20,0x17,0x4a,0xaf,0x5d,0x36,0x09,0x47,0x48,0x91,0xe8,0x3a,0x86,0x9a,0xad,0x06,0x25,0xd7,0x9b,0x53,0xdc,0xc9,0xf4,0x4e,0xc9,0x23,0xeb,0xd8,0x7a,0xd7,0x7c,0x53,0x01,0x00,0x00, + 0x05,0x20,0x17,0x85,0xe1,0x78,0x64,0x92,0xa9,0x3d,0xec,0x9e,0xcb,0x1d,0x8b,0xd8,0xf3,0x07,0x80,0x01,0xcd,0x20,0x9c,0xc2,0x89,0x71,0xf0,0x25,0xb4,0x63,0xb6,0xbc,0x33,0xcc,0x00,0x00, + 0x05,0x20,0x17,0xa4,0x30,0xe4,0x4a,0x75,0x42,0xbf,0x9c,0x7d,0x0c,0x3a,0xf2,0xa9,0x56,0x16,0xaf,0x31,0xaa,0xff,0x0e,0xfb,0xf0,0xab,0x75,0xe5,0x47,0x27,0xe5,0x98,0xdf,0x05,0x00,0x00, + 0x05,0x20,0x10,0x22,0x6f,0xfb,0xaf,0x57,0x48,0x5d,0x76,0xa7,0xab,0xe9,0xf7,0x9e,0x92,0xff,0x70,0xfd,0x5d,0x96,0x2f,0x13,0x47,0x9e,0x8b,0x92,0xa5,0x08,0x9d,0xdd,0x54,0x64,0x00,0x00, + 0x05,0x20,0x10,0x5a,0x57,0xc4,0x1e,0x8b,0x95,0xda,0xfb,0x3c,0x14,0x50,0x58,0x52,0x77,0xfa,0x2d,0x66,0xda,0xc1,0x58,0xb3,0x9e,0xcc,0xac,0x87,0x16,0xa5,0x0d,0x3e,0x97,0x4c,0x00,0x00, + 0x05,0x20,0x10,0xec,0xff,0xbe,0xe2,0x82,0x24,0xe2,0x4f,0x8a,0x58,0x11,0xc9,0xcc,0x8c,0x24,0x92,0xea,0xd1,0x9f,0xcc,0x04,0xfd,0x2c,0x22,0xc3,0x6c,0x47,0x2f,0x6a,0x81,0x5a,0x00,0x00, + 0x05,0x20,0x12,0x2d,0x54,0x32,0x72,0xfe,0x72,0xec,0x45,0x4d,0x3a,0xdd,0x66,0x64,0xfb,0xeb,0x33,0x7e,0x09,0x74,0x87,0xe9,0x81,0x5b,0x65,0x28,0x84,0xaa,0x3a,0xbc,0x9a,0x53,0x00,0x00, + 0x05,0x20,0x13,0x0a,0x6b,0xd1,0x72,0x99,0xbb,0x38,0xb5,0x8c,0x94,0x93,0x51,0xc6,0x1d,0x27,0xe6,0x08,0x16,0x60,0xf2,0x5f,0x44,0x43,0x20,0x54,0x28,0x91,0x8c,0xeb,0x4c,0xb8,0x00,0x00, + 0x05,0x20,0x14,0x06,0x52,0xae,0x46,0x68,0xa4,0xbd,0xe1,0xed,0xb0,0xc5,0xe1,0x8e,0xc3,0x71,0x2b,0xfc,0x88,0x69,0x91,0x06,0x37,0xaf,0x2f,0xd6,0x27,0x73,0xb3,0xb6,0x51,0x50,0x00,0x00, + 0x05,0x20,0x14,0x90,0x45,0xb0,0x89,0x15,0x9a,0xe4,0xf8,0x69,0x9f,0xdc,0xee,0xbb,0x80,0x64,0x5f,0xe7,0xdd,0xf9,0xa9,0x4c,0xf3,0x84,0xb8,0x91,0x7e,0xbb,0x0f,0xfb,0x41,0xb8,0x00,0x00, + 0x05,0x20,0x15,0xcb,0x74,0xf3,0x56,0x0b,0xaf,0x35,0x59,0x49,0xa0,0x15,0x12,0x13,0x9d,0xb8,0x8a,0x36,0x4c,0xe4,0x57,0x11,0xf8,0x5e,0x34,0xcf,0x92,0xfc,0x14,0xbe,0x93,0xa9,0x00,0x00, + 0x05,0x20,0x16,0x39,0x60,0x30,0xe7,0x4c,0x0d,0xf0,0x30,0x0d,0xb9,0x10,0x56,0xed,0x2c,0x24,0xb4,0x96,0xd0,0x02,0x9d,0x53,0x3b,0xba,0xa1,0x84,0x13,0xeb,0xfb,0x35,0x24,0x02,0x00,0x00, + 0x05,0x20,0x16,0x41,0x1b,0xa8,0x8c,0x2b,0x4f,0xd6,0xbe,0x1b,0x4d,0x4c,0x40,0x03,0x06,0xce,0x9f,0xb1,0xb5,0x8d,0x99,0xa9,0xb6,0xa7,0x3e,0xe1,0x1d,0xd2,0xe6,0x95,0xd4,0x42,0x00,0x00, + 0x05,0x20,0x16,0x63,0xeb,0xc7,0x41,0xf3,0x2e,0x65,0x61,0x9e,0x2a,0x40,0x12,0x19,0x39,0x30,0x91,0x78,0x70,0x09,0x11,0x89,0x7b,0xdb,0x4c,0x3c,0xa9,0x4d,0xd2,0xa7,0x3d,0xcc,0x00,0x00, + 0x05,0x20,0x1f,0x08,0xff,0xf7,0x83,0x1c,0x25,0xcb,0xdc,0x67,0x51,0xaf,0x99,0x4b,0x80,0xfb,0x02,0x50,0x6b,0x64,0x05,0x58,0xc6,0x98,0xe6,0x4c,0x88,0x56,0xe4,0x4a,0x9f,0xb1,0x00,0x00, + 0x05,0x20,0x1f,0x86,0xd2,0xa0,0xa0,0xb2,0xf2,0x59,0xea,0x06,0xae,0x9e,0x60,0xe8,0xff,0x19,0x15,0x7f,0xc7,0x85,0x4b,0xfd,0x57,0x1b,0x7a,0x3c,0x1f,0x14,0x63,0xde,0x7d,0x94,0x00,0x00, + 0x05,0x20,0x18,0x31,0xb3,0x9a,0xf8,0x8c,0xec,0x99,0x2e,0x7d,0xe4,0x90,0xa2,0x54,0x27,0xbd,0xe5,0xc8,0x65,0xdf,0x1f,0xaa,0x8f,0xe9,0x0f,0x64,0x85,0x09,0xc3,0x70,0x62,0x13,0x00,0x00, + 0x05,0x20,0x18,0xe1,0xf3,0xc1,0x17,0x5f,0xf5,0x0b,0xbd,0xf8,0x5c,0x6c,0xd6,0x23,0xbf,0xca,0xcd,0x48,0x44,0x56,0x4d,0x22,0x5f,0x33,0x15,0xb4,0x19,0x30,0xed,0x7a,0x2f,0x12,0x00,0x00, + 0x05,0x20,0x18,0xe7,0x40,0x30,0x6e,0xc3,0x64,0x0e,0x47,0xbc,0xdb,0xe4,0x49,0x9e,0x9c,0xc1,0x8b,0x4b,0x54,0x42,0xf9,0x66,0xb0,0xeb,0x80,0x56,0x9b,0xbe,0x99,0xac,0x22,0x8e,0x00,0x00, + 0x05,0x20,0x1b,0x08,0x3f,0x11,0x7a,0x3f,0x7c,0x9e,0xa9,0xae,0xfd,0xdc,0x20,0x2d,0x3e,0x57,0xc8,0x77,0x4b,0x11,0xd1,0x43,0x61,0x45,0x5d,0xc1,0x7d,0xa1,0x6c,0x83,0x13,0x87,0x00,0x00, + 0x05,0x20,0x1b,0x87,0xe8,0xa4,0x44,0x5b,0x92,0x51,0x27,0x18,0x04,0xa1,0x21,0x18,0x04,0xed,0xab,0x14,0x46,0x9a,0x2d,0x86,0xe3,0x7b,0x6f,0xbd,0x55,0x76,0x51,0xa4,0x95,0x9d,0x00,0x00, + 0x05,0x20,0x1b,0xb3,0xa1,0x8e,0x8b,0xc0,0xc7,0x14,0x51,0x9f,0x55,0x54,0x12,0xb2,0x49,0xf7,0x43,0xf1,0xea,0x74,0x6c,0x53,0xe5,0x63,0x27,0xc9,0xa4,0x15,0x03,0xd8,0x5c,0x9b,0x00,0x00, + 0x05,0x20,0x1c,0x91,0xef,0xae,0x13,0xdc,0xfd,0x43,0xaa,0x18,0x7c,0xd6,0xd0,0x20,0x3b,0x48,0x37,0x8d,0x3b,0x7a,0xa3,0x2c,0x20,0xae,0x8b,0x96,0x80,0x87,0x64,0xba,0x81,0x75,0x00,0x00, + 0x05,0x20,0x1d,0x11,0x5b,0xb6,0x2f,0x2a,0xee,0xfb,0x03,0x4d,0x1f,0x68,0x84,0xb4,0x6b,0x2d,0x1f,0x01,0xbe,0x9e,0x37,0xc5,0xcb,0x35,0x97,0x2a,0xf5,0x46,0x88,0x95,0x93,0x85,0x00,0x00, + 0x05,0x20,0x1d,0xbe,0xe7,0x55,0xfc,0xe2,0x9a,0x78,0xa1,0x48,0xa9,0x59,0x3d,0x9e,0x5a,0x5e,0x75,0x38,0xad,0xe1,0xfd,0xdd,0x49,0xf8,0x6b,0x43,0x4a,0xdc,0xdc,0x80,0x16,0xe4,0x00,0x00, + 0x05,0x20,0x1e,0x34,0x23,0xf8,0x0c,0xde,0xab,0x87,0x04,0x14,0xba,0x2b,0xca,0x94,0x71,0x42,0x73,0x93,0xe8,0x1b,0xa8,0x28,0xc0,0x01,0x0f,0xd7,0x59,0xb3,0x3a,0x4c,0xbb,0x98,0x00,0x00, + 0x05,0x20,0x1e,0x4b,0x05,0x83,0x7f,0x43,0x79,0x77,0x9b,0x6f,0x07,0x01,0x42,0x28,0x5c,0xab,0xd3,0x3f,0x3c,0x1f,0xe6,0x4a,0x3d,0xc4,0xe8,0x25,0xb4,0x9a,0x44,0xa5,0x57,0x81,0x00,0x00, + 0x05,0x20,0x1e,0x55,0x2c,0x8d,0x16,0x86,0xeb,0x12,0x4f,0x30,0x44,0xe0,0x00,0x86,0xf1,0x1d,0x77,0xd4,0x4f,0x31,0xd8,0xd6,0x22,0xa6,0x4a,0xb7,0x78,0x4c,0x03,0xc2,0xb0,0xa6,0x00,0x00, + 0x05,0x20,0x26,0xa3,0x05,0xd0,0xdb,0x6d,0x89,0x25,0x9f,0x45,0xe1,0x0d,0x0e,0xa6,0x61,0x31,0x5e,0x5b,0xd5,0x36,0x4d,0xe7,0x7a,0x35,0x40,0xd2,0x13,0x2c,0x92,0x98,0x86,0xc8,0x00,0x00, + 0x05,0x20,0x27,0x7a,0xaf,0x5a,0x9c,0xf4,0x72,0xfe,0x3c,0xdd,0x7a,0xba,0xd7,0x98,0x31,0xde,0x73,0xce,0x84,0x5b,0x41,0xe7,0x9a,0x6a,0xe2,0xc1,0x3b,0x5b,0x37,0x23,0xc7,0xdf,0x00,0x00, + 0x05,0x20,0x27,0xa0,0xec,0x00,0x93,0x4e,0xf2,0x5e,0xa5,0x80,0xab,0x79,0xc0,0x56,0x49,0x1e,0x1b,0x7f,0x38,0x5e,0x5d,0xc6,0x6b,0x96,0x50,0xd0,0x61,0xbc,0xd0,0x9c,0x6e,0x09,0x00,0x00, + 0x05,0x20,0x20,0x90,0xe3,0xd3,0xad,0x87,0xeb,0x2a,0xd9,0x29,0x17,0x74,0x47,0xc9,0x54,0x57,0xfa,0x3d,0x71,0x02,0x11,0xb2,0xc3,0x87,0x31,0xb3,0x9b,0x6f,0x2e,0xfc,0x30,0xea,0x00,0x00, + 0x05,0x20,0x20,0xaf,0x9b,0xcf,0x36,0xc1,0x6d,0x56,0x77,0x18,0x02,0x02,0x2e,0xdb,0x74,0x47,0xbc,0x58,0xa3,0xa0,0xf3,0x3f,0x31,0xc9,0xd0,0x3d,0x1f,0x98,0x41,0xf2,0x65,0xdb,0x00,0x00, + 0x05,0x20,0x20,0xdd,0xeb,0x14,0x0e,0x8f,0xdc,0x0f,0x45,0x98,0x06,0x08,0x89,0x40,0x7f,0x51,0x5a,0x1c,0x65,0x6b,0x0e,0x25,0x5c,0xa1,0x27,0x64,0x94,0x6b,0xdc,0x69,0xb7,0xe6,0x00,0x00, + 0x05,0x20,0x21,0x53,0xaf,0x75,0x5c,0xab,0x7b,0x3d,0xd6,0x1b,0xad,0x1f,0xfc,0xa9,0x4e,0x07,0xc6,0xb8,0x06,0xcb,0x39,0xf1,0xf7,0xd6,0xe9,0x8c,0x16,0x86,0xed,0xba,0x3d,0x9d,0x00,0x00, + 0x05,0x20,0x21,0xb8,0x9f,0x16,0x6d,0xe0,0x54,0xea,0xde,0xeb,0x06,0x4c,0x7a,0x46,0x26,0x6c,0xed,0xa7,0xb3,0x36,0xa9,0x0c,0x56,0x85,0x7b,0x13,0x84,0x30,0x52,0x43,0x05,0x90,0x00,0x00, + 0x05,0x20,0x21,0xcc,0x80,0xf3,0x82,0xe1,0x9e,0xfe,0x39,0xcd,0x56,0xa6,0x18,0x9a,0x4d,0x97,0xb8,0x6b,0xe9,0x13,0xa5,0x77,0xcd,0x7b,0x33,0xaf,0xa8,0xd8,0xe2,0xf6,0x59,0xc6,0x00,0x00, + 0x05,0x20,0x22,0x61,0xbe,0x59,0xd3,0x44,0xd2,0xaf,0xbb,0xb7,0x65,0xc6,0xbb,0xfb,0x20,0x54,0x6e,0x23,0xda,0xd3,0x57,0x2a,0x63,0x3c,0xaf,0xbd,0xf4,0x00,0xe0,0x02,0x89,0xf5,0x00,0x00, + 0x05,0x20,0x22,0x91,0x0a,0x84,0x90,0x80,0x5a,0xbf,0x23,0x05,0xeb,0x4a,0xae,0x29,0x36,0x13,0x21,0xad,0xd8,0xe6,0x63,0xd4,0xfe,0x28,0x16,0x01,0xf0,0x6c,0xe7,0x7d,0x49,0x6c,0x00,0x00, + 0x05,0x20,0x23,0x99,0x78,0xb1,0x86,0x28,0xa0,0x28,0xff,0x33,0xf6,0x57,0x3c,0xd3,0x6b,0xd3,0xcc,0x4a,0xfe,0x43,0x61,0x52,0xc9,0x3f,0x4c,0x7f,0x45,0x69,0xef,0x1a,0xb1,0x6e,0x00,0x00, + 0x05,0x20,0x24,0x42,0x4c,0x6a,0x52,0xb5,0x9b,0xee,0x1a,0x91,0x1f,0xfd,0x87,0x51,0x35,0x6e,0x88,0x06,0x18,0xa5,0xe9,0xc1,0x28,0xa1,0xcc,0x34,0x3d,0xf7,0x08,0x6c,0xf7,0xcf,0x00,0x00, + 0x05,0x20,0x24,0xf1,0xf9,0x89,0x49,0xd1,0x05,0x14,0xa3,0x23,0x11,0x92,0x51,0x65,0x42,0xf5,0x98,0x00,0x8f,0xeb,0xb2,0xec,0xa1,0x69,0x6e,0x22,0xfa,0x9d,0xe3,0x30,0x04,0x01,0x00,0x00, + 0x05,0x20,0x25,0x02,0xc0,0xe5,0x5e,0x8c,0xdf,0x4d,0xd2,0x79,0xe0,0xa2,0x3b,0x55,0x9a,0x4e,0x3b,0xee,0x0b,0x16,0xb5,0xa3,0x6f,0x0f,0x3f,0x5e,0x94,0x5c,0xd4,0x08,0xc5,0x0e,0x00,0x00, + 0x05,0x20,0x25,0x32,0x0c,0xe6,0x7e,0x33,0x48,0x55,0x73,0x1c,0x0d,0xf9,0xcb,0x08,0xa6,0x65,0x02,0xb0,0xfb,0x92,0xe7,0x36,0x84,0x1f,0xb3,0xd0,0x70,0xf4,0x39,0x69,0xb7,0xa7,0x00,0x00, + 0x05,0x20,0x26,0x0b,0xe1,0xbb,0xec,0xd8,0xc8,0x20,0xe5,0xe2,0x8f,0x7c,0x18,0xa8,0x9d,0xbb,0x15,0x7b,0x3c,0x00,0xf3,0x8e,0x4b,0xc2,0xff,0x04,0xe1,0xef,0x88,0x92,0xb5,0x62,0x00,0x00, + 0x05,0x20,0x26,0x70,0xf1,0xb4,0xb9,0x79,0xcd,0x8d,0xf0,0x9d,0x55,0x19,0xaa,0xdc,0x5c,0x4a,0xb9,0x42,0x8b,0x75,0xc2,0xff,0x77,0xb6,0x32,0x38,0x50,0x65,0x4c,0xa0,0x3d,0x0c,0x00,0x00, + 0x05,0x20,0x28,0x51,0x9e,0x8f,0xb2,0xa3,0x9f,0xb7,0x10,0x48,0x98,0x7a,0x6b,0xe2,0x68,0x31,0x9c,0x64,0x54,0x5d,0xf0,0xb3,0x3c,0x07,0x5c,0xbd,0xd3,0x80,0x87,0xa6,0xb9,0x88,0x00,0x00, + 0x05,0x20,0x28,0x68,0x4a,0x09,0xce,0xab,0xe0,0x21,0xfd,0x5c,0x52,0xf2,0x52,0x15,0x6a,0x1d,0x21,0x48,0x06,0x6c,0x84,0x92,0x4b,0x3e,0xeb,0xde,0xd4,0xe3,0x20,0x0c,0x9c,0x8c,0x00,0x00, + 0x05,0x20,0x29,0x0d,0x28,0x48,0x0c,0xe7,0x76,0x89,0xa5,0x27,0x0d,0xc6,0xea,0x04,0x82,0xce,0x4b,0xf4,0x30,0x74,0x69,0x0d,0x27,0xa3,0x5d,0x21,0x51,0x2b,0x0a,0x30,0x60,0x8d,0x00,0x00, + 0x05,0x20,0x2a,0x17,0x65,0x6e,0xc3,0xac,0xc6,0x42,0x03,0xe7,0x32,0x16,0xbd,0x24,0x5e,0x64,0xda,0xa9,0x92,0x4c,0x7f,0x52,0x61,0x78,0xde,0x9c,0xe3,0xcb,0xf4,0x45,0xc6,0xc1,0x00,0x00, + 0x05,0x20,0x2a,0x5c,0xab,0x83,0x51,0x4b,0xba,0x4f,0xbe,0x24,0x78,0x03,0xb9,0x13,0x31,0xfa,0x11,0xf4,0x8a,0x82,0xcd,0x3c,0x75,0xcc,0xd5,0x18,0xd2,0x1b,0xbf,0xed,0x4b,0x4e,0x00,0x00, + 0x05,0x20,0x2a,0xb5,0xe5,0x94,0x2e,0xd1,0xde,0x53,0xb3,0x2a,0x6e,0xcc,0xcf,0x2a,0xe9,0x90,0xf5,0x61,0x4b,0x37,0xf0,0x22,0x1c,0xd7,0x79,0xd1,0x7e,0x2e,0x1e,0x5c,0x6a,0x88,0x00,0x00, + 0x05,0x20,0x2a,0x9f,0xcc,0x1b,0xe6,0x58,0x81,0xe0,0x20,0x41,0x20,0xbc,0xff,0x37,0x74,0x08,0x7f,0xd1,0x37,0x0b,0x44,0x68,0x2e,0xd9,0x74,0x16,0x64,0xc4,0x4f,0x6c,0x03,0x63,0x00,0x00, + 0x05,0x20,0x2b,0x28,0xe0,0xd8,0x48,0xc3,0xea,0x06,0xcb,0xe3,0xc5,0x9c,0x62,0x5f,0xd9,0x60,0x7e,0xb1,0xed,0x5f,0x36,0xf9,0x1b,0xa9,0xb6,0xa8,0x19,0xe4,0xa0,0x43,0x99,0xe8,0x00,0x00, + 0x05,0x20,0x2b,0x6c,0xd5,0xa9,0x25,0xc4,0x89,0x57,0x49,0x9b,0x92,0xae,0x5f,0x2d,0xa2,0xd0,0x3a,0x52,0xed,0x78,0xb5,0x69,0x29,0xa5,0x4f,0x40,0x7b,0xa2,0xf4,0xcf,0x8c,0xc9,0x00,0x00, + 0x05,0x20,0x2b,0x85,0xb7,0x2c,0x9b,0x09,0x65,0x7c,0xe7,0xd2,0xbd,0x0a,0xdb,0x64,0xf7,0xfe,0x84,0x84,0x89,0xde,0x71,0x0b,0x63,0x18,0xfe,0x07,0xd9,0x7f,0xab,0x13,0x0a,0xb6,0x00,0x00, + 0x05,0x20,0x2c,0x11,0x17,0x1d,0xd0,0x42,0xda,0xf5,0x3c,0xd2,0x8b,0x03,0x5d,0xfa,0x91,0x2a,0xf9,0x16,0x3c,0x33,0x00,0x71,0x1a,0x25,0x07,0x68,0xc0,0x49,0x73,0x8e,0xfe,0x33,0x00,0x00, + 0x05,0x20,0x2d,0x23,0x43,0x7a,0x5c,0x1a,0x42,0x86,0xb8,0x8e,0x11,0x81,0x3f,0x47,0x01,0x77,0xdf,0x5a,0xab,0x05,0xb6,0x43,0x76,0x1a,0x4d,0x1a,0x6e,0xcd,0x5d,0x7c,0x88,0x88,0x00,0x00, + 0x05,0x20,0x2d,0x26,0xf7,0x94,0x68,0xac,0x88,0xad,0xea,0x57,0xcd,0x18,0x26,0xb9,0x5d,0x7b,0xb2,0xc5,0x5d,0x98,0x0a,0x24,0x3e,0x69,0x80,0xcd,0xa6,0x34,0x3a,0xac,0x9d,0x96,0x00,0x00, + 0x05,0x20,0x2d,0x51,0x8a,0xe7,0xd0,0xb0,0x15,0x33,0x7a,0xab,0x9e,0x72,0x01,0xf1,0xd2,0x8d,0xc4,0x84,0x3e,0x95,0x23,0xe9,0xba,0xfb,0xc6,0xb7,0xd6,0xef,0xef,0xc2,0x71,0xc4,0x00,0x00, + 0x05,0x20,0x2d,0xdc,0x15,0xe0,0x08,0xa7,0xac,0x67,0x71,0x73,0xc8,0x37,0x34,0xd6,0x40,0xda,0x87,0x9c,0x1c,0x28,0x42,0x1a,0xb6,0x45,0x61,0xcc,0xe4,0x8b,0x04,0xac,0x42,0xef,0x00,0x00, + 0x05,0x20,0x36,0xbc,0x66,0xec,0xd2,0x5e,0x77,0x03,0x80,0x12,0x5d,0x2f,0x1c,0xe9,0x63,0x78,0x3a,0x33,0xc2,0xa1,0x15,0xa8,0xd6,0x5c,0x05,0x7d,0x83,0xd1,0x4f,0x86,0x3a,0xf4,0x00,0x00, + 0x05,0x20,0x37,0x41,0x83,0x9c,0x20,0x6a,0x1e,0x42,0x76,0xd8,0x21,0xea,0x59,0x17,0xa2,0xa4,0x1b,0xa1,0xa5,0x7e,0xbd,0x62,0x26,0x52,0xba,0x8f,0xe9,0x2f,0x32,0x22,0x5f,0xc6,0x00,0x00, + 0x05,0x20,0x37,0x71,0x92,0x9c,0x04,0x58,0x5a,0x68,0x6f,0x30,0x2b,0xe8,0x51,0xc5,0xed,0x9b,0xe1,0x1e,0xd2,0x2d,0x74,0xc8,0x0b,0xb1,0xb9,0x82,0x85,0x22,0xd2,0x12,0xec,0xab,0x00,0x00, + 0x05,0x20,0x37,0x8a,0x3f,0x86,0x9a,0x70,0x09,0xcd,0x8e,0x88,0xfe,0x73,0x6d,0xf1,0xbc,0xf8,0x5a,0x70,0xcf,0x6c,0x4b,0x94,0x50,0x24,0xbc,0xf6,0x4c,0x5f,0x4c,0x1f,0xb0,0x52,0x00,0x00, + 0x05,0x20,0x37,0xb3,0x5b,0xa8,0x74,0x1d,0x7c,0x90,0x34,0x6f,0x93,0x87,0xf0,0xf7,0x12,0xe2,0xba,0xe6,0x64,0x4c,0xd2,0x6b,0xd3,0x03,0x7b,0xc9,0x3d,0x5a,0x34,0xf0,0xa1,0x62,0x00,0x00, + 0x05,0x20,0x30,0x35,0xd7,0x00,0xf3,0xb9,0x81,0xaf,0xbd,0x84,0x11,0x37,0x26,0xd7,0x55,0x5b,0xc4,0x86,0x70,0xc8,0x9d,0x72,0x95,0xf3,0x4c,0x16,0xdd,0x75,0x1c,0x4b,0xb9,0x92,0x00,0x00, + 0x05,0x20,0x30,0xfb,0x1f,0x25,0xc1,0xc2,0x88,0xc9,0x07,0x61,0x22,0x1f,0xf5,0x00,0xe0,0x66,0xe7,0x82,0xc7,0x5b,0xb7,0xd7,0x15,0x26,0xae,0xde,0x40,0x68,0x98,0x31,0x33,0x53,0x00,0x00, + 0x05,0x20,0x31,0x0f,0x30,0x0b,0x9d,0x70,0x0c,0x7c,0xf7,0x98,0x7e,0x1c,0xf4,0x33,0xdc,0x64,0x17,0xf7,0x00,0x7a,0x0c,0x04,0xb5,0x83,0xfc,0x5f,0xa6,0x52,0x39,0x79,0x63,0x87,0x00,0x00, + 0x05,0x20,0x31,0x2a,0x7c,0x15,0x86,0x70,0x86,0x41,0xa0,0xae,0x7e,0x89,0xe1,0x1e,0x5b,0xb9,0x24,0x1d,0x8e,0x85,0x4b,0xed,0x69,0x43,0x07,0x49,0xfe,0xc2,0xfa,0x17,0xd6,0x93,0x00,0x00, + 0x05,0x20,0x31,0x41,0x19,0xda,0x3e,0x7a,0x83,0x9e,0x03,0x7d,0xf1,0xc8,0x4c,0xf3,0x7e,0x2d,0xba,0x86,0x72,0x67,0x43,0x11,0x32,0x4d,0xbe,0x90,0xe5,0x0e,0xf5,0xf1,0x0f,0xf9,0x00,0x00, + 0x05,0x20,0x31,0x4a,0xfe,0x3f,0xc6,0x92,0x5f,0x33,0x45,0x28,0xe8,0x59,0xf0,0xdf,0x01,0x68,0x20,0x29,0xa5,0xd2,0x60,0xe4,0xed,0x23,0x6f,0x24,0x1f,0x4b,0x58,0x69,0x19,0x33,0x00,0x00, + 0x05,0x20,0x31,0x71,0x2a,0xc9,0xda,0xa3,0x89,0x45,0x8b,0xf3,0xe0,0xd2,0xa3,0x3c,0x05,0xb8,0xd4,0xed,0xaa,0x3d,0x65,0x68,0x24,0x0d,0x01,0x32,0x41,0xa9,0x0b,0x60,0x70,0xfb,0x00,0x00, + 0x05,0x20,0x31,0xe8,0x5e,0xef,0x1b,0x1d,0xc6,0xdb,0x99,0x29,0xb8,0x25,0x3e,0xf9,0x22,0x92,0x5c,0x77,0x5c,0xa5,0x17,0x3a,0xc0,0xdf,0xb6,0xad,0xf5,0xb6,0x4f,0xd0,0xf3,0x55,0x00,0x00, + 0x05,0x20,0x31,0xea,0xc7,0x60,0xe4,0x7f,0x24,0x0c,0x1c,0xc4,0x6f,0xc5,0xa7,0x88,0xdd,0xff,0x40,0x84,0x1e,0x36,0x58,0x9a,0x66,0x7d,0x77,0xbc,0x26,0x1c,0x30,0x26,0x62,0x0e,0x00,0x00, + 0x05,0x20,0x31,0xeb,0x72,0x98,0xc7,0xf0,0x4f,0x4e,0x41,0x90,0x51,0x1f,0x48,0x80,0xaf,0xad,0x60,0xc0,0x07,0xbb,0xe6,0x64,0x1a,0xf2,0x11,0xcf,0x6f,0xe7,0xcf,0xd6,0x31,0x69,0x00,0x00, + 0x05,0x20,0x33,0x07,0x85,0x63,0x5f,0xff,0x7d,0x71,0xf0,0x62,0x56,0x3f,0xbe,0x2a,0x90,0x43,0x92,0x6b,0x0c,0x27,0x05,0x73,0xe7,0x53,0xfb,0x1b,0xd4,0x6d,0x5c,0xf6,0x4c,0x65,0x00,0x00, + 0x05,0x20,0x33,0x24,0xaf,0x44,0xfc,0xc0,0x39,0x09,0xc9,0xa8,0xa6,0xa8,0x72,0x1e,0xe0,0xad,0xc1,0x12,0xb0,0x8e,0x48,0x49,0xf9,0x05,0x3a,0xd3,0x9f,0x0f,0x1b,0x51,0x93,0x0e,0x00,0x00, + 0x05,0x20,0x34,0x09,0x15,0xf4,0x2f,0xf0,0x63,0x04,0x2b,0x8f,0xb8,0x0d,0x65,0x8c,0x3e,0x1e,0xa5,0x8e,0x91,0xa1,0xb8,0x2b,0xfc,0x68,0x1c,0x9c,0xcc,0x41,0x65,0x6a,0xf0,0xf3,0x00,0x00, + 0x05,0x20,0x34,0x40,0x29,0x1f,0x84,0x29,0x0c,0x8e,0xf0,0xd2,0x61,0xa0,0xfa,0xaa,0x0f,0x64,0x2f,0x46,0x46,0xda,0x3b,0x53,0x47,0x52,0xa0,0xb1,0xb5,0xc3,0xaf,0xe5,0x28,0x48,0x00,0x00, + 0x05,0x20,0x34,0xf7,0x6d,0x2f,0x85,0x19,0xfb,0x78,0x6e,0xb3,0x11,0xb3,0xa8,0x47,0xdc,0x5d,0xfd,0x64,0x6b,0x30,0x34,0x6e,0x9a,0x7c,0x77,0x8c,0x5c,0x44,0x91,0x8d,0xe5,0xfb,0x00,0x00, + 0x05,0x20,0x36,0x01,0xd8,0x24,0x8a,0x42,0xf8,0x52,0x66,0x81,0xef,0xf3,0xfd,0xbe,0xc2,0x14,0xa4,0x75,0x4d,0xd3,0xd0,0x5b,0x1f,0xd8,0x4a,0x3b,0x02,0x5b,0x5f,0xac,0xcb,0x12,0x00,0x00, + 0x05,0x20,0x36,0x06,0x4d,0x39,0xed,0x38,0xf7,0x6a,0xd8,0x0b,0x04,0xa8,0x6b,0xb0,0x8b,0x51,0xc7,0xb2,0xfe,0x72,0x24,0xb1,0x43,0xbd,0xee,0xfc,0x83,0x9c,0xf6,0xd2,0x01,0x19,0x00,0x00, + 0x05,0x20,0x3f,0x2f,0xca,0x47,0x8b,0x8f,0x62,0x29,0x3d,0xa4,0x6b,0x33,0x8f,0x23,0xaf,0x06,0xc9,0xb7,0x8e,0x72,0xc5,0x5a,0x52,0xf6,0x9d,0x59,0xf7,0x52,0x0e,0xbe,0xdc,0x2b,0x00,0x00, + 0x05,0x20,0x3f,0x31,0x2b,0x5e,0x2c,0x5b,0x08,0xfe,0x33,0x70,0xa7,0x0a,0xff,0x38,0x7a,0x7f,0xd6,0x87,0x38,0x6c,0x4b,0xf9,0x98,0xa1,0xf7,0x79,0xfe,0x12,0xd5,0x98,0xdf,0x16,0x00,0x00, + 0x05,0x20,0x3f,0x62,0x15,0xfd,0x73,0xa2,0x2a,0x8f,0x1a,0xfc,0x43,0x9f,0xc4,0x09,0x2f,0xaa,0x9f,0xa8,0xcd,0x9e,0x9b,0x6c,0x41,0x8d,0x51,0x82,0x82,0x2b,0x2c,0x67,0xce,0xfb,0x00,0x00, + 0x05,0x20,0x3f,0xb7,0x18,0x20,0xad,0x99,0x1a,0x9f,0x4d,0x13,0xc1,0x9c,0xd6,0x9b,0x7f,0xf3,0xaa,0x05,0xf6,0xa6,0x7e,0x8d,0x3c,0xff,0x54,0xa6,0x6e,0x5c,0xa7,0x1f,0x36,0xb9,0x00,0x00, + 0x05,0x20,0x38,0xab,0xdc,0xa3,0x2b,0x88,0xc8,0xc0,0x14,0x44,0xcd,0xb2,0x23,0xd3,0xea,0x5e,0x06,0x18,0xc2,0x94,0x9b,0x07,0x58,0xf6,0xb6,0x00,0x2c,0x31,0x3c,0x56,0x75,0x31,0x00,0x00, + 0x05,0x20,0x39,0x83,0xb4,0xd5,0x79,0xbe,0x97,0x08,0x9a,0xd2,0x3e,0x55,0x98,0x08,0xf6,0xda,0x99,0x61,0xad,0xe0,0x67,0x71,0xe4,0xfa,0xcb,0xb0,0x13,0x07,0x6e,0x41,0x60,0xc2,0x00,0x00, + 0x05,0x20,0x39,0xda,0x47,0x48,0xe2,0x17,0xfc,0x70,0xf5,0xe0,0xed,0x61,0xa7,0x9b,0xf5,0x07,0x2e,0x4d,0xa1,0x41,0x68,0x04,0x3c,0xd2,0x21,0xc8,0x47,0x2c,0x18,0x28,0x3a,0x10,0x00,0x00, + 0x05,0x20,0x3a,0x7c,0xa2,0xa5,0xfe,0xc5,0x24,0x4c,0xe2,0x54,0xa8,0x2e,0x46,0x8c,0xb5,0xd0,0x71,0x6d,0x12,0x2d,0x42,0xa9,0xe5,0xe6,0x65,0x50,0x3f,0xbf,0x1b,0xa8,0x07,0xe1,0x00,0x00, + 0x05,0x20,0x3a,0xf3,0xf5,0x67,0xef,0x51,0xfd,0x38,0xfc,0x34,0xc9,0x4c,0xdc,0x4a,0x36,0x69,0xd4,0x77,0xfd,0x94,0xff,0x8e,0x16,0x1f,0x4d,0x6f,0xc3,0xad,0x2f,0xb5,0x97,0x63,0x00,0x00, + 0x05,0x20,0x3b,0x59,0x10,0x07,0x28,0x72,0x2d,0x74,0xfb,0x88,0x3e,0xb7,0xf8,0xdc,0xba,0xc8,0x47,0x39,0x95,0xa3,0x41,0x1e,0xff,0xd5,0x0a,0x9e,0x92,0xa7,0x7d,0xd5,0xac,0x55,0x00,0x00, + 0x05,0x20,0x3b,0x6f,0x79,0x5f,0xf2,0x9d,0xf2,0x49,0x21,0x2e,0x2f,0x0a,0x68,0xf2,0xf7,0xc4,0xa8,0xd4,0x3d,0xa8,0xab,0x6e,0x2d,0xae,0x09,0xd2,0xc8,0x59,0x7d,0x5f,0x1c,0x0a,0x00,0x00, + 0x05,0x20,0x3b,0xc0,0xba,0x99,0x3f,0x29,0xf6,0x1c,0x7d,0xba,0xaf,0x8e,0x0d,0xc2,0x55,0xf1,0xeb,0xf8,0x17,0x89,0x13,0xab,0x32,0x18,0x30,0x5c,0xe6,0x69,0xbb,0x7b,0x28,0xbe,0x00,0x00, + 0x05,0x20,0x3d,0x40,0x56,0xba,0x7b,0xe6,0x3b,0x4c,0x0a,0x23,0x52,0xa8,0x4d,0x9a,0x2f,0x07,0x64,0xc4,0x3a,0x55,0x5e,0xda,0x77,0x11,0x10,0x57,0x83,0xe2,0x37,0x7a,0xee,0x1c,0x00,0x00, + 0x05,0x20,0x3d,0xdc,0x0a,0x1a,0xfb,0x65,0x9b,0x87,0x99,0x2a,0x66,0xf7,0x54,0x0c,0xcf,0xe5,0x67,0xe9,0x9d,0xe2,0x54,0x4a,0x08,0x14,0xc8,0x2e,0x1b,0xa0,0xe5,0x58,0x4b,0x0a,0x00,0x00, + 0x05,0x20,0x3d,0xed,0xe4,0x36,0x34,0xf0,0xa2,0x56,0x2a,0x88,0xe5,0xd2,0x9a,0x0a,0xc3,0x4f,0x5e,0x52,0x91,0x3d,0x51,0x3d,0xfc,0xe1,0xa1,0x37,0x8f,0x6d,0x84,0xd1,0x21,0xdd,0x00,0x00, + 0x05,0x20,0x3e,0x22,0xc1,0x92,0x00,0x2d,0x2b,0xed,0xe0,0x6d,0x41,0xe9,0x66,0xd0,0xe0,0x03,0x42,0xb4,0x4d,0x64,0x9d,0xbb,0xf8,0x53,0x98,0x99,0x94,0x6a,0x4b,0xa4,0x96,0x44,0x00,0x00, + 0x05,0x20,0x3e,0x2e,0xe3,0x3e,0xf1,0x7b,0x62,0x9c,0x49,0xc5,0xa7,0x0d,0x1e,0xa4,0x6f,0x99,0x67,0x64,0xa5,0x79,0xf4,0xcf,0x0b,0x90,0xb2,0x01,0x45,0x31,0x4f,0x47,0x15,0xed,0x00,0x00, + 0x05,0x20,0x46,0x95,0xbd,0x48,0x3b,0x2b,0x14,0x72,0x32,0x9a,0x36,0x59,0xf3,0xf1,0x9a,0xe5,0x02,0x23,0x40,0x6e,0x39,0xcd,0x0e,0x72,0x18,0x07,0xf2,0x15,0x44,0xd6,0xf3,0x28,0x00,0x00, + 0x05,0x20,0x46,0xaf,0xfd,0x27,0x4e,0x22,0x54,0xda,0x0c,0x83,0xbc,0x82,0x0b,0xaf,0xc0,0x64,0x3c,0x0f,0xbc,0xe8,0x2c,0xbd,0xb0,0x95,0xb5,0x6d,0x2f,0x72,0x8f,0x43,0x27,0xef,0x00,0x00, + 0x05,0x20,0x46,0xb1,0x7e,0xfa,0xad,0x92,0x04,0x06,0x33,0xad,0xcc,0xb2,0x3f,0x02,0x77,0x35,0xf1,0xa5,0xcd,0x34,0x2d,0x41,0xe4,0xa8,0xb4,0x49,0x23,0xb0,0x6d,0xee,0x48,0x92,0x00,0x00, + 0x05,0x20,0x47,0x04,0x40,0xbc,0xae,0x41,0x00,0xfc,0x7e,0x97,0x6e,0x3f,0x14,0xd5,0xb9,0xfa,0x57,0xf8,0xc2,0xbd,0xdc,0x8a,0xb3,0x03,0xbc,0x78,0x1e,0xbe,0x43,0x02,0x5f,0xc8,0x00,0x00, + 0x05,0x20,0x47,0xf0,0x67,0xba,0x42,0x01,0x5c,0x39,0x33,0x34,0x43,0xa7,0x4a,0x3f,0xf0,0x49,0xb0,0xa5,0xd7,0x73,0xa0,0x0f,0xa8,0xfe,0x39,0xa5,0xac,0xae,0x31,0x89,0x0f,0x27,0x00,0x00, + 0x05,0x20,0x41,0x7a,0xd8,0x8a,0x0d,0x4d,0x34,0x1c,0x76,0x3e,0x6e,0x99,0x76,0x18,0xd0,0xf6,0x6d,0xa8,0x0e,0x42,0x9a,0x76,0x41,0xbe,0x0c,0x4b,0x2b,0x05,0x79,0xa3,0x9a,0x80,0x00,0x00, + 0x05,0x20,0x41,0xc0,0x8b,0x7c,0xf2,0xf3,0x83,0x57,0xa7,0x84,0x3b,0xbd,0x88,0x00,0xc8,0xe1,0x05,0x42,0xf4,0x24,0x8f,0x8e,0xba,0xba,0x8f,0x8a,0x0b,0xcc,0x96,0xf1,0xfe,0x8c,0x00,0x00, + 0x05,0x20,0x42,0x3f,0x10,0x75,0x6e,0x87,0xdb,0x6e,0x6d,0x57,0x4c,0xe3,0xe9,0x8c,0xe5,0xf0,0x97,0x59,0xb4,0xb0,0x80,0x26,0xd0,0x67,0x4c,0x9c,0x7c,0xf2,0xf4,0xf8,0x22,0xc3,0x00,0x00, + 0x05,0x20,0x42,0xe5,0x76,0x3b,0x0d,0x19,0x2d,0xc2,0x0f,0x46,0x32,0xcb,0xd6,0x06,0xce,0x77,0x2c,0x4e,0xce,0x7e,0x83,0x1f,0xc5,0x66,0xb9,0xc6,0x6b,0x62,0x57,0x48,0x91,0x7f,0x00,0x00, + 0x05,0x20,0x43,0x6d,0x2a,0x90,0xa2,0xbc,0xb2,0x72,0x45,0x3e,0x0d,0xdb,0xf7,0x53,0xf2,0xac,0x91,0x39,0xe3,0x5d,0xf6,0xfe,0x7c,0xf1,0x05,0xc3,0x7f,0x7c,0xc4,0x27,0xff,0x27,0x00,0x00, + 0x05,0x20,0x45,0x03,0xaa,0xf8,0xf8,0x33,0x79,0x96,0xb7,0x7c,0x6d,0xb5,0x9a,0x20,0xf4,0x78,0xb3,0x11,0x3d,0xa8,0x86,0x82,0x34,0x2e,0xb2,0x5a,0xc6,0xb9,0x50,0x45,0x8c,0x60,0x00,0x00, + 0x05,0x20,0x45,0xce,0x60,0x59,0xef,0xe8,0x1b,0x15,0xda,0xf7,0x31,0x68,0xde,0x65,0x7b,0x67,0x6e,0x75,0xdc,0x12,0x94,0xb2,0xd1,0x3c,0xfc,0x47,0x09,0xe0,0x61,0x81,0xe9,0x61,0x00,0x00, + 0x05,0x20,0x4e,0xb5,0xd6,0xc5,0x8d,0x1d,0xaa,0x84,0x1d,0xe4,0xfa,0x03,0xe6,0x33,0xa7,0xfe,0xb6,0x23,0x7b,0x56,0x88,0x7f,0x56,0xd9,0xc5,0x73,0xeb,0xcf,0xea,0x84,0xde,0x6c,0x00,0x00, + 0x05,0x20,0x4e,0xbc,0x67,0x80,0x0d,0xe8,0x02,0xb0,0xf7,0xca,0xe4,0x66,0x12,0x01,0x95,0xda,0x0e,0x3e,0x54,0x79,0x1d,0x7f,0xc1,0xdb,0x8a,0x51,0x2b,0x78,0xd0,0x0f,0xb0,0x23,0x00,0x00, + 0x05,0x20,0x49,0xfe,0x4a,0xf0,0x1d,0xc9,0x72,0xc2,0x60,0x8a,0x43,0x4f,0x30,0xc0,0xa8,0xf0,0xbf,0x73,0xd4,0x5c,0x64,0x86,0xfc,0x23,0xdf,0x4e,0xe5,0x75,0xfa,0x3c,0xe5,0x15,0x00,0x00, + 0x05,0x20,0x49,0xee,0x7b,0x15,0x10,0xc4,0xa2,0x9e,0x8d,0x0f,0x0c,0xc6,0xe5,0x20,0xba,0xe8,0x0f,0x24,0xff,0xa0,0x98,0xe1,0x10,0xad,0xd8,0xef,0xb8,0xc2,0x75,0x77,0x20,0x06,0x00,0x00, + 0x05,0x20,0x4a,0xa5,0x9b,0xfb,0xd5,0x70,0x14,0xf0,0x7f,0x44,0x29,0x54,0x9d,0x5e,0xe9,0x6f,0x20,0x65,0xc9,0x03,0xb1,0x12,0xcb,0xb9,0x90,0xc0,0x8f,0x56,0xe1,0xe6,0x87,0xca,0x00,0x00, + 0x05,0x20,0x4a,0xf9,0x58,0xf5,0x40,0x17,0xda,0x9c,0x2e,0x68,0xab,0x7f,0x49,0xf4,0x05,0xc4,0x3a,0x87,0xe4,0x5d,0xb3,0xae,0xbe,0x77,0x5b,0x23,0x1c,0x3b,0xa2,0xe2,0x46,0xf3,0x00,0x00, + 0x05,0x20,0x4a,0xc5,0x98,0x67,0xad,0x42,0xd7,0xba,0xc8,0x41,0x4d,0xf8,0x92,0xb3,0xae,0x35,0xc6,0xad,0x97,0x2d,0xac,0xa5,0x89,0xe5,0x20,0x6b,0xb5,0x43,0x91,0x9c,0xb5,0x62,0x00,0x00, + 0x05,0x20,0x4b,0x47,0x1e,0xa3,0x90,0x3d,0xe5,0xe0,0x03,0x41,0x85,0x68,0x58,0x9a,0x73,0x87,0x88,0xd0,0x57,0x06,0x3a,0x3b,0xc1,0xc0,0xb4,0x55,0x35,0x06,0xca,0x63,0x80,0x3a,0x00,0x00, + 0x05,0x20,0x4b,0xe2,0xb3,0x6d,0xd6,0x9e,0xfe,0x6a,0x04,0xfb,0xdc,0x34,0x75,0xe7,0x4a,0xbe,0xf9,0x51,0xde,0x9c,0xf7,0x1f,0xd7,0xc0,0x1c,0xc1,0xec,0x02,0xdd,0xaf,0xa3,0xd8,0x00,0x00, + 0x05,0x20,0x4c,0x49,0x19,0xed,0xda,0x89,0xc2,0xa7,0xc2,0x98,0x0d,0x8d,0xf9,0xc3,0x81,0x1d,0x57,0x72,0x1f,0xcb,0x6a,0xc5,0x1e,0x8c,0x64,0xba,0xa8,0x6a,0x55,0x1a,0x5e,0x9f,0x00,0x00, + 0x05,0x20,0x4c,0x4d,0x95,0x39,0xe8,0xeb,0xe1,0x36,0x87,0x96,0x23,0xbf,0x89,0xa3,0x48,0x33,0x3e,0x6d,0x11,0xa4,0xe0,0x0c,0x6c,0x8c,0x51,0x8a,0x6e,0xb3,0x6d,0xab,0x6f,0xe2,0x00,0x00, + 0x05,0x20,0x4c,0x6a,0x6d,0x6a,0xf5,0x0b,0x13,0x88,0xaa,0x06,0xfb,0x23,0xed,0x6b,0x27,0x68,0xc1,0xb4,0x26,0x74,0x07,0xba,0x28,0x34,0xd6,0x8d,0x48,0xdf,0xc8,0xbd,0xc8,0xff,0x00,0x00, + 0x05,0x20,0x4c,0x8d,0xc1,0xca,0xf5,0x32,0x45,0x0c,0xec,0x5a,0x81,0xa7,0x64,0x71,0x0f,0xda,0xf8,0xde,0x1d,0x77,0x70,0xc3,0x53,0x51,0x56,0x02,0x1f,0x81,0x59,0xda,0xf6,0x68,0x00,0x00, + 0x05,0x20,0x4c,0x93,0x4b,0x17,0x24,0x09,0x85,0x82,0x1e,0xa7,0xeb,0x37,0xb4,0x57,0xc3,0xf0,0x86,0xf7,0x28,0x80,0x51,0x4f,0xba,0xb6,0x50,0xab,0xe8,0x14,0x08,0x5f,0xdc,0x1a,0x00,0x00, + 0x05,0x20,0x4d,0x40,0xe3,0xef,0x62,0x78,0xb2,0xff,0x6b,0xcb,0x1d,0xa3,0xc0,0x64,0xfc,0x38,0x7a,0x24,0xb2,0xeb,0x0e,0x76,0x38,0x6c,0x57,0x44,0x86,0xbc,0xb7,0xf9,0xd7,0x49,0x00,0x00, + 0x05,0x20,0x4d,0xa0,0xba,0xc1,0x85,0xab,0x86,0xd8,0xc9,0x63,0x26,0x90,0x38,0x4f,0x5d,0x85,0xd1,0x8a,0x9a,0x03,0x5c,0x75,0x0e,0x51,0xc3,0xec,0xbc,0xb5,0x31,0x64,0x63,0xf0,0x00,0x00, + 0x05,0x20,0x4d,0xe1,0x84,0x64,0x9a,0x14,0xfc,0xc6,0x6d,0x35,0xae,0x41,0x56,0x6b,0x21,0x10,0xa4,0xe2,0x76,0x03,0xe1,0x15,0x07,0x7f,0x26,0x9f,0xfb,0x1c,0xe7,0x6c,0x6a,0x37,0x00,0x00, + 0x05,0x20,0x57,0x5d,0x86,0xfc,0xe8,0x33,0xe1,0x60,0x46,0x47,0xdd,0x14,0x33,0x32,0xfb,0xcf,0xa7,0x58,0x0a,0xc9,0xa7,0x2e,0x0b,0x44,0xc4,0xf0,0x01,0x2b,0x44,0x6d,0x73,0xb6,0x00,0x00, + 0x05,0x20,0x57,0x6a,0x98,0xaf,0x33,0xde,0xc6,0x75,0x6e,0xce,0x94,0x8a,0xde,0x8c,0x8f,0x65,0x71,0xd9,0xdc,0x28,0xab,0xeb,0x9d,0xda,0x3d,0xd3,0x00,0x04,0x24,0xd7,0x3e,0x67,0x00,0x00, + 0x05,0x20,0x50,0x41,0x61,0x20,0x98,0x22,0xed,0x64,0x4e,0x29,0x75,0xbb,0xbf,0xe5,0xec,0x1a,0x9a,0x2b,0x22,0x1c,0xd4,0x4e,0x93,0x03,0x16,0xeb,0xbf,0x4e,0xfb,0x4c,0x56,0xb6,0x00,0x00, + 0x05,0x20,0x51,0xef,0x1a,0x38,0x0e,0x67,0xd3,0x47,0x09,0x4a,0x76,0xa6,0x1b,0xc1,0xdb,0x0b,0x62,0x96,0x3a,0x09,0x38,0xdc,0x01,0xe3,0x78,0xc4,0x79,0x00,0x0b,0x3c,0x93,0x99,0x00,0x00, + 0x05,0x20,0x52,0xe4,0x04,0xf0,0xda,0x49,0xff,0x6f,0x9a,0xf6,0x14,0xda,0x85,0x4c,0xdb,0x3c,0x2d,0x27,0xb3,0xf9,0x5a,0xad,0x39,0x02,0xf6,0xe3,0x69,0xbe,0xa6,0x52,0x48,0x25,0x00,0x00, + 0x05,0x20,0x53,0x36,0x1e,0xa7,0xc2,0x84,0x45,0x02,0x58,0x6f,0xa5,0x48,0x80,0xbe,0x76,0xe9,0x8d,0x4b,0x2a,0x76,0x03,0x77,0xe4,0xad,0xd6,0xe5,0xf0,0xa7,0x9b,0x43,0x34,0x7c,0x00,0x00, + 0x05,0x20,0x53,0x8f,0xfe,0x2a,0xa1,0x29,0xa8,0x80,0x33,0x7b,0x2c,0x88,0x51,0xad,0x52,0xe9,0xe7,0x41,0x2a,0xa1,0xd9,0xf1,0xbf,0x54,0xe1,0x65,0x6c,0x78,0xc1,0x77,0x78,0x58,0x00,0x00, + 0x05,0x20,0x54,0xc8,0x41,0xaf,0x6a,0xf2,0xad,0xf5,0x19,0xbd,0x30,0x63,0x00,0x8d,0x77,0xab,0x20,0x13,0x20,0x13,0x05,0x1b,0x08,0xc2,0x6d,0x47,0xa9,0x6f,0xd3,0x0a,0x71,0x7d,0x00,0x00, + 0x05,0x20,0x55,0xb7,0x5f,0x1a,0x1d,0x91,0x18,0x69,0xf0,0xc6,0xf2,0x27,0x46,0x6e,0x13,0x06,0x16,0x06,0xe1,0xc5,0xfd,0x9b,0xe0,0xb4,0x2d,0x30,0xc8,0x1c,0x72,0xe8,0xbd,0x1c,0x00,0x00, + 0x05,0x20,0x5f,0x9d,0xd7,0x90,0xab,0x48,0x8d,0xa2,0x94,0x71,0x0d,0x41,0x3c,0x8b,0x7f,0x06,0x86,0xab,0xc5,0xa3,0xd7,0x73,0xfa,0xdd,0x48,0x66,0xa7,0xbc,0xb2,0x59,0xb4,0x8f,0x00,0x00, + 0x05,0x20,0x58,0xbb,0xc0,0x3b,0x4e,0xab,0x7c,0x0b,0x13,0x2b,0xf3,0x8c,0xfb,0x8f,0x77,0x02,0x89,0x6e,0x79,0xd3,0x1d,0x3f,0x45,0xe3,0xa0,0x34,0xc2,0x36,0x20,0xaa,0x33,0xf9,0x00,0x00, + 0x05,0x20,0x5a,0x29,0xfe,0x8a,0xaa,0x9d,0x78,0x81,0x04,0x53,0x37,0xf5,0x6f,0xb6,0xe1,0x57,0x08,0x80,0xcf,0xf6,0x03,0x11,0x92,0x8d,0x08,0xe3,0x99,0x9f,0x98,0x4a,0x27,0x6b,0x00,0x00, + 0x05,0x20,0x5a,0x9a,0x96,0x22,0xf6,0xad,0xf2,0xb0,0x6c,0x46,0xa8,0x7b,0x06,0x3c,0x24,0x3c,0x1e,0x52,0xae,0x89,0x10,0x1e,0xde,0xb0,0xea,0x55,0x3d,0xbb,0x80,0x06,0xb9,0xa4,0x00,0x00, + 0x05,0x20,0x5a,0xc1,0x5a,0x79,0xa7,0x36,0x9c,0xfa,0x81,0xfa,0x5e,0xfb,0x42,0xa3,0x5f,0xfe,0x7e,0x4b,0x6a,0xcd,0x99,0x1f,0x57,0x45,0xb4,0x05,0x79,0x3f,0x15,0x8f,0x61,0x72,0x00,0x00, + 0x05,0x20,0x5b,0x2e,0x80,0x3e,0x46,0x70,0x7a,0x08,0x24,0x9e,0x71,0x69,0xc6,0xbe,0xee,0x17,0x4c,0xd4,0xcc,0x25,0x19,0xb1,0x2e,0x88,0x81,0xe1,0xc3,0x21,0x3a,0x33,0x5e,0x71,0x00,0x00, + 0x05,0x20,0x5b,0xc8,0xa9,0xb9,0xb1,0xd5,0x30,0x87,0x1e,0x99,0x46,0xfb,0x23,0xcd,0x3b,0x70,0x01,0xff,0xc5,0x4b,0x64,0x24,0x8a,0xd3,0x03,0xba,0x85,0x75,0x10,0x1a,0x1d,0xa9,0x00,0x00, + 0x05,0x20,0x5c,0x40,0x7f,0x80,0x43,0x91,0x9c,0xfc,0x04,0xdc,0xdc,0x8e,0x01,0xda,0xc8,0xaf,0x90,0x62,0x64,0x16,0xf7,0x11,0xe4,0x87,0xac,0xa4,0x06,0x6f,0x8d,0x87,0x4e,0xd6,0x00,0x00, + 0x05,0x20,0x5c,0x4a,0x29,0xcb,0xf8,0x8d,0xa1,0xc8,0x4e,0x20,0x0a,0xf6,0x04,0x75,0x69,0xbb,0x4e,0x60,0xe4,0x1c,0x72,0x43,0xa7,0x29,0xb9,0x73,0x82,0x3a,0x8d,0xb9,0x3b,0xfd,0x00,0x00, + 0x05,0x20,0x5d,0x46,0x18,0x02,0xa6,0x1b,0x99,0xd3,0xf4,0x64,0x6d,0x94,0xc1,0xda,0x4b,0x2e,0x6e,0x25,0x17,0xc4,0x18,0xec,0x55,0x91,0x61,0x71,0xbf,0x33,0x3b,0x4c,0xfd,0x24,0x00,0x00, + 0x05,0x20,0x5d,0x93,0x10,0x3d,0x45,0x25,0xd3,0x84,0xc0,0xba,0x8c,0x47,0x1e,0x18,0xe7,0xbb,0x17,0x1d,0xa4,0x78,0x34,0x9c,0xd2,0x4c,0xd3,0x39,0x0c,0xba,0xb2,0x34,0xed,0xfd,0x00,0x00, + 0x05,0x20,0x5d,0xcf,0xc1,0xcb,0x26,0xb5,0x53,0x92,0xa5,0xf8,0xde,0x89,0x14,0x0c,0x2d,0xd6,0x2f,0x96,0x08,0x22,0x2c,0xbd,0x73,0x81,0x9f,0xd7,0xf5,0x11,0xec,0x6c,0x44,0xf0,0x00,0x00, + 0x05,0x20,0x5e,0x0d,0xaf,0x49,0x2a,0x15,0xfa,0x82,0x0f,0xa0,0xe0,0x3e,0x91,0xdd,0x85,0x23,0xd6,0x51,0x36,0x97,0xd9,0x69,0x7e,0xc6,0x57,0xca,0x99,0xd6,0x18,0x21,0x92,0xd7,0x00,0x00, + 0x05,0x20,0x5e,0x40,0xd1,0x09,0x74,0x77,0xd7,0x99,0x1b,0xb9,0xca,0xf0,0xe6,0x27,0x9c,0x20,0x03,0x0a,0xb9,0xe1,0xd7,0xea,0xb0,0xc8,0x11,0x31,0x26,0x90,0xa0,0x3f,0x91,0xc7,0x00,0x00, + 0x05,0x20,0x5e,0x62,0x6d,0xd4,0x84,0xdd,0x83,0x9f,0xc0,0x1a,0x1f,0x19,0x50,0x21,0x39,0x20,0x70,0xd3,0xdf,0x7d,0xf7,0xe2,0xf4,0x9c,0x75,0x20,0x48,0x4a,0x94,0xe5,0x8b,0xfc,0x00,0x00, + 0x05,0x20,0x60,0x70,0x5e,0x8f,0x75,0x3a,0xf0,0xa4,0xb2,0x0f,0x50,0xd1,0x6e,0x6a,0x4f,0x08,0x7f,0x4e,0x0b,0xf5,0xa7,0xd3,0x4a,0xcb,0x78,0x28,0x6c,0x08,0x4d,0x2d,0x83,0x7b,0x00,0x00, + 0x05,0x20,0x60,0x73,0xcb,0x60,0xa4,0x84,0xd6,0xb1,0x08,0x11,0xc6,0x85,0x10,0x2b,0x50,0x2b,0xaa,0xd0,0x43,0x5b,0xf7,0xaa,0x31,0x8e,0x2e,0xff,0x90,0x7b,0x88,0x00,0xa9,0x5f,0x00,0x00, + 0x05,0x20,0x60,0xaa,0xa1,0x92,0x7a,0xf5,0xf3,0x2c,0xf3,0xe7,0x5d,0x21,0xdc,0x98,0x18,0x66,0x13,0x5c,0xeb,0x3e,0x6a,0x24,0x2e,0x92,0x6c,0x6b,0xd4,0xea,0x0f,0x2a,0xc2,0xd1,0x00,0x00, + 0x05,0x20,0x64,0x2b,0x8c,0xfb,0x8b,0xc5,0xba,0xe5,0x0d,0xf2,0x2a,0x4a,0x52,0x80,0x34,0xed,0x34,0xb2,0x38,0x3e,0xa4,0xa0,0xc2,0x8f,0xa0,0x9f,0x48,0x00,0x7e,0x3b,0xf8,0xcb,0x00,0x00, + 0x05,0x20,0x65,0x89,0x53,0xf6,0x3d,0x1a,0xb2,0x31,0xad,0xda,0x72,0xfc,0x17,0x25,0xe3,0x1c,0xb6,0xa6,0xbb,0x97,0x83,0xb1,0xe7,0xfa,0x8b,0x40,0xf6,0xf0,0x01,0x86,0x8c,0xd6,0x00,0x00, + 0x05,0x20,0x65,0xb0,0x9c,0x8e,0x26,0x9e,0x1e,0x1b,0x27,0x14,0x5d,0xb8,0x82,0x92,0x64,0x4e,0x7d,0x7a,0x4a,0x12,0x9d,0x73,0x85,0xe6,0x72,0x79,0xde,0x6d,0x47,0x59,0x2f,0xe8,0x00,0x00, + 0x05,0x20,0x65,0xcc,0xb3,0x43,0xa8,0x17,0x23,0xa6,0x20,0xd3,0xa3,0x09,0xde,0x3a,0xc5,0xd3,0xd4,0xe5,0xa7,0x91,0xb4,0x4c,0xa5,0xd7,0xb0,0x90,0xfa,0x06,0x07,0xb5,0x62,0x32,0x00,0x00, + 0x05,0x20,0x6e,0xdf,0xd1,0xa9,0x1c,0xaa,0x92,0xca,0xc3,0xec,0x33,0xfa,0x12,0x1c,0x05,0x27,0x45,0x1a,0xaf,0xd0,0xeb,0xc8,0xa1,0x14,0x47,0x8d,0xb1,0x39,0x7c,0x7e,0x18,0x43,0x00,0x00, + 0x05,0x20,0x6e,0xee,0x4b,0xbf,0x4a,0x4d,0x45,0x08,0x8f,0xb7,0x93,0x0c,0xe1,0xbe,0x5a,0x41,0xeb,0x59,0x28,0x50,0x45,0x1e,0xbd,0x0d,0xd9,0x1e,0x43,0x1c,0x90,0x1e,0x4b,0x61,0x00,0x00, + 0x05,0x20,0x6f,0x4e,0x81,0xcb,0xfd,0xfb,0x4e,0x74,0xb3,0x84,0x2a,0x1a,0xd2,0xd4,0xc1,0xea,0x98,0x6b,0xda,0xb3,0xf0,0x06,0x60,0x9f,0xdc,0xe9,0xba,0x54,0x85,0xe7,0x11,0xff,0x00,0x00, + 0x05,0x20,0x6f,0xd2,0xe8,0xa1,0x8b,0x84,0x52,0x59,0x0c,0x32,0xad,0x9d,0x96,0x13,0xc4,0x40,0x9f,0x44,0x6f,0xbb,0x13,0xb6,0xe8,0x07,0x48,0xa3,0xca,0x4b,0x7a,0xcb,0x4b,0x53,0x00,0x00, + 0x05,0x20,0x68,0x1d,0x7f,0xe5,0xe0,0x32,0xb7,0x9d,0x64,0x51,0x13,0x63,0x56,0xa6,0x54,0x80,0x4c,0xc3,0xca,0x61,0xde,0x7a,0x6c,0xb5,0xed,0x1d,0xb6,0x75,0x87,0x97,0xee,0x40,0x00,0x00, + 0x05,0x20,0x68,0xb4,0x36,0xf9,0xa8,0x29,0x3e,0x92,0x30,0x41,0x50,0x97,0xb4,0x19,0xf8,0xb5,0x29,0x94,0x77,0xb2,0x9c,0x09,0x5d,0xca,0xa2,0x6b,0x68,0x9d,0x02,0x69,0x75,0x97,0x00,0x00, + 0x05,0x20,0x68,0xc7,0xb8,0x91,0x85,0xda,0x06,0x2e,0x7e,0x84,0xa6,0x1e,0x7d,0xec,0x44,0xd0,0xcd,0x0b,0x3d,0x11,0xb8,0x20,0xe6,0x54,0xda,0xd5,0x5b,0xf1,0x94,0xb6,0xd2,0xfc,0x00,0x00, + 0x05,0x20,0x68,0xe6,0xe4,0x77,0x65,0xcf,0xc9,0xe6,0x2f,0xd5,0xf2,0x5b,0xbd,0xfb,0xfd,0x6d,0x84,0x8b,0x7d,0x94,0xeb,0x24,0xdf,0x80,0xb9,0x09,0xc8,0x17,0xc6,0x92,0x81,0xbe,0x00,0x00, + 0x05,0x20,0x6a,0x1e,0x4a,0x9f,0xae,0x78,0x8d,0xf9,0x4e,0x4c,0x2f,0xb8,0x3a,0xcd,0x5d,0x0b,0x79,0xd7,0x44,0x4a,0x70,0x35,0x1d,0xf8,0xc2,0x6c,0xcb,0xd4,0x6c,0xf2,0xda,0x47,0x00,0x00, + 0x05,0x20,0x6a,0x93,0xac,0x80,0x29,0xe8,0x79,0x53,0xb9,0x63,0xde,0xdb,0x9d,0xa8,0xcf,0xd5,0xf6,0x8d,0x92,0x5a,0x5e,0xd1,0x9f,0x72,0x37,0xbf,0xc8,0xcf,0xc5,0x46,0xa0,0x41,0x00,0x00, + 0x05,0x20,0x6a,0xe9,0x69,0x19,0xe1,0x56,0xc4,0xf5,0x88,0x3a,0x2b,0xda,0x57,0xa6,0x27,0x74,0xf5,0x6f,0x83,0xcc,0x9a,0x4c,0x65,0x41,0x0a,0xa0,0xe4,0xfc,0x4a,0x0b,0x90,0x89,0x00,0x00, + 0x05,0x20,0x6b,0x34,0x3a,0x48,0xdb,0x7e,0x3f,0xf6,0x6b,0x62,0x8e,0xdb,0x3d,0x27,0x90,0xfd,0x15,0x6c,0xd6,0x06,0xaf,0x8f,0xed,0xf5,0xf6,0xe4,0x96,0x6b,0x59,0xf3,0x22,0x8a,0x00,0x00, + 0x05,0x20,0x6b,0xdc,0x57,0x84,0x31,0xa6,0x75,0x00,0x70,0x35,0x11,0xd6,0x05,0xef,0xdb,0x8e,0xe8,0x84,0x78,0xc9,0x61,0x8a,0xf1,0x76,0x31,0x21,0x83,0xa7,0x23,0xab,0x10,0x15,0x00,0x00, + 0x05,0x20,0x6c,0xde,0xd2,0xc7,0x42,0x65,0xf2,0xb6,0x4b,0x2d,0xa9,0x8b,0x5d,0xea,0x36,0xd3,0xc7,0x50,0xe7,0xec,0xbd,0x27,0xb0,0x99,0xe7,0x27,0x1d,0xae,0x0e,0x0b,0xa8,0xf8,0x00,0x00, + 0x05,0x20,0x6d,0x2c,0xf3,0xce,0x94,0x19,0x63,0x2b,0x20,0x72,0xd6,0xa0,0x98,0x7b,0x79,0x35,0xcf,0xdb,0x53,0xe4,0x88,0x0a,0xbd,0xf9,0x38,0x6a,0x29,0x73,0xe7,0xfd,0x42,0xb1,0x00,0x00, + 0x05,0x20,0x6d,0x8a,0x3b,0x2c,0x2b,0x3d,0x06,0xe6,0x6d,0xd0,0x26,0xf5,0x8c,0xe6,0x94,0x4e,0xa4,0x1d,0xfe,0x69,0xaa,0xd8,0x86,0x22,0x34,0xe0,0x9c,0x0c,0xa3,0xa5,0x89,0x09,0x00,0x00, + 0x05,0x20,0x6d,0xcf,0x2f,0xa8,0xff,0xd1,0xa6,0x4b,0xff,0x67,0x3d,0x3a,0x0f,0xcc,0xc9,0xa2,0xfb,0x96,0x7a,0x1f,0x1d,0xc8,0x98,0x15,0x75,0x1c,0x3c,0x17,0x43,0xc0,0xe3,0x11,0x00,0x00, + 0x05,0x20,0x6e,0x78,0xb8,0x7d,0xec,0x95,0x9a,0x60,0x12,0xb5,0xd5,0x21,0x80,0x21,0xb0,0xcd,0x26,0x5b,0xad,0x40,0xad,0xcc,0x32,0x6a,0xda,0x92,0xdd,0xa7,0xf8,0x9a,0x50,0x8b,0x00,0x00, + 0x05,0x20,0x76,0xa2,0x25,0x46,0x1f,0x49,0x12,0xaf,0x64,0xb7,0x85,0x37,0x92,0x0f,0xb5,0xc2,0x5f,0x00,0x19,0x5e,0x71,0xa1,0x27,0xc3,0xfe,0xf9,0x2a,0x01,0x12,0x3a,0x9d,0x81,0x00,0x00, + 0x05,0x20,0x77,0x26,0xa0,0x0f,0xf6,0x19,0x30,0x08,0x90,0xb4,0x25,0xb4,0x3d,0xe2,0x6f,0xb0,0xb9,0xd9,0xd9,0x42,0x07,0x6a,0xe0,0x99,0x03,0x3d,0x2b,0xe3,0xff,0x91,0xdc,0x8b,0x00,0x00, + 0x05,0x20,0x77,0x65,0xd4,0xec,0xc7,0x3a,0x3e,0x94,0x3e,0x43,0xe2,0x7a,0x91,0x07,0xf0,0x48,0x64,0x09,0xaa,0xd7,0x15,0x5d,0x33,0x25,0x38,0x34,0xc4,0x9d,0xad,0x00,0x4b,0xb0,0x00,0x00, + 0x05,0x20,0x70,0x1a,0xfe,0xcb,0x8e,0x5c,0xba,0x81,0xc5,0xeb,0x03,0x98,0xb5,0x25,0xde,0xbf,0x88,0x00,0x25,0x1a,0xb8,0x69,0xd5,0x35,0x6e,0xa5,0xc0,0x76,0x59,0x19,0x82,0x1f,0x00,0x00, + 0x05,0x20,0x70,0x30,0x29,0xb3,0xf5,0xbc,0xc0,0x66,0x8e,0xc0,0x7b,0x7b,0x27,0x26,0x16,0xd6,0xdc,0x33,0x37,0x2d,0xd8,0xb9,0xfc,0xae,0xc2,0xed,0xc0,0xb1,0x45,0xa5,0x2e,0x15,0x00,0x00, + 0x05,0x20,0x70,0xfd,0x70,0x0e,0xb5,0x5c,0x08,0x35,0xfe,0xa9,0x27,0x41,0x4a,0x39,0xfc,0x7b,0x6c,0x5d,0x79,0xe5,0x4f,0x3c,0xcb,0xde,0x82,0xac,0xf7,0xc8,0xaf,0xb7,0xeb,0xb8,0x00,0x00, + 0x05,0x20,0x70,0xd9,0xc7,0x5d,0xd9,0x63,0x0d,0xda,0x94,0xf9,0xf8,0xbf,0x55,0xbd,0xe8,0x50,0x75,0x2f,0xcf,0xd1,0x69,0xd5,0xd4,0x07,0x3d,0xa9,0x92,0x4f,0xb3,0x68,0x30,0xba,0x00,0x00, + 0x05,0x20,0x71,0x8c,0xdf,0x40,0x2f,0x60,0x40,0x6d,0x6b,0x86,0xa3,0x00,0x6c,0x99,0xae,0xee,0xd8,0x67,0x64,0x3e,0xec,0xdf,0x99,0xf5,0x64,0xca,0x42,0x50,0x85,0x10,0x56,0x39,0x00,0x00, + 0x05,0x20,0x71,0xde,0x08,0xc6,0x86,0xaa,0x74,0xb8,0x1d,0x23,0xee,0x8b,0xb0,0x8d,0x9b,0xb0,0x38,0xc6,0x13,0x5d,0x76,0x53,0x04,0xc0,0xc2,0x32,0x5b,0x4e,0x4a,0x56,0xc2,0x40,0x00,0x00, + 0x05,0x20,0x72,0x14,0x51,0x06,0xf4,0x36,0xf9,0x59,0x95,0xaa,0x2a,0xcf,0xe7,0x19,0xa2,0xbb,0xeb,0x99,0x75,0x39,0x29,0xc0,0x04,0x6b,0x97,0xa5,0x73,0x86,0x96,0x48,0xdc,0x97,0x00,0x00, + 0x05,0x20,0x72,0x29,0x23,0x1d,0xfb,0x56,0xf9,0xb7,0x16,0x58,0xb6,0xb0,0xcf,0x20,0x89,0xaa,0x32,0xda,0x2a,0xfd,0x5c,0x4e,0x02,0xdf,0x23,0x04,0x98,0x95,0x63,0x5c,0x45,0xc2,0x00,0x00, + 0x05,0x20,0x72,0x8b,0x72,0x38,0xfe,0x44,0xe9,0xc2,0xf4,0xbc,0xd8,0xce,0x1c,0xd5,0x50,0xb1,0x63,0x56,0x74,0x5e,0xf2,0xd3,0xe5,0xd5,0x29,0xe4,0x34,0x1d,0xf5,0x1c,0x7a,0xb9,0x00,0x00, + 0x05,0x20,0x73,0x14,0x85,0xbf,0xe4,0x1e,0x55,0xf2,0xbd,0x8c,0x5e,0x8b,0x85,0x82,0x3e,0xe3,0xc5,0xd7,0x28,0x17,0xa2,0x33,0x5f,0xcc,0xb0,0x56,0xa0,0xc9,0x14,0x6e,0x53,0xf8,0x00,0x00, + 0x05,0x20,0x74,0x72,0x72,0xac,0x9f,0xc1,0x1a,0x14,0x12,0x51,0x99,0xb7,0xf5,0xa9,0x78,0xa2,0x84,0x9c,0x24,0x55,0x28,0xe2,0xf5,0x6d,0xed,0x8c,0x64,0x79,0xaf,0xd2,0x18,0xa3,0x00,0x00, + 0x05,0x20,0x75,0x54,0x9c,0x2c,0x32,0x29,0x35,0xfe,0xf8,0x4f,0x79,0xf3,0x7d,0x66,0xa7,0x3b,0x26,0x12,0x4e,0x3d,0x12,0x3d,0x2b,0x33,0x03,0x80,0xba,0x89,0x81,0x30,0xbb,0x3e,0x00,0x00, + 0x05,0x20,0x75,0x89,0x75,0xd0,0x89,0x0e,0xc9,0x2c,0xdf,0x8f,0xd8,0x7d,0x9a,0x5f,0x06,0x34,0xaf,0x79,0xaa,0xe5,0x35,0xdd,0x85,0xa8,0x06,0x29,0x05,0x2d,0x84,0xc5,0x6b,0xd2,0x00,0x00, + 0x05,0x20,0x7e,0xe1,0x73,0xcd,0xd7,0x02,0x54,0xc9,0xfe,0x66,0x17,0xa5,0x3a,0xf7,0xac,0x92,0x09,0x51,0x77,0x7a,0xdc,0x67,0x19,0x22,0xd2,0x9d,0x66,0x5d,0xfd,0x16,0x47,0x07,0x00,0x00, + 0x05,0x20,0x7f,0x27,0x28,0x5a,0xa3,0x78,0x11,0x3a,0xac,0xc0,0xa2,0x4b,0x1d,0x33,0x50,0x0c,0x77,0xe8,0x22,0xd4,0x90,0x25,0xdc,0xa9,0x14,0x9f,0xed,0xab,0x24,0x4f,0xdc,0xa0,0x00,0x00, + 0x05,0x20,0x7f,0x97,0xc5,0x6f,0x0b,0xf1,0xd9,0x22,0x3f,0x92,0x3c,0x79,0xf6,0x92,0xf6,0xc8,0xfa,0xce,0x4f,0xe3,0x1e,0x7d,0x82,0x3d,0x7a,0x94,0x18,0xa4,0x0a,0xf5,0x28,0x42,0x00,0x00, + 0x05,0x20,0x79,0x23,0x63,0x95,0x6f,0x9b,0x12,0xaa,0x30,0xa1,0xd4,0x36,0xc9,0xde,0x0a,0xc9,0xd5,0x88,0x3f,0xfa,0xda,0xc2,0xbe,0x0a,0x7a,0xca,0x2a,0x7c,0x32,0x8f,0x54,0xe9,0x00,0x00, + 0x05,0x20,0x7a,0xc8,0x27,0x35,0xb4,0x50,0xe7,0xc2,0xbf,0xe2,0x48,0x92,0x7f,0x80,0xba,0x06,0xdb,0x99,0x35,0x45,0x82,0x4d,0x7d,0x4b,0xe9,0x0f,0x6f,0x83,0xc3,0x61,0xed,0xc0,0x00,0x00, + 0x05,0x20,0x7b,0x98,0xe1,0xe0,0xbb,0x6b,0x41,0x5f,0xe0,0x94,0xd5,0x25,0x19,0x1f,0x30,0xf8,0xea,0x38,0x02,0xd1,0x3b,0x81,0x4d,0xd2,0xeb,0x43,0x11,0x53,0xe3,0x9e,0x5b,0x01,0x00,0x00, + 0x05,0x20,0x7b,0xa8,0x45,0xdf,0x63,0x53,0xa0,0xde,0x8e,0xab,0x0e,0xaa,0x40,0x64,0xe8,0x42,0x9b,0x6a,0xce,0xa0,0x18,0x43,0x95,0x3e,0x2a,0xdb,0x59,0x55,0xf2,0xb0,0x78,0x98,0x00,0x00, + 0x05,0x20,0x7b,0xc9,0x9e,0xef,0x11,0x97,0x96,0x06,0xe2,0xb8,0xbd,0x2e,0x15,0xc2,0xe8,0xa5,0x4e,0xd8,0x56,0xb3,0x01,0x59,0x60,0x20,0x7a,0x51,0x9f,0xa1,0xdf,0x55,0xea,0x01,0x00,0x00, + 0x05,0x20,0x7c,0x1b,0x0b,0x5d,0x7f,0x4c,0xa2,0xe5,0x7e,0xa6,0x79,0x85,0x55,0xde,0xcb,0x51,0xbd,0x81,0x2a,0xfb,0xdb,0x76,0x6e,0x5c,0xbd,0x5d,0x68,0xd9,0xd9,0xbe,0xd8,0x7c,0x00,0x00, + 0x05,0x20,0x7c,0x1e,0x98,0xa5,0xb5,0x0c,0x57,0x9c,0xe5,0xb5,0xdc,0x5b,0xae,0x3d,0x45,0x23,0x2b,0xed,0x4a,0x83,0x1c,0x66,0x5e,0xab,0x37,0xba,0xf6,0x00,0x91,0x5d,0xb9,0x77,0x00,0x00, + 0x05,0x20,0x7c,0xf6,0x85,0x05,0x70,0xd6,0x26,0xe8,0x10,0x44,0x9d,0xc7,0x44,0x6c,0x97,0x16,0x24,0xd8,0x87,0x29,0xd4,0x6d,0x1e,0x40,0x37,0x84,0xd6,0x25,0x2e,0x4a,0x4b,0xba,0x00,0x00, + 0x05,0x20,0x7d,0x0e,0x49,0x44,0x50,0xeb,0x92,0x2a,0xbc,0x8d,0x1b,0xd3,0x5e,0x9d,0x1f,0x51,0x6f,0x5c,0x7b,0x87,0x5b,0xcc,0x27,0x28,0xb6,0x44,0x36,0x22,0x29,0xcc,0x3c,0x7c,0x00,0x00, + 0x05,0x20,0x7d,0x7c,0x6f,0xd1,0x0d,0xf7,0x77,0x12,0x44,0x68,0x45,0x46,0x69,0xb9,0x11,0x4d,0x5c,0xa4,0xba,0xc8,0xe0,0x76,0x5b,0x02,0x72,0xc8,0xd7,0x32,0x61,0xd2,0xda,0x34,0x00,0x00, + 0x05,0x20,0x7d,0x61,0x8a,0xb7,0x4b,0x7d,0x5c,0x4c,0x1c,0xc2,0x35,0x1a,0xe8,0x4c,0x93,0x54,0x54,0xff,0xf9,0x04,0x36,0x1c,0x84,0x68,0x05,0xe0,0xa2,0xd5,0xcd,0xde,0x30,0x75,0x00,0x00, + 0x05,0x20,0x7d,0xdb,0xe0,0x17,0x76,0xe3,0xfc,0x0a,0x19,0x6a,0x9a,0x09,0x45,0x52,0x5e,0xa6,0x73,0xa7,0x85,0xfa,0x26,0x01,0xc7,0x52,0xb1,0xfa,0xf2,0xbb,0x9f,0x46,0x8e,0x79,0x00,0x00, + 0x05,0x20,0x87,0x74,0x2d,0x93,0x04,0xd9,0xaa,0x02,0x3e,0x07,0xa7,0x3a,0xd9,0xf1,0x07,0x34,0x0b,0x4c,0xca,0x3d,0x39,0xfa,0xce,0xb4,0xd0,0x9c,0x4f,0x06,0x59,0x24,0x4a,0x5b,0x00,0x00, + 0x05,0x20,0x87,0xd8,0xd6,0x3c,0xcb,0xef,0x04,0x10,0x3a,0x24,0x68,0x94,0x0c,0x04,0xf6,0x69,0xfa,0xea,0xe0,0x0a,0x15,0x66,0x76,0x24,0x72,0x65,0x61,0x44,0x3f,0xa4,0x2f,0x1a,0x00,0x00, + 0x05,0x20,0x80,0xc6,0x6f,0xb3,0x18,0x5a,0x1a,0xde,0x4e,0xde,0x50,0xd2,0xc6,0x3f,0xc5,0x96,0x09,0x35,0x3a,0x4d,0x88,0x5f,0xa3,0x49,0x37,0xff,0xe6,0xc5,0x43,0x10,0xaf,0xa8,0x00,0x00, + 0x05,0x20,0x81,0x43,0x43,0x1c,0xb1,0xe9,0xce,0x67,0x39,0x80,0x96,0x2a,0x8b,0x2b,0x79,0x43,0x75,0xca,0x12,0x2f,0x5f,0xa9,0x1c,0xf6,0x4c,0xcd,0xc5,0xa1,0xa2,0xbd,0x45,0xee,0x00,0x00, + 0x05,0x20,0x82,0xa5,0x33,0xa3,0x30,0x99,0x46,0x94,0xdc,0x51,0x01,0xe1,0x75,0x2f,0x61,0x25,0x7f,0xd5,0x6b,0x81,0x58,0x0d,0x15,0x3a,0x59,0xb9,0x1b,0xce,0xe4,0x8b,0x42,0x5e,0x00,0x00, + 0x05,0x20,0x83,0x3d,0x52,0xc3,0x8f,0x2d,0x52,0x6d,0xc7,0x86,0xd6,0xae,0xa3,0x73,0xf7,0x17,0x07,0xac,0x74,0x5f,0x82,0xe4,0xe8,0x60,0xe5,0x7b,0xe5,0x53,0xec,0xd1,0x49,0x54,0x00,0x00, + 0x05,0x20,0x83,0x21,0x20,0xe0,0x1f,0xc1,0xde,0x35,0x1a,0xf8,0x84,0xf2,0x26,0x5c,0x09,0x41,0xc8,0x36,0xbf,0xd2,0x61,0xda,0x6b,0xfe,0x5a,0x6f,0x0d,0x7e,0xb2,0x91,0x9f,0xac,0x00,0x00, + 0x05,0x20,0x83,0x60,0xe4,0xae,0x67,0xc3,0x3f,0x9e,0x1a,0xc8,0xc8,0x82,0xb3,0xbc,0x7a,0x99,0xf1,0xfa,0xf0,0x1e,0x41,0x58,0x4e,0xfc,0x39,0xc2,0xf6,0xdb,0xe5,0x49,0xf2,0x04,0x00,0x00, + 0x05,0x20,0x83,0xc1,0xd6,0xbf,0xff,0x64,0x4c,0x96,0x30,0xe7,0xfe,0x83,0x04,0xb4,0xeb,0xbc,0x3a,0x94,0xec,0x0d,0x6c,0xce,0xe8,0x58,0x5f,0xd4,0xb3,0xfa,0x71,0x3c,0xca,0x8d,0x00,0x00, + 0x05,0x20,0x84,0x19,0x7a,0xd1,0x36,0x47,0x15,0x33,0x27,0x42,0xa4,0x19,0x6e,0x29,0x14,0x4a,0x8b,0xfa,0x2a,0x2a,0x71,0x3b,0x1c,0x63,0x81,0x48,0x7f,0x3c,0x2c,0x8f,0x5c,0x92,0x00,0x00, + 0x05,0x20,0x84,0x23,0x5c,0x0a,0x74,0x73,0x25,0x78,0x22,0x0a,0xb4,0xf2,0xf2,0xde,0x63,0x73,0xf3,0x11,0xc1,0x80,0xbb,0x6c,0xd3,0xb6,0x99,0xca,0xf4,0xb8,0x8c,0x56,0xf9,0x9e,0x00,0x00, + 0x05,0x20,0x85,0x82,0xc4,0xdc,0xcd,0xb3,0x51,0x34,0x37,0x5f,0x30,0x2d,0x3a,0x76,0xc4,0x46,0x02,0xee,0xb5,0xab,0x34,0xb9,0x38,0xc4,0xfd,0xaa,0x3b,0xad,0x74,0xa4,0xcb,0x11,0x00,0x00, + 0x05,0x20,0x85,0x8f,0x55,0xbe,0x27,0x56,0xdb,0x39,0x5a,0x3d,0xbb,0x66,0xd1,0x68,0xe7,0x33,0x2a,0x3d,0x84,0x26,0xc9,0x94,0x17,0x30,0x28,0x40,0x4f,0x19,0x27,0xea,0xf1,0xb1,0x00,0x00, + 0x05,0x20,0x85,0xa6,0xf6,0x1f,0xd2,0x93,0x54,0x47,0x59,0xc2,0x6d,0x57,0xfa,0x54,0x94,0x39,0x5c,0x33,0xcf,0x67,0x91,0xad,0x6c,0x0c,0xf8,0xdd,0x79,0x76,0x5a,0x01,0xb5,0x49,0x00,0x00, + 0x05,0x20,0x85,0xec,0x3d,0xb6,0x9c,0x52,0x05,0x6a,0x60,0xee,0x49,0x38,0x30,0x18,0x67,0x0a,0x0b,0xc0,0xdc,0x8c,0xe4,0x95,0xd2,0x4e,0xb5,0x41,0xb0,0x20,0x93,0xba,0x71,0x50,0x00,0x00, + 0x05,0x20,0x8f,0x8e,0x3d,0xa9,0xb0,0x46,0x9f,0xe5,0x02,0xdf,0x3e,0x03,0x11,0x17,0x50,0xea,0xc4,0x08,0xd1,0x62,0x16,0x65,0xb9,0x18,0x54,0xcf,0x30,0x2d,0x48,0x09,0xd9,0xb0,0x00,0x00, + 0x05,0x20,0x8f,0xc3,0x43,0x7a,0xc1,0x39,0x2b,0x08,0x2c,0x20,0xab,0xa8,0x9d,0x98,0xcf,0x07,0xc9,0xdf,0xc8,0x23,0xdb,0x91,0x55,0x66,0x04,0xc0,0x0d,0x19,0xde,0x47,0x62,0x5e,0x00,0x00, + 0x05,0x20,0x88,0x3f,0x99,0xc3,0xee,0x87,0xd2,0x27,0x65,0xf4,0x47,0xc5,0xcc,0xd7,0xfe,0x31,0xff,0x14,0xd8,0xf0,0xe9,0x54,0xfb,0xbf,0xe3,0xad,0xbf,0x14,0x4d,0x02,0x57,0xbd,0x00,0x00, + 0x05,0x20,0x88,0x7f,0x3c,0x24,0x7e,0x32,0x3e,0x4a,0xb2,0x7d,0x66,0x6b,0x30,0xba,0x20,0x64,0x10,0xfe,0x6e,0x47,0xfe,0xb2,0x9b,0xb6,0xc7,0x4f,0x55,0xfd,0x64,0xa8,0xd9,0xbc,0x00,0x00, + 0x05,0x20,0x88,0x44,0x8b,0x59,0xc8,0x63,0xb7,0x5e,0xf4,0x1f,0x6f,0x2e,0x1d,0x60,0xf8,0xb9,0x23,0x4a,0xe7,0x13,0xd0,0x86,0x52,0x34,0xdb,0x3e,0xc1,0x10,0x1a,0x1c,0x46,0x51,0x00,0x00, + 0x05,0x20,0x89,0x0a,0xee,0x57,0xfa,0xfa,0x58,0x52,0xfb,0x0b,0x8b,0xc2,0xaa,0x8f,0xa4,0x62,0xcb,0x1d,0x1c,0x0c,0x01,0x0f,0xfc,0x9d,0xde,0x75,0x40,0xbe,0x8d,0x8d,0xb2,0xe6,0x00,0x00, + 0x05,0x20,0x89,0x4d,0x24,0x9f,0x15,0x80,0x68,0xd2,0x17,0xa1,0xec,0x74,0x46,0x26,0x8e,0xbd,0xf4,0x8f,0xc4,0x52,0x5f,0xcc,0x09,0x9f,0x1a,0x6f,0x0d,0x64,0xe3,0x00,0x9f,0x83,0x00,0x00, + 0x05,0x20,0x8a,0x21,0x15,0x27,0xf9,0x3d,0x2d,0x00,0xbc,0x6b,0xa1,0x16,0x84,0x9b,0x14,0xae,0x28,0x12,0x40,0x99,0xd3,0x46,0xda,0xa3,0xd9,0x26,0x59,0x51,0x5a,0x0c,0xc5,0xe5,0x00,0x00, + 0x05,0x20,0x8a,0x77,0xf3,0x26,0x77,0xd5,0x19,0x01,0x08,0x4b,0xbd,0x99,0x32,0x8c,0xc3,0xba,0x8b,0x2b,0x3f,0x8f,0x34,0x5a,0x68,0xd4,0xf0,0x87,0x0a,0x73,0xa6,0x04,0xa0,0xfe,0x00,0x00, + 0x05,0x20,0x8a,0xe5,0xe7,0x6b,0x68,0xcf,0x6c,0x30,0x0d,0xda,0x6d,0xe4,0x3b,0xda,0xf2,0x51,0x7c,0xc1,0x4e,0x45,0xf6,0xb6,0xa4,0x7a,0x8a,0xa3,0xe2,0x32,0xe9,0x65,0x10,0x6a,0x00,0x00, + 0x05,0x20,0x8b,0x3d,0x54,0x9e,0x74,0x6f,0x72,0x94,0x6c,0xa4,0x30,0x6b,0x4d,0x65,0x83,0x5b,0xbd,0xf9,0xd2,0xa3,0x06,0x86,0x1a,0x92,0x08,0xd5,0x59,0x08,0x5c,0x71,0x0c,0x96,0x00,0x00, + 0x05,0x20,0x8c,0x19,0x6c,0x70,0x40,0xcd,0xa6,0xc5,0x55,0x74,0xb5,0xf3,0x9f,0xab,0x4b,0xc7,0x53,0x61,0x39,0x01,0x04,0x7d,0x52,0xdd,0xf1,0xee,0x80,0x06,0x2e,0x2c,0xed,0x88,0x00,0x00, + 0x05,0x20,0x8c,0x59,0xa7,0x91,0x92,0xe6,0xba,0x1a,0x1d,0xcd,0x7c,0xdf,0xf5,0x86,0x61,0x7c,0x59,0x6b,0x24,0xe1,0x2c,0xc9,0x8e,0x51,0x35,0x56,0xba,0xd1,0x2e,0xff,0x89,0x23,0x00,0x00, + 0x05,0x20,0x8c,0xb8,0x4b,0xb7,0x1c,0x99,0xf6,0x0f,0xb4,0xc8,0x34,0x4c,0xf5,0xae,0x46,0x71,0x25,0x77,0x5f,0x30,0x82,0xbb,0x47,0xe7,0x34,0xd7,0x0c,0x32,0xd7,0xd1,0x48,0x05,0x00,0x00, + 0x05,0x20,0x8c,0xec,0xcf,0x35,0x24,0x2f,0x66,0x82,0xda,0xbd,0x72,0xe5,0xb0,0xf1,0xb2,0x0b,0x9a,0x84,0x1b,0xaa,0x1d,0xb7,0xa4,0x2b,0xb0,0x0d,0x77,0x66,0x1d,0xce,0xdb,0xc2,0x00,0x00, + 0x05,0x20,0x96,0x93,0xa8,0xd7,0x43,0x12,0x32,0x6d,0xa0,0x2c,0x8d,0xb2,0x2a,0xc0,0x9d,0x11,0xa6,0x01,0x93,0x20,0xb3,0xac,0xdf,0xf9,0x7e,0x91,0x60,0x39,0xa8,0xad,0xce,0x52,0x00,0x00, + 0x05,0x20,0x90,0x40,0xb7,0xe8,0x6e,0xbe,0x08,0x39,0xc7,0xba,0x52,0x7b,0xfa,0x83,0x51,0x60,0x51,0xd6,0xbe,0x4f,0xaf,0x07,0x15,0x72,0xb7,0x6d,0x12,0x03,0x7f,0x46,0x9b,0xd1,0x00,0x00, + 0x05,0x20,0x90,0x8b,0x8c,0xe4,0x6d,0xc0,0x9e,0xf0,0xea,0xb2,0xe2,0x00,0x4f,0xda,0xc9,0x88,0x67,0x8b,0x4e,0x85,0xe2,0x31,0x81,0x81,0x0e,0x5a,0xab,0x9c,0x68,0x7e,0x0e,0xe6,0x00,0x00, + 0x05,0x20,0x91,0x0c,0xda,0xcd,0x49,0x84,0x0f,0x97,0x77,0x4d,0x4d,0xd8,0x0d,0xa4,0xc4,0x8d,0x82,0xb6,0xbe,0xb0,0x8b,0x92,0x9c,0x12,0x90,0x36,0x41,0x5f,0x8e,0xc9,0x5e,0x5c,0x00,0x00, + 0x05,0x20,0x91,0x1a,0x19,0x6a,0xa3,0xdb,0x12,0x69,0x17,0x4d,0xab,0xd2,0x26,0x93,0xdb,0x7e,0x44,0x57,0x2d,0xaa,0xd5,0x66,0x5d,0x26,0xe0,0xfb,0xee,0x41,0x50,0x8f,0x2a,0x53,0x00,0x00, + 0x05,0x20,0x91,0x94,0x32,0xe9,0xaa,0xf6,0xa4,0xbb,0xf8,0xd3,0x8b,0x63,0x72,0x39,0x0a,0x6b,0xc6,0x72,0xa5,0x39,0x6c,0x22,0x22,0x4c,0x6d,0xa6,0x93,0xd4,0x21,0x73,0xbf,0x84,0x00,0x00, + 0x05,0x20,0x91,0xfa,0x7b,0x5b,0x9a,0xad,0x97,0x25,0xf7,0xe2,0x1c,0x5c,0xf0,0x12,0x0c,0x65,0x9d,0x94,0x35,0xb1,0xd4,0xcd,0xeb,0x43,0x8f,0x89,0xbb,0x68,0xaa,0x92,0xad,0xd2,0x00,0x00, + 0x05,0x20,0x91,0xcf,0xa2,0x5b,0x04,0x33,0x69,0x66,0xb0,0x72,0x27,0x54,0xbe,0xcd,0xd8,0x08,0xeb,0x95,0x55,0x5a,0xc2,0x79,0x91,0x3a,0xd9,0xf2,0x2c,0x73,0x9f,0x78,0x50,0xca,0x00,0x00, + 0x05,0x20,0x92,0x22,0x1f,0x8a,0x44,0x4c,0xd5,0xfb,0xda,0x3e,0x86,0x18,0x63,0x50,0x73,0x2c,0xfc,0x2b,0x0f,0xa3,0xe2,0x22,0xe4,0xf2,0xab,0x02,0x4e,0x84,0x3e,0x7a,0x3a,0x01,0x00,0x00, + 0x05,0x20,0x92,0x65,0xff,0x27,0xea,0x05,0x16,0xd7,0xad,0xfe,0xb2,0x65,0xd6,0xb9,0x52,0x38,0xdd,0x63,0x14,0x3f,0x17,0x9a,0xf6,0x32,0x6d,0x6c,0x10,0xc3,0x66,0xf7,0x89,0xf5,0x00,0x00, + 0x05,0x20,0x92,0xc9,0xb1,0x04,0x23,0x73,0x3d,0x15,0x34,0x5b,0x1c,0x61,0x30,0x58,0x53,0x7e,0x3d,0xbe,0xa0,0x40,0xe8,0xfa,0x62,0x45,0x29,0x18,0x0e,0x5c,0x31,0x4e,0x57,0x18,0x00,0x00, + 0x05,0x20,0x93,0x96,0x86,0xc8,0x64,0xb6,0x32,0x33,0x40,0x24,0xe5,0xe4,0xef,0x59,0x5d,0x47,0xa5,0x4e,0x18,0x56,0x04,0xbd,0x9b,0x8f,0x90,0xdb,0x99,0xc5,0xa6,0xa9,0xaf,0x34,0x00,0x00, + 0x05,0x20,0x93,0xda,0x29,0x12,0xda,0xc9,0xb0,0xd0,0x4f,0x15,0xaa,0xfa,0xc0,0xf2,0x74,0xc4,0x87,0xfd,0xba,0xec,0x06,0x66,0x14,0x59,0x2d,0x70,0x96,0x4c,0x5e,0x84,0xbe,0x29,0x00,0x00, + 0x05,0x20,0x94,0xd7,0x30,0x49,0x85,0xe0,0x7b,0xc9,0x46,0x29,0x0e,0xd8,0x5f,0x9d,0x33,0x4d,0x59,0x5a,0xb2,0x5a,0xf0,0x67,0x70,0x28,0x42,0x1c,0xd6,0xb3,0x45,0x9a,0x86,0x4d,0x00,0x00, + 0x05,0x20,0x95,0x3e,0x3e,0x05,0x14,0x8a,0x0e,0xac,0x47,0x70,0x21,0x01,0xf6,0x01,0x4a,0xbe,0x50,0xab,0xc7,0xb9,0x47,0x32,0xda,0xc7,0x07,0xd8,0x52,0x49,0x3d,0xef,0x29,0xef,0x00,0x00, + 0x05,0x20,0x96,0x01,0xec,0x0d,0x1c,0x47,0x87,0x25,0xe5,0x37,0x62,0xd7,0x43,0x4b,0xa6,0xc3,0xa4,0x6f,0xc5,0xf6,0xb1,0x4c,0x05,0xc7,0x27,0x1e,0xb9,0xf5,0x73,0x57,0x88,0x83,0x00,0x00, + 0x05,0x20,0x96,0x0f,0x72,0x1e,0xab,0xf4,0x68,0x15,0xdb,0xca,0xee,0x24,0xcc,0x8a,0x50,0x8e,0x47,0x26,0x8f,0xe4,0x84,0x43,0x60,0x2c,0xaa,0xa9,0xcc,0x51,0x09,0xf4,0xd3,0xa5,0x00,0x00, + 0x05,0x20,0x96,0x14,0x9b,0x6d,0x2d,0x0f,0xdb,0xe0,0xbb,0xbf,0xe5,0x9a,0xf4,0x02,0xe7,0x7e,0x9a,0xce,0x18,0x5e,0x38,0xb8,0x93,0xf2,0xbe,0x9c,0x64,0x17,0x85,0xd8,0x93,0x9c,0x00,0x00, + 0x05,0x20,0x96,0x61,0x5b,0x17,0x98,0xbb,0x61,0x57,0xbe,0x35,0xf5,0x33,0x75,0x37,0xf5,0x75,0xc0,0x1d,0x23,0xb6,0x21,0x81,0xf5,0x37,0xbe,0x74,0x69,0xa4,0x7a,0xcf,0xcd,0x27,0x00,0x00, + 0x05,0x20,0x9f,0x1a,0xe9,0xad,0x03,0xe0,0x48,0x9b,0x67,0x53,0xcd,0x04,0xfa,0x90,0x6d,0x51,0x29,0x25,0x11,0xaf,0x6d,0x3b,0x28,0x08,0x23,0x39,0xf6,0xb8,0x3a,0x88,0x34,0x2e,0x00,0x00, + 0x05,0x20,0x9f,0xbc,0x8c,0x21,0xab,0xa0,0x66,0x6e,0x65,0xa7,0x9e,0x81,0xe3,0x5a,0xc2,0xc2,0x0b,0x34,0xba,0x54,0x87,0xee,0x1a,0x47,0x86,0x29,0x14,0xa3,0xdb,0x0c,0xbb,0x86,0x00,0x00, + 0x05,0x20,0x98,0xfc,0x41,0x3a,0x3f,0x83,0xce,0x68,0xd3,0xbe,0xbc,0xf5,0x81,0xa0,0xfe,0x57,0xa6,0x04,0xee,0x75,0x7f,0xff,0x93,0xa1,0x8e,0x4f,0x35,0x3d,0xad,0xdd,0xa7,0xda,0x00,0x00, + 0x05,0x20,0x99,0x18,0x50,0x29,0xbb,0x47,0xec,0x0d,0x0c,0x8a,0x12,0xc2,0x6e,0x7e,0x4c,0xc0,0x4b,0xdd,0x3b,0x6a,0xc5,0xb8,0x26,0xe2,0xc2,0x64,0x4f,0x18,0x6c,0x60,0x4b,0x6c,0x00,0x00, + 0x05,0x20,0x99,0x26,0xe8,0x24,0x06,0x91,0x7e,0x57,0x91,0x20,0x4a,0x2c,0xce,0x45,0xd2,0x84,0x85,0x8e,0x9e,0x90,0x0e,0x7a,0x71,0x40,0xc5,0xa1,0xc1,0xd9,0x8c,0xad,0x5c,0x5b,0x00,0x00, + 0x05,0x20,0x99,0x79,0x37,0x64,0xfd,0xa3,0x64,0x6c,0x65,0xe3,0x93,0x22,0x31,0x3c,0x26,0x22,0xad,0xa0,0x1a,0x9f,0x9b,0xfa,0x9a,0xe0,0x4b,0xc8,0xa5,0xd5,0x26,0x83,0xb5,0x9e,0x00,0x00, + 0x05,0x20,0x9a,0x4a,0x37,0xf9,0x84,0x5e,0xed,0x91,0xbe,0xea,0x38,0x70,0x78,0xb0,0xb1,0x38,0x3e,0x62,0x2a,0xbb,0x31,0x8e,0x05,0xb6,0xe4,0xcc,0x59,0x56,0x9f,0x1a,0x68,0xa2,0x00,0x00, + 0x05,0x20,0x9b,0x05,0xde,0x44,0xe9,0xf6,0x2e,0xd2,0x64,0x86,0xf4,0x5d,0x53,0x4d,0x58,0x1f,0xd5,0x65,0x91,0x0d,0x0f,0xc4,0x9e,0x62,0x63,0x04,0xec,0x71,0x91,0x7c,0xac,0xad,0x00,0x00, + 0x05,0x20,0x9b,0xf1,0x2f,0x96,0xdf,0xd8,0x58,0x65,0xb5,0x33,0x44,0xee,0x40,0xbe,0x26,0xbc,0xce,0x6f,0x12,0xdc,0x33,0x4e,0xfe,0xf2,0x82,0xd6,0xc4,0xd2,0x10,0xbf,0x92,0x35,0x00,0x00, + 0x05,0x20,0x9c,0x68,0x2a,0xac,0x16,0x7d,0x0b,0x19,0x65,0x58,0xe6,0x72,0x73,0xde,0x63,0x1b,0x4e,0x87,0x71,0x8d,0x80,0x2d,0x91,0x73,0xed,0xfa,0x90,0xaf,0x23,0x9c,0xe3,0x35,0x00,0x00, + 0x05,0x20,0x9d,0x19,0x58,0x72,0xaf,0x06,0xbb,0x9e,0xe7,0x8f,0x3c,0x97,0xa7,0x0e,0x26,0x95,0xa6,0x5d,0xac,0xe0,0xc4,0x4b,0x38,0x48,0x67,0xa9,0x13,0x9c,0xbf,0xf8,0xd6,0x56,0x00,0x00, + 0x05,0x20,0x9d,0x77,0x7e,0x28,0x63,0x0d,0x3f,0xdd,0xcd,0xab,0x31,0xcc,0x7d,0xce,0xee,0x33,0xf5,0xe9,0xaf,0x03,0x9f,0x3f,0x15,0xf6,0x42,0xbf,0xc8,0xeb,0x99,0xae,0x11,0x78,0x00,0x00, + 0x05,0x20,0x9d,0xac,0x96,0x06,0xb1,0x11,0x54,0xbf,0xcb,0x67,0x3f,0x3f,0xb4,0xd9,0x97,0x1e,0x25,0xac,0xdd,0xda,0x76,0x56,0x54,0x56,0x49,0xa8,0x4f,0xa5,0x38,0x2b,0xdd,0x65,0x00,0x00, + 0x05,0x20,0x9d,0xff,0xd9,0xf4,0x45,0x78,0xbb,0x49,0x31,0x0f,0x20,0xd8,0xde,0xdb,0xf2,0xbb,0x58,0x47,0x15,0xcb,0xbe,0x15,0xb9,0x44,0x52,0x1f,0x31,0x47,0xa9,0x46,0x95,0x3b,0x00,0x00, + 0x05,0x20,0x9d,0xd9,0x15,0x05,0x09,0xa3,0x0d,0x71,0x9e,0x3b,0xe9,0x83,0x88,0x48,0x45,0x0f,0x01,0xbc,0x7d,0x61,0x8a,0xf4,0x30,0x69,0xb8,0x84,0x47,0x34,0x2e,0x0f,0x27,0x7c,0x00,0x00, + 0x05,0x20,0xa7,0x08,0xd8,0x1d,0x0b,0x07,0xde,0xab,0x06,0xd4,0xc1,0x42,0x51,0xef,0xd0,0x5a,0xc3,0x8a,0xff,0x1b,0x7f,0x1a,0x45,0xdc,0x8a,0x89,0x76,0x54,0x65,0xfc,0x3c,0xf2,0x00,0x00, + 0x05,0x20,0xa7,0xb7,0xde,0x7f,0xf4,0xbc,0x25,0xfc,0xf2,0x95,0xb5,0xf5,0xae,0x53,0xce,0x4b,0x76,0x2d,0x92,0xc2,0x0f,0xbc,0x5d,0xa7,0xf0,0x58,0x73,0x0c,0x46,0x24,0xad,0xd2,0x00,0x00, + 0x05,0x20,0xa0,0x38,0x51,0x80,0x99,0xf9,0x0a,0xdf,0xf3,0x08,0xad,0x57,0x83,0x6a,0x0e,0x74,0x85,0x09,0x2a,0xa8,0xa3,0xab,0x83,0x22,0x89,0x31,0xf6,0x9c,0x37,0xcf,0x28,0x18,0x00,0x00, + 0x05,0x20,0xa0,0x8c,0x2d,0xb8,0x4f,0x88,0x90,0x4c,0x25,0x3b,0x52,0x57,0x89,0x03,0xb8,0xd6,0x32,0x52,0x2a,0xb3,0x7b,0x08,0x6e,0x7a,0x7c,0x3c,0xeb,0x54,0x00,0x93,0xe9,0x2b,0x00,0x00, + 0x05,0x20,0xa0,0xb3,0x9d,0x6b,0x08,0x16,0x69,0x81,0xb5,0xd0,0x18,0xe3,0x80,0x23,0xdd,0xef,0x3e,0x05,0xf1,0x42,0xd6,0xc9,0x5f,0xd3,0xc2,0x61,0x92,0x36,0xda,0xf0,0xb0,0x9a,0x00,0x00, + 0x05,0x20,0xa1,0x38,0x9e,0x1d,0x56,0xf0,0xf1,0xc0,0xc2,0xfd,0x5f,0x0d,0x69,0x75,0x43,0x91,0x21,0x37,0x6b,0x1e,0xc5,0xc2,0x01,0x9f,0x7a,0xc2,0x1f,0x61,0x62,0xd2,0x2f,0x1e,0x00,0x00, + 0x05,0x20,0xa1,0x0c,0xbe,0x81,0x1d,0xae,0x86,0x3c,0x94,0x90,0xf1,0x06,0x0f,0xab,0x74,0x5e,0xbb,0xc2,0x08,0x38,0x4a,0x7a,0xb8,0x2c,0x53,0xfb,0x65,0x15,0xa5,0x37,0x54,0x8e,0x00,0x00, + 0x05,0x20,0xa1,0x7d,0xa4,0xd4,0x3d,0xf1,0x98,0x7c,0x96,0xb8,0xe4,0x37,0x18,0xc5,0x0f,0xb6,0xcc,0x0d,0x19,0xe4,0xa4,0xdf,0xec,0xe1,0xeb,0x29,0x22,0x2e,0x52,0x9f,0x4e,0x90,0x00,0x00, + 0x05,0x20,0xa1,0xd4,0x58,0xba,0x50,0x16,0xa9,0x01,0x66,0xc2,0x54,0xc2,0x1f,0xd1,0xf2,0xe8,0x7b,0x3d,0x51,0xff,0xc1,0xd8,0x81,0x47,0x11,0xcc,0x14,0xd5,0x27,0x7b,0xe4,0x5b,0x00,0x00, + 0x05,0x20,0xa2,0x42,0xbf,0x4b,0x0f,0xe1,0xff,0x63,0x84,0xcc,0x81,0x43,0x23,0xad,0xbf,0xbd,0x59,0x24,0x3a,0x29,0x87,0x6e,0x9d,0x76,0xd5,0x5f,0xac,0xf1,0x61,0x81,0xb5,0x81,0x00,0x00, + 0x05,0x20,0xa2,0x4d,0xe0,0xf0,0x58,0xb9,0xd1,0xd7,0x97,0x8f,0xa5,0xab,0x6a,0x3e,0x91,0xda,0x06,0x36,0x6b,0x74,0x40,0x40,0xf4,0x19,0xf6,0x5f,0x03,0x29,0xd5,0x73,0xe0,0xaa,0x00,0x00, + 0x05,0x20,0xa2,0xec,0x7a,0xc1,0x85,0x22,0x3d,0x9a,0xdd,0xb4,0x92,0xfb,0x88,0x61,0x37,0x30,0x7c,0x2b,0xba,0xee,0x28,0x34,0x43,0x3f,0xa4,0x15,0x62,0xfe,0x9e,0xef,0x64,0x23,0x00,0x00, + 0x05,0x20,0xa3,0x16,0x15,0x59,0xec,0xdf,0x46,0xf7,0xfb,0xc6,0x35,0xe7,0xad,0xcc,0x79,0x94,0x0f,0xb9,0xe8,0x0d,0x10,0xf1,0x13,0x03,0xad,0xba,0x06,0xdd,0x2d,0xaa,0x19,0xaf,0x00,0x00, + 0x05,0x20,0xa3,0x47,0x9a,0x16,0x49,0x20,0x79,0x05,0x97,0xf8,0xea,0xd6,0x7e,0xfa,0x69,0x47,0xb2,0xb3,0xce,0x47,0x5c,0xb0,0x79,0xf3,0x09,0x1c,0x81,0xa5,0x70,0x18,0xbf,0xeb,0x00,0x00, + 0x05,0x20,0xa3,0xc5,0x61,0x3c,0xf4,0x7e,0xc8,0xe4,0x43,0x8e,0x80,0x90,0xd3,0x76,0x2f,0x5a,0x84,0xbf,0x71,0x64,0x33,0x6b,0xed,0xc6,0xf7,0x8e,0xab,0xaf,0x02,0x7e,0x46,0xcf,0x00,0x00, + 0x05,0x20,0xa4,0x0a,0xf8,0xf0,0x7c,0xa8,0x83,0x2f,0xb4,0x7d,0x5f,0x5d,0xc9,0x6d,0x99,0x5e,0xc6,0xf9,0x82,0x42,0x31,0x24,0x54,0x44,0xb4,0xa1,0xeb,0x40,0x0f,0x23,0x6e,0xbc,0x00,0x00, + 0x05,0x20,0xa5,0x79,0xc6,0x25,0xd0,0x8a,0x76,0xcd,0x9b,0x39,0xed,0xae,0xb6,0xcb,0x33,0xeb,0xea,0x65,0x6d,0x10,0x58,0xb6,0xf6,0x40,0xa4,0xf5,0x1b,0xe3,0x5c,0x18,0x96,0x85,0x00,0x00, + 0x05,0x20,0xa6,0x02,0xe4,0xfb,0x4a,0x64,0x75,0x02,0x6d,0xec,0x07,0xd6,0x44,0xf3,0x56,0x30,0xae,0xad,0x23,0xc9,0xcc,0xd0,0xc5,0x5b,0x83,0x20,0x7f,0x82,0xf7,0xae,0x67,0xc2,0x00,0x00, + 0x05,0x20,0xaf,0xde,0xd1,0x52,0x17,0x5b,0x8b,0x66,0x1e,0xe8,0xd4,0x48,0x10,0xde,0xa9,0x8e,0xc5,0x01,0x8f,0x24,0xb0,0x73,0x73,0x49,0x92,0xcf,0x7e,0x8e,0xc6,0x49,0xe6,0x48,0x00,0x00, + 0x05,0x20,0xa8,0x2a,0xf7,0x12,0xb3,0x77,0x3a,0x3a,0xf6,0x4f,0x1f,0x05,0x25,0x6e,0x93,0xd8,0x0a,0x4e,0x89,0x63,0x9e,0x6a,0xe1,0x12,0x88,0x45,0xf8,0x86,0x99,0x85,0x3d,0xd6,0x00,0x00, + 0x05,0x20,0xa8,0x95,0x26,0xe2,0x98,0xb6,0xd1,0xe3,0x96,0xa8,0x70,0x7b,0x8c,0xbb,0x0d,0x87,0xdc,0xab,0xa3,0xdf,0xf8,0x6d,0xfd,0x6b,0x9a,0xfe,0xca,0x93,0xc9,0x5a,0x51,0xa2,0x00,0x00, + 0x05,0x20,0xaa,0xb3,0xfd,0x21,0x0c,0x24,0xad,0xe5,0x2d,0xb4,0x8d,0x12,0x9c,0x3b,0x00,0x79,0xcd,0x72,0xa7,0xfc,0xb1,0xbe,0x74,0xd1,0x18,0x8e,0xd2,0x78,0x53,0xe5,0x76,0xe3,0x00,0x00, + 0x05,0x20,0xaa,0xde,0xa9,0xd2,0x09,0x53,0x97,0xdc,0x56,0xa9,0x4c,0xc0,0xc5,0x87,0xaa,0xec,0xf5,0x8b,0x46,0x52,0xc6,0x9a,0x8a,0x81,0xa2,0x6e,0xc9,0x1e,0x61,0x8d,0xc5,0xd1,0x00,0x00, + 0x05,0x20,0xab,0xb5,0xa7,0x6b,0x38,0xf1,0x83,0xc6,0xc9,0x82,0x99,0x08,0xb7,0xe1,0xc0,0xe2,0x8e,0x7d,0x9d,0xc6,0x71,0x36,0x99,0x19,0x12,0xf6,0x0c,0xbc,0x46,0x77,0xca,0xdd,0x00,0x00, + 0x05,0x20,0xac,0x3b,0x53,0xf3,0xa3,0x41,0xf3,0x4b,0xa8,0xd5,0xa7,0x56,0x4f,0x30,0x14,0xa8,0xd6,0xc5,0x6d,0xe9,0xc9,0x5c,0x16,0x8a,0xa0,0x22,0xe8,0xcb,0x17,0xbe,0x1f,0x2d,0x00,0x00, + 0x05,0x20,0xac,0x27,0xad,0x5f,0x8d,0x69,0x56,0xc0,0x99,0x13,0x49,0xc8,0xd2,0x80,0xd9,0x3a,0x99,0x02,0x28,0x29,0x72,0x19,0xea,0xdd,0x2c,0x06,0x04,0xee,0x12,0xc3,0x6d,0xe5,0x00,0x00, + 0x05,0x20,0xac,0x40,0xdd,0x3c,0x9a,0xf4,0x53,0x4d,0x05,0xcb,0xf0,0xd6,0xb8,0x9d,0x86,0x8d,0x07,0xe2,0x52,0x6c,0x3f,0x91,0xa1,0xba,0x6b,0xaf,0x0c,0xd5,0x6f,0x14,0x56,0xb1,0x00,0x00, + 0x05,0x20,0xad,0x20,0xaf,0xf9,0x35,0xb9,0x55,0xde,0x85,0x4e,0xac,0x04,0xc6,0x2a,0xb8,0x13,0x1a,0x32,0x13,0xe9,0xdc,0xe9,0x5f,0x93,0x23,0x0e,0xa4,0xb8,0x95,0xe9,0xc5,0x5c,0x00,0x00, + 0x05,0x20,0xad,0x22,0x4b,0x2e,0x78,0xc5,0x1d,0xf9,0x7a,0xf9,0x6a,0x7f,0x41,0xa6,0x6e,0x82,0xc4,0xcf,0x75,0x5f,0xc8,0x4b,0xa4,0x8d,0x34,0x0a,0xc4,0xc4,0x50,0x8e,0x08,0x29,0x00,0x00, + 0x05,0x20,0xae,0x6b,0x3e,0x0c,0x6a,0x76,0x7f,0x21,0x25,0x89,0xcd,0x38,0x3a,0x81,0xaa,0x8a,0xaf,0x7d,0x86,0x53,0x2c,0x93,0x44,0x08,0x9e,0xe7,0xbc,0x15,0x92,0x84,0x32,0x65,0x00,0x00, + 0x05,0x20,0xb6,0xbb,0x09,0xb6,0x9d,0xcb,0xbb,0x2e,0x10,0x59,0x72,0x10,0x3c,0x5d,0x38,0xbe,0x8d,0x6f,0x69,0xa8,0x98,0x08,0xad,0xd1,0xd3,0x00,0x2c,0x08,0xd4,0x69,0xdf,0x46,0x00,0x00, + 0x05,0x20,0xb6,0x98,0x60,0x64,0x1f,0xe8,0x19,0x1a,0x95,0xc2,0x5f,0xed,0x3f,0x57,0xe4,0x43,0x1f,0x15,0x82,0x54,0x4e,0xc2,0x8e,0x5c,0x99,0x1c,0x75,0x6c,0x40,0xea,0xbe,0x6d,0x00,0x00, + 0x05,0x20,0xb6,0xa9,0x1a,0x58,0x25,0x83,0x29,0x17,0x27,0x92,0xd2,0x9c,0xd0,0xfd,0x22,0x9c,0x07,0xf6,0x4f,0x9f,0xc4,0x2d,0x23,0x1b,0x1e,0xe9,0xc9,0xf2,0xd4,0xb1,0x91,0xac,0x00,0x00, + 0x05,0x20,0xb6,0xcf,0x88,0x35,0x74,0x20,0x79,0x8a,0xf5,0x6a,0xca,0x77,0x65,0xb6,0x29,0x7f,0xcb,0x97,0xdd,0xa8,0x37,0xaf,0xe6,0x6e,0xdd,0x1d,0x34,0xf9,0x95,0x22,0x66,0x93,0x00,0x00, + 0x05,0x20,0xb6,0xe3,0xd3,0xc6,0xb8,0x0e,0x9e,0xf4,0x5a,0x8b,0xb7,0x65,0xa8,0xf6,0xd6,0x45,0x7d,0x7e,0xde,0xa8,0x8b,0xcb,0x31,0xd0,0xd5,0x9d,0x41,0x19,0xa8,0x88,0x2c,0x83,0x00,0x00, + 0x05,0x20,0xb7,0x33,0x86,0x25,0x90,0xf9,0x6e,0xf2,0x0b,0x02,0xf0,0x76,0xf9,0x08,0x12,0x48,0x51,0xb5,0x27,0x86,0x31,0x68,0x20,0xfc,0xc7,0xe5,0x9c,0x4c,0x09,0xa9,0x95,0xd8,0x00,0x00, + 0x05,0x20,0xb0,0x04,0x52,0x59,0x1e,0x21,0xd8,0x5b,0xd4,0xb3,0xbc,0x19,0x10,0x08,0xa7,0xfc,0x89,0xa9,0xfd,0xd9,0x5f,0xb5,0x4e,0x1e,0x54,0xc0,0xf8,0x2e,0xdc,0xb9,0xa0,0x13,0x00,0x00, + 0x05,0x20,0xb1,0x04,0xad,0x10,0xac,0x24,0x86,0x4b,0x10,0xa7,0x18,0xe8,0x1d,0xf5,0xcf,0x92,0xb3,0x6e,0xf6,0x67,0xa0,0x6b,0x01,0x24,0xa0,0x0b,0x59,0x40,0x1f,0x34,0x5c,0xbc,0x00,0x00, + 0x05,0x20,0xb1,0x63,0x56,0x80,0x90,0x00,0xfd,0x92,0x54,0xab,0xc3,0x09,0xef,0x37,0x6f,0xff,0xc3,0xc0,0x5f,0x0c,0x6a,0x37,0xb2,0xd3,0x9a,0x09,0xe4,0x02,0x23,0xc2,0x64,0x5e,0x00,0x00, + 0x05,0x20,0xb2,0xf7,0xeb,0x70,0x68,0x10,0x1d,0x50,0x2e,0xbe,0xb7,0x2a,0x84,0xb7,0x69,0xb5,0xa5,0xeb,0x52,0x3b,0xed,0x5a,0xb3,0xa0,0x7d,0x8f,0xfc,0x70,0x2f,0x4e,0xa7,0x71,0x00,0x00, + 0x05,0x20,0xb3,0x85,0xed,0x8a,0x80,0xb5,0x2f,0xbd,0xe4,0xda,0x13,0xba,0x54,0x0e,0x76,0xd8,0x16,0x58,0x14,0x5b,0x63,0xab,0xb0,0xa5,0x5e,0xea,0x1f,0xc3,0x13,0x83,0xcf,0x09,0x00,0x00, + 0x05,0x20,0xb3,0xc1,0x4d,0xdc,0xcf,0x54,0x7f,0xa8,0xeb,0x12,0x08,0x1a,0x72,0x4f,0xff,0xb9,0xe6,0x0b,0x33,0xac,0x8b,0x3c,0x0f,0x32,0xa9,0x6d,0x78,0xe8,0x71,0x58,0x7d,0xea,0x00,0x00, + 0x05,0x20,0xb4,0x82,0x5e,0xcd,0xee,0xf9,0x05,0x20,0x16,0x92,0x2a,0xf1,0x86,0x7f,0x4a,0xf4,0xc3,0x81,0x2c,0xd5,0x80,0x2b,0xdf,0x40,0x05,0xae,0x05,0xc4,0xee,0x4f,0xc8,0xdd,0x00,0x00, + 0x05,0x20,0xb4,0xca,0x40,0x86,0xcc,0x95,0xdd,0x8b,0x53,0xcd,0xb7,0x44,0xeb,0x2e,0xf0,0x3c,0xdc,0xab,0xc6,0xe5,0x9d,0x49,0xac,0x90,0x9e,0x2a,0xeb,0x17,0xc0,0xdc,0x4f,0x98,0x00,0x00, + 0x05,0x20,0xb5,0x10,0xa2,0xd9,0x44,0xbc,0xfc,0xb0,0xaf,0xd4,0x89,0xdd,0x89,0x47,0x40,0x08,0xb0,0x52,0xf5,0x6a,0x66,0x9c,0x98,0xf9,0x85,0x23,0x61,0x0d,0x75,0xb9,0x5a,0xe9,0x00,0x00, + 0x05,0x20,0xb5,0x83,0x6f,0xb6,0x11,0xd8,0x0e,0xa8,0x57,0xda,0x15,0x20,0x5b,0x1a,0x6d,0x21,0x15,0x5a,0xbd,0xb4,0x17,0x11,0xc2,0xfb,0x0e,0xfc,0xde,0xe8,0x26,0x56,0xa8,0xac,0x00,0x00, + 0x05,0x20,0xb5,0xad,0x1b,0xfc,0xbb,0xa4,0x59,0xc3,0x68,0x3d,0xae,0xe3,0x31,0x5c,0x48,0x48,0xc8,0x54,0xa2,0x24,0xc4,0x30,0x25,0xf8,0x62,0x76,0x00,0xff,0x54,0x15,0xd4,0xa0,0x00,0x00, + 0x05,0x20,0xb6,0x35,0x41,0xa9,0x66,0xc0,0xcf,0xf4,0x29,0xad,0x29,0x43,0x9a,0xac,0x6e,0x45,0xa4,0x29,0xf8,0x78,0xdb,0xbe,0x54,0x8a,0x49,0x10,0xd2,0xe8,0x70,0x3e,0xed,0x4e,0x00,0x00, + 0x05,0x20,0xb6,0x16,0xe1,0x81,0x6b,0x5f,0x82,0x3d,0xaf,0x75,0x49,0x41,0x95,0xd5,0x93,0x96,0x18,0x66,0xf4,0x2e,0x50,0xed,0x81,0xb0,0x39,0x7f,0x5a,0x2b,0x5b,0x7d,0x4b,0xe4,0x00,0x00, + 0x05,0x20,0xbe,0xd8,0x00,0xb0,0xd7,0xde,0x8e,0xb4,0x86,0xfc,0xf5,0xe0,0x97,0x04,0xfe,0x5e,0xe7,0x58,0xc5,0x03,0x6d,0xcd,0x15,0x83,0x90,0xfc,0xb4,0x13,0x29,0x5e,0xd8,0x20,0x00,0x00, + 0x05,0x20,0xb8,0x24,0x4b,0x3d,0x10,0x7e,0x4f,0x83,0x1a,0xf6,0x90,0x12,0xc6,0xaa,0x2f,0x7a,0x34,0xec,0xb0,0x0f,0x85,0x7d,0xef,0xef,0x34,0xa6,0x18,0xea,0x12,0x1e,0xfc,0xd6,0x00,0x00, + 0x05,0x20,0xb8,0x5a,0xbd,0x49,0x91,0xff,0xfe,0x18,0x28,0xab,0xb0,0x73,0x29,0xd2,0xcc,0x5d,0x69,0xf2,0x55,0x77,0x5f,0x18,0x4d,0xe1,0xaf,0x38,0xa5,0xb2,0x7f,0x51,0x59,0xba,0x00,0x00, + 0x05,0x20,0xb9,0x79,0x74,0x9d,0x11,0xc6,0xef,0xdf,0x9a,0x5f,0xdd,0xce,0x22,0xca,0xd4,0x59,0x8d,0x90,0x64,0xae,0xa4,0xb2,0xa0,0x9b,0xb4,0x77,0xdc,0x05,0x0b,0xe2,0xa6,0xdd,0x00,0x00, + 0x05,0x20,0xb9,0x71,0x92,0xd0,0xce,0xdc,0x26,0x57,0xc3,0x72,0xee,0x44,0x20,0x86,0x11,0xb9,0x54,0x6c,0x6e,0x73,0x5c,0x0f,0x9f,0x4f,0xce,0xab,0x26,0x68,0xca,0x98,0x11,0x3f,0x00,0x00, + 0x05,0x20,0xb9,0xf2,0xeb,0x82,0x4a,0x04,0x4f,0x4e,0xde,0x40,0xf4,0x81,0x3f,0xa8,0x37,0x78,0x89,0xe9,0xae,0xa2,0xd5,0x8b,0x0f,0x21,0x83,0x61,0x60,0x6b,0x04,0x38,0x86,0x1f,0x00,0x00, + 0x05,0x20,0xba,0x67,0x18,0xbc,0x23,0x77,0x47,0x58,0x27,0x32,0x8f,0xc6,0x77,0x61,0x2e,0x14,0x62,0xb4,0x95,0x54,0x9b,0xb1,0x16,0x0b,0x00,0x49,0x72,0x17,0xbb,0x2b,0xc4,0xe4,0x00,0x00, + 0x05,0x20,0xbb,0x43,0xb7,0xde,0x6c,0x02,0x3c,0xe2,0x84,0x11,0xc0,0x84,0xbb,0x5a,0x84,0x00,0x22,0xde,0x47,0x79,0x9e,0xf2,0x65,0x10,0x8f,0x77,0x1e,0x66,0x4a,0xd0,0xa9,0x45,0x00,0x00, + 0x05,0x20,0xbb,0x51,0x5c,0xfe,0xde,0xc1,0xd2,0x7a,0xc6,0xb8,0x9d,0x1e,0x5e,0x0f,0xe4,0x1e,0x06,0xd2,0xd7,0x2c,0x2b,0xe1,0x5f,0x34,0x67,0xb9,0x44,0xf5,0x0b,0x3c,0xf6,0x04,0x00,0x00, + 0x05,0x20,0xbb,0x8a,0x02,0x1e,0x26,0xdb,0xe6,0x9c,0x0c,0xc6,0x5e,0x32,0xab,0x6f,0xc2,0xba,0x3c,0x23,0x38,0xca,0x1c,0xff,0x81,0x71,0x6c,0x0b,0x4d,0xea,0xbd,0xae,0x21,0xaf,0x00,0x00, + 0x05,0x20,0xbc,0xee,0x7e,0x5a,0x6c,0x0a,0x57,0x2f,0xfa,0xd7,0x69,0x0e,0x4e,0xfc,0x93,0xa0,0x69,0x0a,0xc8,0x68,0xa3,0x6c,0x6a,0x93,0xca,0xb2,0x67,0xc0,0x0a,0xd2,0xb3,0x53,0x00,0x00, + 0x05,0x20,0xbd,0x11,0x5a,0xb5,0xe2,0x4e,0xa2,0x79,0x5d,0x8a,0xc6,0x13,0x96,0x62,0x1e,0x07,0xcd,0x63,0x52,0x4d,0x85,0x86,0xa5,0x99,0x0c,0x03,0x2a,0xac,0xd3,0xf1,0x6b,0x59,0x00,0x00, + 0x05,0x20,0xbd,0x47,0x03,0x4e,0x69,0x75,0x76,0x9c,0x99,0x8a,0x26,0xdd,0x67,0x17,0x98,0xf6,0xd3,0x64,0x4e,0xf3,0x0d,0xca,0xb9,0x3e,0xef,0xf9,0xa0,0x5e,0x4f,0x55,0x70,0x6b,0x00,0x00, + 0x05,0x20,0xbd,0x5f,0x90,0x40,0xb3,0x59,0x6f,0xa2,0x4e,0x18,0x97,0xf7,0xb6,0x34,0x6c,0xfa,0x63,0xb5,0xe9,0x3b,0x41,0x77,0x69,0x28,0xab,0x4e,0x40,0xeb,0x76,0x5c,0x8c,0x4b,0x00,0x00, + 0x05,0x20,0xbe,0x55,0x60,0xbe,0xea,0x46,0xdf,0x19,0x45,0x98,0x5c,0x53,0x9c,0x1b,0xb9,0xd8,0x14,0x99,0xd6,0xdc,0x45,0x3b,0x93,0x92,0xac,0xcf,0x40,0x41,0x98,0x3a,0x6b,0x7b,0x00,0x00, + 0x05,0x20,0xc6,0xdc,0x21,0x2f,0xb1,0x80,0xb4,0xcc,0xfb,0x84,0x95,0x3a,0xc8,0x65,0xd8,0x2e,0x56,0x1b,0xb9,0xff,0x9c,0xe6,0x5d,0x07,0x66,0xc5,0xd3,0x49,0x4f,0xbf,0x9d,0xcb,0x00,0x00, + 0x05,0x20,0xc7,0x3b,0x73,0xc1,0x41,0xe6,0xda,0x27,0x28,0xb6,0x3c,0x99,0x1e,0x67,0xc5,0xb6,0x15,0x44,0x4f,0xce,0xdb,0xf4,0xa0,0xc9,0xdb,0x23,0x2b,0xf9,0x4d,0xe8,0xb5,0x9d,0x00,0x00, + 0x05,0x20,0xc7,0xc4,0x03,0x80,0x5b,0xb6,0x0f,0xe5,0x5e,0x81,0xb2,0x15,0x88,0xb8,0x24,0xe7,0x82,0xce,0x9c,0xe4,0xe3,0xab,0x76,0xf0,0x97,0xf6,0x4b,0xa7,0x25,0x4a,0x05,0xa3,0x00,0x00, + 0x05,0x20,0xc7,0xca,0xb2,0xa9,0x11,0x63,0x43,0x9c,0xd6,0xc9,0xc1,0x78,0xbe,0xbc,0xc4,0x86,0x52,0x6b,0xc7,0x67,0xd0,0xe5,0xed,0xac,0x5f,0x52,0xef,0xc0,0xe1,0x0d,0x23,0xad,0x00,0x00, + 0x05,0x20,0xc0,0x46,0x77,0xc8,0xcc,0x9d,0xb8,0x42,0x5a,0x24,0x77,0xd5,0x2b,0x09,0x66,0x25,0xc7,0x99,0xe5,0x5b,0xd0,0x3b,0x7e,0x3c,0x31,0xed,0xa5,0xe6,0xb3,0x9a,0x33,0xdd,0x00,0x00, + 0x05,0x20,0xc0,0x9b,0x34,0x23,0x0f,0x5a,0xc2,0xec,0x3f,0x68,0x52,0xfc,0xd4,0xa7,0x1c,0xf9,0xae,0xa2,0xe0,0x55,0xb0,0xaa,0xc0,0xe1,0x0a,0x91,0xda,0x9b,0xed,0x7a,0x0d,0x6a,0x00,0x00, + 0x05,0x20,0xc1,0x19,0x15,0x62,0x0c,0x4e,0x6d,0x66,0xeb,0x00,0x94,0xf4,0x60,0x78,0x62,0x6c,0x9d,0x56,0xde,0xc8,0x7e,0xa2,0x97,0xa0,0x7d,0xf1,0xa2,0x33,0x7d,0x13,0xa1,0x9e,0x00,0x00, + 0x05,0x20,0xc1,0x74,0xdc,0x68,0x6e,0xce,0xa0,0x88,0x9a,0xcb,0xc8,0xbc,0x62,0x05,0x5e,0x22,0x0b,0x0a,0xe4,0x8e,0xc8,0x89,0x28,0x91,0x84,0xfd,0x3f,0xea,0x30,0xac,0xa8,0x38,0x00,0x00, + 0x05,0x20,0xc2,0x77,0x5d,0xb8,0x46,0x58,0xda,0x01,0x2a,0xef,0x9c,0x92,0xcb,0x02,0x40,0xe5,0xf3,0x74,0xed,0x13,0xf4,0x67,0x43,0xb1,0x6f,0xbd,0x6c,0xb8,0x75,0x4c,0xc6,0x27,0x00,0x00, + 0x05,0x20,0xc2,0xab,0xed,0x45,0x15,0x5d,0xe9,0x18,0x6a,0xca,0x20,0x80,0x6c,0xcb,0xfe,0x9d,0x16,0x57,0x47,0xfe,0xe8,0xb5,0xbf,0x86,0x49,0x6f,0xd3,0x3e,0x73,0x7e,0x53,0x75,0x00,0x00, + 0x05,0x20,0xc2,0xf5,0x8d,0xc3,0x8a,0xf6,0xc7,0xc0,0x7e,0x75,0x82,0x58,0x19,0xc3,0x54,0xc6,0x59,0x14,0xc0,0xcd,0x3a,0xfb,0x70,0x4c,0x40,0x62,0x48,0xdf,0x14,0x00,0xbc,0x5d,0x00,0x00, + 0x05,0x20,0xc2,0xd7,0x58,0x2b,0x54,0x9a,0x19,0x74,0xcd,0xd8,0xca,0xbe,0xbd,0x72,0x5c,0x6f,0x65,0x07,0xf4,0x61,0x6f,0x6b,0x69,0x06,0x7b,0x36,0xc6,0x3f,0x1f,0x83,0xbc,0x89,0x00,0x00, + 0x05,0x20,0xc2,0xee,0x88,0x4c,0x60,0xec,0x36,0x87,0x2d,0x18,0x29,0x78,0x29,0x5b,0x2b,0xc7,0x03,0x50,0x80,0x00,0x0b,0xd0,0x2f,0x08,0xf1,0x12,0xec,0x95,0x4f,0x7b,0x98,0xc1,0x00,0x00, + 0x05,0x20,0xc3,0x86,0xde,0xea,0x07,0xb7,0x2b,0xd0,0x38,0x0e,0x81,0x65,0x46,0xd4,0xa4,0x10,0x42,0xbf,0x0b,0x0a,0xea,0x78,0x08,0x69,0xe5,0x67,0x1d,0x3a,0x7b,0x70,0x5b,0xfc,0x00,0x00, + 0x05,0x20,0xc3,0x9e,0x7a,0x68,0xb9,0x2d,0x97,0x2f,0x0d,0x8f,0x69,0xf1,0xb3,0xe5,0xe5,0x21,0x73,0xb9,0x51,0xb4,0xf6,0xc3,0x3e,0xb9,0x1b,0xcd,0xfd,0x6c,0x14,0xe4,0x03,0xa9,0x00,0x00, + 0x05,0x20,0xc3,0xa4,0xd4,0xcb,0xa7,0x43,0x66,0xa0,0xa6,0x36,0xc4,0x6a,0x19,0x79,0x98,0x16,0xb2,0x3f,0x99,0xe5,0x94,0x4d,0xf9,0xfc,0x2f,0x8b,0x67,0x6c,0x21,0x70,0x69,0x5b,0x00,0x00, + 0x05,0x20,0xc3,0xc7,0x1a,0x37,0xf6,0xb8,0x76,0x03,0xf6,0x2f,0xf8,0xb0,0x26,0xa3,0x26,0xf1,0xda,0xa1,0xd1,0x0e,0x80,0x05,0xf7,0xff,0xab,0x52,0xe5,0x3a,0x0b,0x2e,0x42,0x53,0x00,0x00, + 0x05,0x20,0xc3,0xce,0xcc,0x7a,0xdb,0x66,0x31,0x8d,0x81,0x9d,0x05,0x86,0xa9,0x17,0x07,0x0b,0x18,0xb2,0x41,0x81,0x5c,0x69,0xb7,0x95,0xc0,0x49,0xd2,0x34,0x2d,0x53,0xb0,0xc4,0x00,0x00, + 0x05,0x20,0xc5,0x95,0x18,0x87,0x19,0xb1,0x85,0xd0,0xe9,0x74,0x0f,0x11,0xdc,0xf5,0x16,0x99,0x06,0x5c,0xe8,0x38,0x31,0xcf,0xfe,0xee,0xb9,0x5c,0x78,0xbb,0xc9,0x56,0x8c,0x9b,0x00,0x00, + 0x05,0x20,0xc5,0xfc,0x63,0xc0,0xe9,0xf8,0xbb,0x0d,0x8c,0xac,0xb4,0xd8,0xf3,0x73,0xc3,0x85,0x10,0x24,0x18,0x06,0x6d,0x8f,0x6f,0x02,0xdb,0x35,0x32,0x83,0x73,0x11,0x1d,0xa6,0x00,0x00, + 0x05,0x20,0xce,0x93,0x84,0x27,0x52,0x78,0xc5,0x64,0xc2,0x05,0xcf,0xa6,0x77,0x83,0x80,0xf0,0x5f,0xc5,0xe0,0xda,0x48,0x41,0x05,0x35,0x08,0xc6,0x07,0xc3,0xb8,0x41,0x5d,0x8d,0x00,0x00, + 0x05,0x20,0xce,0xf8,0xfb,0x76,0x6b,0x75,0xac,0x8d,0x99,0xe9,0xde,0x04,0x1d,0x0d,0xf3,0x36,0x29,0x0f,0x74,0x2f,0x4f,0xed,0xbf,0x5c,0x07,0x92,0xcc,0x85,0x18,0xce,0xe9,0x00,0x00,0x00, + 0x05,0x20,0xce,0xd3,0xab,0xc8,0xeb,0xe4,0xde,0x1b,0x83,0x01,0x13,0xe2,0x7c,0xc3,0xe2,0xa6,0x7d,0x48,0x85,0xd0,0x75,0xeb,0x57,0xb4,0xb1,0x45,0x78,0xdd,0x2e,0x1f,0xd2,0x65,0x00,0x00, + 0x05,0x20,0xce,0xde,0x6c,0x15,0x16,0x2e,0x44,0x3d,0x1b,0xf5,0xe4,0x65,0xe2,0x2f,0xb3,0xa8,0xbb,0xdc,0x7c,0x1b,0x98,0x11,0xc3,0x08,0x2f,0x93,0xbc,0x55,0x80,0x89,0x12,0x88,0x00,0x00, + 0x05,0x20,0xcf,0x8d,0xe5,0xb2,0xd4,0x3b,0x56,0x34,0x03,0x38,0x2f,0xf5,0x95,0xca,0xb3,0xb0,0x60,0xbe,0xb0,0xb5,0x7b,0x30,0x04,0x3e,0x95,0x49,0x6c,0xd0,0xfa,0x4b,0x22,0xfc,0x00,0x00, + 0x05,0x20,0xcf,0x8c,0x5f,0xd3,0xdf,0xf2,0x84,0x14,0x88,0xbb,0xbe,0x07,0x29,0x24,0x17,0x27,0xff,0x50,0x4e,0x11,0xfa,0xe3,0xcd,0xf7,0xd4,0x91,0x87,0x59,0x50,0xfd,0xe2,0x5e,0x00,0x00, + 0x05,0x20,0xc8,0xac,0x68,0x5b,0xe7,0x5d,0xbf,0xcd,0xfc,0x1f,0x05,0x3c,0xdf,0x38,0x2b,0x48,0xc3,0xc0,0x45,0xb2,0x3b,0x90,0x11,0xc1,0xde,0xab,0xa2,0x42,0x72,0xe8,0xcb,0x5d,0x00,0x00, + 0x05,0x20,0xc9,0xf7,0xca,0x27,0x62,0xb6,0x23,0xfc,0xcb,0x54,0x17,0x00,0x4c,0x44,0xe5,0x29,0xa8,0xcb,0x8f,0xb4,0xcb,0xca,0xf0,0xb0,0x34,0xc1,0x27,0x05,0x0f,0x77,0xc7,0x10,0x00,0x00, + 0x05,0x20,0xcb,0x67,0xe6,0x0e,0xac,0x94,0xee,0x21,0x82,0x04,0x45,0x1d,0xef,0xab,0x54,0x37,0x09,0xcd,0x68,0xc9,0x2c,0xe2,0xd6,0x7d,0xd5,0xd2,0x32,0x02,0x50,0xff,0xd8,0xfb,0x00,0x00, + 0x05,0x20,0xcc,0x0e,0xe8,0x18,0xbb,0x23,0x53,0xa7,0xd7,0xfc,0x92,0x5d,0x5f,0x0e,0x67,0x7c,0x7c,0x98,0x00,0xb6,0xec,0x21,0x9c,0xca,0xad,0x28,0xe1,0x9c,0x0b,0x02,0x3d,0xdf,0x00,0x00, + 0x05,0x20,0xcc,0x7f,0xce,0x2f,0x37,0xa6,0x97,0x5c,0xb4,0x54,0x10,0xac,0x17,0x69,0xfd,0x8b,0xdc,0x29,0x20,0x6e,0x89,0xfa,0xda,0x1b,0x48,0x9e,0xb0,0x59,0x3d,0xe1,0x12,0x64,0x00,0x00, + 0x05,0x20,0xcc,0xd8,0x73,0xec,0xfc,0xf5,0x2b,0x61,0xf5,0xec,0xa0,0x29,0x94,0x9c,0x52,0xc0,0x5d,0xe9,0xc0,0xd7,0xe8,0x38,0xf6,0x1d,0xee,0x5d,0xa7,0x7c,0x11,0x14,0x1f,0xae,0x00,0x00, + 0x05,0x20,0xcd,0xe3,0xa9,0x59,0x8a,0xdf,0xdb,0x76,0x88,0x6a,0xc9,0xf6,0x0c,0x33,0xc1,0x51,0x37,0x66,0xa8,0xbe,0xf6,0x4a,0x5a,0xf9,0x5c,0xb2,0x2a,0x22,0x7a,0x4c,0x0c,0x49,0x00,0x00, + 0x05,0x20,0xce,0x11,0x15,0xb3,0x32,0x69,0xd5,0x83,0x86,0x5a,0x5e,0x01,0xd6,0x34,0x35,0xc8,0x6a,0xdb,0xea,0x70,0x83,0x58,0xf5,0xaa,0x40,0xd1,0x0f,0x2f,0xcb,0x98,0xb8,0xa5,0x00,0x00, + 0x01,0x04,0x02,0x27,0xa3,0xbf,0x20,0x8d, + 0x01,0x04,0x02,0x53,0xf8,0x4d,0x20,0x8d, + 0x01,0x04,0x02,0x57,0x48,0xeb,0x20,0x8d, + 0x01,0x04,0x03,0x09,0xbc,0x2c,0x20,0x8d, + 0x01,0x04,0x03,0x4c,0x8f,0xb9,0x20,0x8d, + 0x01,0x04,0x03,0xe7,0x9a,0xc3,0x20,0x8d, 0x01,0x04,0x05,0x02,0x17,0xe2,0x20,0x8d, + 0x01,0x04,0x05,0x2d,0x48,0x0b,0x20,0x8d, + 0x01,0x04,0x05,0x4e,0x47,0xad,0x20,0x8d, + 0x01,0x04,0x05,0x4e,0x74,0x7f,0x20,0x8d, 0x01,0x04,0x05,0x80,0x57,0x7e,0x20,0x8d, - 0x01,0x04,0x05,0x9d,0x67,0xca,0x20,0x8d, + 0x01,0x04,0x05,0x90,0x58,0x53,0x20,0x8d, + 0x01,0x04,0x05,0xac,0x84,0x68,0x20,0x8d, + 0x01,0x04,0x05,0xba,0x3c,0x0d,0x20,0x8d, 0x01,0x04,0x05,0xbc,0x3e,0x12,0x20,0x8d, - 0x01,0x04,0x05,0xfd,0x12,0xda,0x20,0x8d, - 0x01,0x04,0x05,0xff,0x6d,0xa0,0x20,0x8d, - 0x01,0x04,0x08,0x81,0xb8,0xff,0x20,0x8d, + 0x01,0x04,0x05,0xff,0x61,0x5c,0x20,0x8d, 0x01,0x04,0x08,0xd1,0x46,0x4d,0x20,0x8d, - 0x01,0x04,0x08,0xd2,0x12,0x38,0x20,0x8d, - 0x01,0x04,0x0c,0x22,0x62,0x94,0x20,0x8d, - 0x01,0x04,0x12,0x1b,0x4f,0x11,0x20,0x8d, - 0x01,0x04,0x17,0x5d,0xaa,0x76,0x20,0x8d, - 0x01,0x04,0x17,0x9a,0x88,0x90,0x20,0x8d, - 0x01,0x04,0x17,0xaf,0x00,0xd4,0x20,0x8d, + 0x01,0x04,0x0e,0xcb,0x39,0x32,0x20,0x8d, + 0x01,0x04,0x0f,0xeb,0x52,0xb2,0x20,0x8d, + 0x01,0x04,0x12,0xb7,0x57,0xf0,0x20,0x8d, + 0x01,0x04,0x14,0x59,0xf3,0x8b,0x20,0x8d, + 0x01,0x04,0x17,0x86,0x5e,0x52,0x20,0x8d, + 0x01,0x04,0x17,0x8e,0x91,0xee,0x20,0x8d, 0x01,0x04,0x17,0xaf,0x00,0xde,0x20,0x8d, - 0x01,0x04,0x18,0x54,0xa4,0x32,0x20,0x8d, - 0x01,0x04,0x18,0x56,0x5a,0x7f,0x20,0x8d, - 0x01,0x04,0x18,0x65,0x7e,0xc2,0x20,0x8d, - 0x01,0x04,0x18,0xb7,0x4b,0x9a,0x20,0x8d, - 0x01,0x04,0x1b,0x7c,0x6c,0x13,0x20,0x8d, + 0x01,0x04,0x18,0x06,0x59,0x9b,0x20,0x8d, + 0x01,0x04,0x18,0x24,0x60,0x0e,0x20,0x8d, + 0x01,0x04,0x18,0x4c,0xc7,0x56,0x20,0x8d, + 0x01,0x04,0x18,0x74,0xa3,0xe3,0x20,0x8d, + 0x01,0x04,0x18,0x77,0x29,0xea,0x20,0x8d, + 0x01,0x04,0x18,0x92,0x21,0x0d,0x20,0x8d, + 0x01,0x04,0x18,0x94,0x34,0x6c,0x20,0x8d, + 0x01,0x04,0x18,0x9c,0x2a,0x9a,0x20,0x8d, 0x01,0x04,0x1b,0x94,0xce,0x8c,0x20,0x8d, - 0x01,0x04,0x1f,0x19,0x62,0x10,0x20,0x8d, - 0x01,0x04,0x1f,0x29,0x17,0xf9,0x20,0x8d, - 0x01,0x04,0x1f,0x2f,0xca,0x70,0x20,0x8d, - 0x01,0x04,0x1f,0x9c,0x80,0xf8,0x20,0x8d, - 0x01,0x04,0x1f,0xa4,0xa0,0xa2,0x20,0x8d, - 0x01,0x04,0x1f,0xc9,0xbe,0x86,0x20,0x8d, - 0x01,0x04,0x1f,0xd0,0x22,0x3d,0x20,0x8d, - 0x01,0x04,0x22,0x4e,0x0e,0x19,0x20,0x8d, - 0x01,0x04,0x22,0x50,0x86,0x44,0x20,0x8d, - 0x01,0x04,0x23,0x89,0x85,0xe1,0x20,0x8d, - 0x01,0x04,0x23,0xc1,0xc0,0x30,0x20,0x8d, - 0x01,0x04,0x23,0xc2,0x27,0xfa,0x20,0x8d, - 0x01,0x04,0x25,0x0f,0x3c,0x90,0x20,0x8d, - 0x01,0x04,0x25,0x3c,0xe4,0xfb,0x20,0x8d, - 0x01,0x04,0x25,0x3c,0xe5,0x75,0x20,0x8d, - 0x01,0x04,0x25,0x6e,0x84,0x5e,0x20,0x8d, - 0x01,0x04,0x25,0x78,0xb3,0x1d,0x20,0x8d, - 0x01,0x04,0x25,0x8b,0x66,0x49,0x20,0x8d, + 0x01,0x04,0x1f,0x13,0xcd,0x13,0x20,0x8d, + 0x01,0x04,0x1f,0x1e,0x3b,0xc9,0x20,0x8d, + 0x01,0x04,0x1f,0xbd,0x18,0xbc,0x20,0x8d, + 0x01,0x04,0x23,0xaa,0x4d,0xce,0x20,0x8d, + 0x01,0x04,0x23,0xd0,0x3e,0x82,0x20,0x8d, + 0x01,0x04,0x23,0xd5,0x9f,0xa8,0x20,0x8d, + 0x01,0x04,0x23,0xe4,0xd2,0xc1,0x20,0x8d, + 0x01,0x04,0x23,0xf4,0x09,0xb6,0x20,0x8d, + 0x01,0x04,0x25,0x3c,0xf6,0x52,0x20,0x8d, 0x01,0x04,0x25,0x9d,0xc0,0x5e,0x20,0x8d, - 0x01,0x04,0x25,0xdc,0x87,0x97,0x20,0x8d, - 0x01,0x04,0x26,0x09,0x51,0xa0,0x20,0x8d, - 0x01,0x04,0x26,0x15,0xdd,0xfc,0x20,0x8d, - 0x01,0x04,0x26,0x36,0x0e,0x59,0x20,0x8d, - 0x01,0x04,0x26,0x5b,0x6a,0x6f,0x20,0x8d, + 0x01,0x04,0x25,0xdd,0xc5,0xd0,0x20,0x8d, + 0x01,0x04,0x26,0x26,0xc0,0xf8,0x20,0x8d, + 0x01,0x04,0x26,0x28,0x6e,0x42,0x20,0x8d, + 0x01,0x04,0x26,0x4b,0xd7,0xfa,0x20,0x8d, + 0x01,0x04,0x26,0x4b,0xeb,0x61,0x20,0x8d, 0x01,0x04,0x26,0x66,0x55,0x24,0x20,0x8d, - 0x01,0x04,0x2a,0x02,0xa2,0xda,0x20,0x8d, - 0x01,0x04,0x2b,0x81,0x4b,0x14,0x20,0x8d, + 0x01,0x04,0x26,0x6f,0x72,0x9b,0x20,0x8d, + 0x01,0x04,0x26,0xfe,0x8c,0x28,0x20,0x8d, + 0x01,0x04,0x28,0xa0,0x0d,0x07,0x20,0x8d, 0x01,0x04,0x2b,0x9f,0x3d,0x10,0x20,0x8d, - 0x01,0x04,0x2b,0xe1,0x3e,0x6b,0x20,0x8d, - 0x01,0x04,0x2b,0xf5,0xc4,0xd6,0x20,0x8d, - 0x01,0x04,0x2d,0x0d,0x07,0xdd,0x20,0x8d, - 0x01,0x04,0x2d,0x2c,0xd5,0x7b,0x20,0x8d, - 0x01,0x04,0x2d,0x30,0x4b,0xe0,0x20,0x8d, - 0x01,0x04,0x2d,0x4f,0x4c,0x0c,0x20,0x8d, - 0x01,0x04,0x2d,0x5e,0xd1,0x7f,0x20,0x8d, - 0x01,0x04,0x2d,0x82,0x17,0x39,0x20,0x8d, - 0x01,0x04,0x2d,0x84,0x76,0x19,0x20,0x8d, - 0x01,0x04,0x2d,0x90,0xf9,0xcf,0x20,0x8d, - 0x01,0x04,0x2d,0x91,0x28,0x2b,0x20,0x8d, - 0x01,0x04,0x2d,0x9b,0xa9,0x1e,0x20,0x8d, - 0x01,0x04,0x2e,0x11,0x63,0x0d,0x20,0x8d, - 0x01,0x04,0x2e,0x11,0x63,0x1a,0x20,0x8d, - 0x01,0x04,0x2e,0x15,0xfa,0x19,0x20,0x8d, - 0x01,0x04,0x2e,0x1c,0xcc,0xa1,0x20,0x8d, - 0x01,0x04,0x2e,0x80,0xc7,0x1a,0x20,0x8d, - 0x01,0x04,0x2e,0xa4,0x3b,0x8b,0x20,0x8d, - 0x01,0x04,0x2e,0xa6,0x8e,0x02,0x20,0x8d, - 0x01,0x04,0x2e,0xac,0xe9,0xf1,0x20,0x8d, - 0x01,0x04,0x2e,0xfc,0x05,0x70,0x20,0x8d, - 0x01,0x04,0x2f,0x1c,0x55,0x47,0x20,0x8d, - 0x01,0x04,0x2f,0xb0,0xf8,0xfa,0x20,0x8d, - 0x01,0x04,0x2f,0xc6,0x3c,0xb4,0x20,0x8d, - 0x01,0x04,0x32,0x1b,0x16,0x8d,0x20,0x8d, - 0x01,0x04,0x32,0x27,0xaa,0x95,0x20,0x8d, - 0x01,0x04,0x32,0x35,0xfa,0xa2,0x20,0x8d, - 0x01,0x04,0x33,0x9a,0x3e,0x67,0x20,0x8d, - 0x01,0x04,0x33,0x9e,0x96,0x9b,0x20,0x8d, + 0x01,0x04,0x2b,0xc6,0x9f,0x11,0x20,0x8d, + 0x01,0x04,0x2b,0xe1,0x8f,0x11,0x20,0x8d, + 0x01,0x04,0x2d,0x2d,0x1b,0xe9,0x20,0x8d, + 0x01,0x04,0x2d,0x58,0x6a,0x6b,0x20,0x8d, + 0x01,0x04,0x2d,0x81,0x54,0x88,0x20,0x8d, + 0x01,0x04,0x2d,0x81,0xb5,0x6b,0x20,0x8d, + 0x01,0x04,0x2d,0x82,0x14,0xb1,0x20,0x8d, + 0x01,0x04,0x2d,0x8e,0xeb,0x2e,0x20,0x8d, + 0x01,0x04,0x2d,0x96,0x42,0x0a,0x20,0x8d, + 0x01,0x04,0x2d,0xcf,0x2b,0x6e,0x20,0x8d, + 0x01,0x04,0x2e,0x0a,0xd3,0x8f,0x20,0x8d, + 0x01,0x04,0x2e,0x17,0x57,0xda,0x20,0x8d, + 0x01,0x04,0x2e,0x1c,0xcd,0x44,0x20,0x8d, + 0x01,0x04,0x2e,0x20,0xb2,0x52,0x20,0x8d, + 0x01,0x04,0x2e,0x27,0xa7,0x31,0x20,0x8d, + 0x01,0x04,0x2e,0x3b,0x28,0x5b,0x20,0x8d, + 0x01,0x04,0x2e,0x94,0xeb,0x24,0x20,0x8d, + 0x01,0x04,0x2e,0x96,0xa1,0x2b,0x20,0x8d, + 0x01,0x04,0x2e,0xaf,0xb2,0x03,0x20,0x8d, + 0x01,0x04,0x2e,0xe5,0xee,0xbb,0x20,0x8d, + 0x01,0x04,0x2f,0x0c,0xe4,0x7a,0x20,0x8d, + 0x01,0x04,0x2f,0xb8,0x9f,0xec,0x20,0x8d, + 0x01,0x04,0x2f,0xfe,0xb2,0x2c,0x20,0x8d, + 0x01,0x04,0x32,0x04,0x12,0x5a,0x20,0x8d, + 0x01,0x04,0x32,0x1e,0x24,0x8c,0x20,0x8d, + 0x01,0x04,0x32,0x2d,0x80,0x1c,0x20,0x8d, + 0x01,0x04,0x32,0x4f,0x56,0x71,0x20,0x8d, + 0x01,0x04,0x32,0x7e,0x60,0x16,0x20,0x8d, + 0x01,0x04,0x32,0x90,0x87,0x28,0x20,0x8d, + 0x01,0x04,0x33,0x9a,0x1a,0x0b,0x20,0x8d, 0x01,0x04,0x33,0xae,0xce,0x4c,0x20,0x8d, - 0x01,0x04,0x36,0xd9,0x88,0x7a,0x20,0x8d, - 0x01,0x04,0x36,0xfd,0x0f,0x21,0x20,0x8d, - 0x01,0x04,0x39,0x80,0x60,0x73,0x20,0x8d, - 0x01,0x04,0x39,0x80,0x94,0xa9,0x20,0x8d, - 0x01,0x04,0x3a,0x06,0x2e,0xab,0x20,0x8d, - 0x01,0x04,0x3a,0x60,0x4d,0x72,0x20,0x8d, - 0x01,0x04,0x3a,0x60,0x7b,0x78,0x20,0x8d, - 0x01,0x04,0x3a,0xa8,0xfd,0x23,0x20,0x8d, - 0x01,0x04,0x3b,0xa7,0xbf,0x3c,0x20,0x8d, - 0x01,0x04,0x3c,0xcd,0xcd,0x77,0x20,0x8d, - 0x01,0x04,0x3c,0xd4,0xbd,0x97,0x20,0x8d, - 0x01,0x04,0x3d,0x4a,0x63,0xc1,0x20,0x8d, - 0x01,0x04,0x3e,0x18,0x4c,0x7a,0x20,0x8d, - 0x01,0x04,0x3e,0x6a,0x46,0xf9,0x20,0x8d, + 0x01,0x04,0x33,0xc2,0x0d,0x19,0x20,0x8d, + 0x01,0x04,0x3a,0xe5,0x69,0x26,0x20,0x8d, + 0x01,0x04,0x3b,0xbc,0x6c,0x96,0x20,0x8d, + 0x01,0x04,0x3e,0x0c,0xa8,0x64,0x20,0x8d, 0x01,0x04,0x3e,0xa8,0x41,0x2a,0x20,0x8d, - 0x01,0x04,0x3e,0xab,0x81,0x20,0x20,0x8d, - 0x01,0x04,0x3e,0xf5,0x4b,0x46,0x20,0x8d, - 0x01,0x04,0x3e,0xf8,0x08,0xa7,0x20,0x8d, - 0x01,0x04,0x40,0x17,0x96,0xd3,0x20,0x8d, - 0x01,0x04,0x40,0x62,0x77,0x88,0x20,0x8d, - 0x01,0x04,0x41,0x18,0x4b,0x22,0x20,0x8d, - 0x01,0x04,0x41,0xaf,0xb9,0x65,0x20,0x8d, - 0x01,0x04,0x42,0x2d,0x8d,0x2e,0x20,0x8d, - 0x01,0x04,0x42,0x3a,0xa3,0xb9,0x20,0x8d, - 0x01,0x04,0x42,0x55,0x85,0xb6,0x20,0x8d, - 0x01,0x04,0x42,0xce,0x16,0x1a,0x20,0x8d, - 0x01,0x04,0x43,0x28,0x66,0x21,0x20,0x8d, - 0x01,0x04,0x43,0x2b,0xd2,0x3e,0x20,0x8d, - 0x01,0x04,0x43,0x52,0x88,0xb1,0x20,0x8d, - 0x01,0x04,0x43,0xc1,0x57,0x32,0x20,0x8d, + 0x01,0x04,0x3e,0xb1,0x6f,0x4e,0x20,0x8d, + 0x01,0x04,0x3e,0xd2,0xcf,0x3f,0x20,0x8d, + 0x01,0x04,0x40,0x14,0x2d,0x2a,0x20,0x8d, + 0x01,0x04,0x40,0x1f,0x3d,0x96,0x20,0x8d, + 0x01,0x04,0x40,0x2a,0xb0,0xea,0x20,0x8d, + 0x01,0x04,0x40,0x2e,0x3a,0xac,0x20,0x8d, + 0x01,0x04,0x40,0x44,0xcb,0x0b,0x20,0x8d, + 0x01,0x04,0x40,0x9c,0xc0,0x3d,0x20,0x8d, + 0x01,0x04,0x40,0xb9,0xe1,0x1a,0x20,0x8d, + 0x01,0x04,0x40,0xbb,0xa8,0xc6,0x20,0x8d, + 0x01,0x04,0x40,0xfd,0x68,0x76,0x20,0x8d, + 0x01,0x04,0x42,0x12,0x0d,0xa2,0x20,0x8d, + 0x01,0x04,0x42,0x1d,0x81,0xe9,0x20,0x8d, + 0x01,0x04,0x42,0x23,0x54,0x1e,0x20,0x8d, + 0x01,0x04,0x42,0xc2,0x26,0x2d,0x20,0x8d, + 0x01,0x04,0x42,0xe4,0x1c,0x3f,0x20,0x8d, + 0x01,0x04,0x43,0x91,0xcc,0x12,0x20,0x8d, + 0x01,0x04,0x43,0xcd,0xbe,0x8f,0x20,0x8d, 0x01,0x04,0x43,0xd2,0xe4,0xcb,0x20,0x8d, - 0x01,0x04,0x43,0xd3,0xd3,0x76,0x20,0x8d, - 0x01,0x04,0x43,0xe7,0xf6,0x3a,0x20,0x8d, - 0x01,0x04,0x44,0x06,0x54,0xde,0x20,0x8d, - 0x01,0x04,0x44,0x30,0x88,0xd8,0x20,0x8d, - 0x01,0x04,0x44,0x45,0xaa,0x5c,0x20,0x8d, + 0x01,0x04,0x43,0xd9,0x3d,0xd5,0x20,0x8d, + 0x01,0x04,0x43,0xfb,0x87,0x11,0x20,0x8d, + 0x01,0x04,0x44,0x27,0xbe,0xb9,0x20,0x8d, + 0x01,0x04,0x44,0x4b,0xc3,0x02,0x20,0x8d, + 0x01,0x04,0x44,0x66,0x86,0xe3,0x20,0x8d, + 0x01,0x04,0x44,0xdb,0xf2,0x22,0x20,0x8d, 0x01,0x04,0x45,0x04,0x5e,0xe2,0x20,0x8d, - 0x01,0x04,0x45,0x08,0xaf,0xc9,0x20,0x8d, - 0x01,0x04,0x45,0x39,0xa0,0x31,0x20,0x8d, - 0x01,0x04,0x45,0x70,0x67,0x7c,0x20,0x8d, + 0x01,0x04,0x45,0x8e,0x1c,0x36,0x20,0x8d, + 0x01,0x04,0x45,0x92,0x3e,0x01,0x20,0x8d, + 0x01,0x04,0x45,0xb0,0xbc,0xfb,0x20,0x8d, + 0x01,0x04,0x45,0xb4,0xaa,0xd7,0x20,0x8d, + 0x01,0x04,0x45,0xb5,0x40,0x57,0x20,0x8d, 0x01,0x04,0x45,0xc4,0x98,0x21,0x20,0x8d, - 0x01,0x04,0x47,0x13,0x94,0xb4,0x20,0x8d, - 0x01,0x04,0x49,0xe3,0x99,0xd5,0x20,0x8d, - 0x01,0x04,0x4a,0x32,0x51,0x5d,0x20,0x8d, - 0x01,0x04,0x4a,0x65,0xcd,0xd6,0x20,0x8d, - 0x01,0x04,0x4a,0x76,0x89,0x77,0x20,0x8d, - 0x01,0x04,0x4a,0xd5,0xaf,0x6c,0x20,0x8d, - 0x01,0x04,0x4a,0xd5,0xfb,0xef,0x20,0x8d, + 0x01,0x04,0x46,0x23,0x62,0x0c,0x20,0x8d, + 0x01,0x04,0x46,0x43,0x8b,0xcc,0x20,0x8d, + 0x01,0x04,0x46,0x79,0x32,0x93,0x20,0x8d, + 0x01,0x04,0x46,0xac,0x84,0x4e,0x20,0x8d, + 0x01,0x04,0x47,0xe0,0xc9,0xe0,0x20,0x8d, + 0x01,0x04,0x48,0x12,0x35,0xbd,0x20,0x8d, + 0x01,0x04,0x48,0x2e,0x83,0x12,0x20,0x8d, + 0x01,0x04,0x48,0x32,0xdc,0x05,0x20,0x8d, + 0x01,0x04,0x48,0x47,0xd1,0x60,0x20,0x8d, + 0x01,0x04,0x49,0x23,0xf6,0xaf,0x20,0x8d, + 0x01,0x04,0x49,0x62,0x6b,0x25,0x20,0x8d, + 0x01,0x04,0x49,0x62,0xb2,0xec,0x20,0x8d, + 0x01,0x04,0x49,0x75,0x84,0x8a,0x20,0x8d, + 0x01,0x04,0x49,0x83,0xd1,0x46,0x20,0x8d, + 0x01,0x04,0x49,0x9d,0x70,0xb2,0x20,0x8d, + 0x01,0x04,0x49,0xe4,0xad,0x15,0x20,0x8d, + 0x01,0x04,0x49,0xfd,0x37,0xd9,0x20,0x8d, + 0x01,0x04,0x4a,0x49,0xe5,0x94,0x20,0x8d, + 0x01,0x04,0x4a,0x70,0x73,0xc5,0x20,0x8d, + 0x01,0x04,0x4a,0x76,0x8a,0x7c,0x20,0x8d, + 0x01,0x04,0x4a,0x76,0x8f,0x08,0x20,0x8d, + 0x01,0x04,0x4a,0x85,0x5a,0xfb,0x20,0x8d, + 0x01,0x04,0x4a,0xd5,0xfb,0xe9,0x20,0x8d, 0x01,0x04,0x4a,0xdc,0xff,0xbe,0x20,0x8d, - 0x01,0x04,0x4d,0x14,0x30,0x90,0x20,0x8d, - 0x01,0x04,0x4d,0x15,0x95,0xa0,0x20,0x8d, - 0x01,0x04,0x4d,0x25,0xf0,0xd1,0x20,0x8d, - 0x01,0x04,0x4d,0x2b,0x0e,0x44,0x20,0x8d, - 0x01,0x04,0x4d,0x6f,0x39,0x6d,0x20,0x8d, - 0x01,0x04,0x4d,0xa2,0xbe,0x5a,0x20,0x8d, - 0x01,0x04,0x4d,0xad,0x84,0x8c,0x20,0x8d, - 0x01,0x04,0x4d,0xca,0x0a,0xdc,0x20,0x8d, - 0x01,0x04,0x4e,0x1b,0x8b,0x0d,0x20,0x8d, - 0x01,0x04,0x4e,0x1f,0x47,0xbe,0x20,0x8d, - 0x01,0x04,0x4e,0x23,0x93,0xcb,0x20,0x8d, - 0x01,0x04,0x4e,0x2a,0x90,0x18,0x20,0x8d, - 0x01,0x04,0x4e,0x2b,0x99,0xb9,0x20,0x8d, - 0x01,0x04,0x4e,0x38,0x59,0x92,0x20,0x8d, - 0x01,0x04,0x4e,0x46,0xd0,0x35,0x20,0x8d, - 0x01,0x04,0x4f,0x6d,0x78,0x26,0x20,0x8d, - 0x01,0x04,0x4f,0x74,0x38,0x59,0x20,0x8d, - 0x01,0x04,0x4f,0x7c,0x07,0xfd,0x20,0x8d, - 0x01,0x04,0x4f,0x88,0xfa,0xa2,0x20,0x8d, - 0x01,0x04,0x50,0x53,0xba,0x19,0x20,0x8d, - 0x01,0x04,0x50,0x62,0x4b,0xf8,0x20,0x8d, - 0x01,0x04,0x50,0xe5,0x1c,0x3c,0x20,0x8d, - 0x01,0x04,0x50,0xf4,0x1a,0xc0,0x20,0x8d, - 0x01,0x04,0x51,0x04,0x6e,0xa8,0x20,0x8d, + 0x01,0x04,0x4c,0x71,0x78,0xf6,0x20,0x8d, + 0x01,0x04,0x4c,0x7f,0xd3,0x5a,0x20,0x8d, + 0x01,0x04,0x4c,0x9a,0xa2,0xb6,0x20,0x8d, + 0x01,0x04,0x4d,0x21,0x90,0x9c,0x20,0x8d, + 0x01,0x04,0x4d,0x26,0x03,0x5a,0x20,0x8d, + 0x01,0x04,0x4d,0x64,0x14,0xb2,0x20,0x8d, + 0x01,0x04,0x4d,0x6d,0x70,0xdf,0x20,0x8d, + 0x01,0x04,0x4d,0xa5,0xfa,0x3e,0x20,0x8d, + 0x01,0x04,0x4d,0xdf,0x78,0x8b,0x20,0x8d, + 0x01,0x04,0x4d,0xf0,0xbe,0x29,0x20,0x8d, + 0x01,0x04,0x4e,0x1e,0x39,0x4e,0x20,0x8d, + 0x01,0x04,0x4e,0x9d,0x5b,0x78,0x20,0x8d, + 0x01,0x04,0x4f,0x36,0xf0,0x7c,0x20,0x8d, + 0x01,0x04,0x4f,0x74,0x35,0x32,0x20,0x8d, + 0x01,0x04,0x4f,0x86,0x63,0x72,0x20,0x8d, + 0x01,0x04,0x4f,0x9c,0x8a,0x6b,0x20,0x8d, + 0x01,0x04,0x50,0x3c,0x78,0x77,0x20,0x8d, + 0x01,0x04,0x50,0x40,0xd3,0x66,0x20,0x8d, + 0x01,0x04,0x50,0x40,0xd3,0x67,0x20,0x8d, + 0x01,0x04,0x50,0x5a,0x04,0xb2,0x20,0x8d, + 0x01,0x04,0x50,0x6c,0xdb,0x99,0x20,0x8d, + 0x01,0x04,0x50,0xd1,0xe7,0x7e,0x20,0x8d, + 0x01,0x04,0x50,0xf1,0xc2,0x93,0x20,0x8d, 0x01,0x04,0x51,0x07,0x11,0xca,0x20,0x8d, - 0x01,0x04,0x51,0x13,0x0a,0x02,0x20,0x8d, 0x01,0x04,0x51,0x53,0xd6,0x86,0x20,0x8d, - 0x01,0x04,0x51,0xaa,0x8e,0x64,0x20,0x8d, - 0x01,0x04,0x51,0xab,0x16,0x8f,0x20,0x8d, - 0x01,0x04,0x51,0xf2,0xef,0x8b,0x20,0x8d, + 0x01,0x04,0x51,0xc5,0xb6,0xc3,0x20,0x8d, + 0x01,0x04,0x51,0xe5,0xea,0x57,0x20,0x8d, + 0x01,0x04,0x52,0x0a,0xfa,0x82,0x20,0x8d, + 0x01,0x04,0x52,0x40,0x31,0x1b,0x20,0x8d, 0x01,0x04,0x52,0x42,0x0a,0x0b,0x20,0x8d, - 0x01,0x04,0x52,0x42,0xcc,0xb1,0x20,0x8d, - 0x01,0x04,0x52,0x60,0x60,0x28,0x20,0x8d, - 0x01,0x04,0x52,0x95,0xe1,0xf9,0x20,0x8d, - 0x01,0x04,0x52,0x9b,0x94,0xd3,0x20,0x8d, - 0x01,0x04,0x52,0xb5,0xda,0x85,0x20,0x8d, - 0x01,0x04,0x53,0x63,0xf7,0x19,0x20,0x8d, + 0x01,0x04,0x52,0x47,0x2f,0xd8,0x20,0x8d, + 0x01,0x04,0x52,0x49,0xbc,0xb2,0x20,0x8d, + 0x01,0x04,0x52,0x55,0x6e,0x14,0x20,0x8d, + 0x01,0x04,0x52,0x7c,0x21,0x77,0x20,0x8d, + 0x01,0x04,0x52,0xae,0x8e,0xca,0x20,0x8d, + 0x01,0x04,0x52,0xc3,0xed,0xfb,0x20,0x8d, + 0x01,0x04,0x52,0xda,0x22,0xa2,0x20,0x8d, + 0x01,0x04,0x53,0x31,0x0a,0xe3,0x20,0x8d, + 0x01,0x04,0x53,0x4e,0x70,0x8e,0x20,0x8d, 0x01,0x04,0x53,0x88,0xe8,0x15,0x20,0x8d, - 0x01,0x04,0x53,0xc0,0xe2,0x42,0x20,0x8d, + 0x01,0x04,0x53,0x90,0xb4,0x58,0x20,0x8d, + 0x01,0x04,0x53,0x96,0x02,0x80,0x20,0x8d, + 0x01,0x04,0x53,0xa8,0x41,0xba,0x20,0x8d, 0x01,0x04,0x53,0xd0,0xc1,0xf2,0x20,0x8d, - 0x01,0x04,0x53,0xf0,0x76,0xc4,0x20,0x8d, - 0x01,0x04,0x54,0x07,0xdb,0x82,0x20,0x8d, - 0x01,0x04,0x54,0x34,0x40,0x52,0x20,0x8d, - 0x01,0x04,0x54,0x40,0x63,0x4e,0x20,0x8d, - 0x01,0x04,0x54,0x70,0x3c,0x10,0x20,0x8d, + 0x01,0x04,0x53,0xda,0xa0,0xa1,0x20,0x8d, + 0x01,0x04,0x54,0x20,0xf8,0x3f,0x20,0x8d, + 0x01,0x04,0x54,0x4b,0x00,0xb2,0x20,0x8d, 0x01,0x04,0x54,0x71,0x81,0xc3,0x20,0x8d, - 0x01,0x04,0x54,0xd3,0xbb,0xd3,0x20,0x8d, - 0x01,0x04,0x54,0xd9,0x86,0xd5,0x20,0x8d, - 0x01,0x04,0x54,0xf7,0x80,0x0f,0x20,0x8d, - 0x01,0x04,0x54,0xf7,0x84,0x1b,0x20,0x8d, - 0x01,0x04,0x54,0xf7,0xad,0x75,0x20,0x8d, - 0x01,0x04,0x54,0xf7,0xb3,0x33,0x20,0x8d, - 0x01,0x04,0x54,0xff,0xf5,0xc2,0x20,0x8d, - 0x01,0x04,0x55,0x91,0x4f,0x1a,0x20,0x8d, - 0x01,0x04,0x55,0xad,0xa5,0x42,0x20,0x8d, - 0x01,0x04,0x55,0xc3,0xc4,0x56,0x20,0x8d, - 0x01,0x04,0x55,0xd6,0x76,0x47,0x20,0x8d, - 0x01,0x04,0x56,0x16,0x14,0x0d,0x20,0x8d, - 0x01,0x04,0x56,0x2d,0xee,0x73,0x20,0x8d, - 0x01,0x04,0x56,0xb6,0xdf,0xbd,0x20,0x8d, - 0x01,0x04,0x56,0xd7,0xa8,0x73,0x20,0x8d, - 0x01,0x04,0x57,0x4f,0x5e,0xdd,0x20,0x8d, - 0x01,0x04,0x57,0x5a,0x5e,0x78,0x20,0x8d, - 0x01,0x04,0x57,0x5c,0xab,0x35,0x20,0x8d, + 0x01,0x04,0x54,0xc3,0x74,0x1a,0x20,0x8d, + 0x01,0x04,0x54,0xf6,0xc8,0x7a,0x20,0x8d, + 0x01,0x04,0x54,0xff,0xee,0x78,0x20,0x8d, + 0x01,0x04,0x55,0x0e,0x4f,0x1a,0x20,0x8d, + 0x01,0x04,0x55,0x92,0x73,0x88,0x20,0x8d, + 0x01,0x04,0x55,0x9f,0xed,0x47,0x20,0x8d, + 0x01,0x04,0x55,0xc3,0x53,0x32,0x20,0x8d, + 0x01,0x04,0x55,0xd6,0xa1,0xfc,0x20,0x8d, + 0x01,0x04,0x55,0xd6,0xdf,0x24,0x20,0x8d, + 0x01,0x04,0x55,0xd7,0x4b,0xd2,0x20,0x8d, + 0x01,0x04,0x55,0xea,0x91,0x84,0x20,0x8d, + 0x01,0x04,0x55,0xf6,0x26,0x96,0x20,0x8d, + 0x01,0x04,0x55,0xfc,0xd8,0x92,0x20,0x8d, + 0x01,0x04,0x56,0x29,0x82,0x6c,0x20,0x8d, + 0x01,0x04,0x56,0x65,0x5c,0x5d,0x20,0x8d, + 0x01,0x04,0x56,0x68,0xe4,0x0c,0x20,0x8d, + 0x01,0x04,0x56,0x68,0xe4,0x24,0x20,0x8d, + 0x01,0x04,0x56,0x6d,0x0c,0x3c,0x20,0x8d, + 0x01,0x04,0x56,0x6f,0x30,0x47,0x20,0x8d, + 0x01,0x04,0x56,0x6f,0x30,0x48,0x20,0x8d, + 0x01,0x04,0x56,0x7c,0x91,0xb8,0x20,0x8d, + 0x01,0x04,0x56,0x85,0x85,0x52,0x20,0x8d, + 0x01,0x04,0x57,0x78,0x08,0xef,0x20,0x8d, + 0x01,0x04,0x57,0xb3,0x7a,0x81,0x20,0x8d, 0x01,0x04,0x57,0xec,0xc3,0xc6,0x20,0x8d, - 0x01,0x04,0x57,0xec,0xc7,0xc5,0x20,0x8d, - 0x01,0x04,0x58,0x06,0x1f,0x42,0x20,0x8d, - 0x01,0x04,0x58,0x09,0x49,0xfc,0x20,0x8d, - 0x01,0x04,0x58,0x54,0xdf,0x1e,0x20,0x8d, - 0x01,0x04,0x58,0x92,0x72,0xad,0x20,0x8d, - 0x01,0x04,0x59,0x23,0x8e,0xb1,0x20,0x8d, - 0x01,0x04,0x59,0x2c,0x29,0x8e,0x20,0x8d, - 0x01,0x04,0x59,0x74,0x19,0xea,0x20,0x8d, - 0x01,0x04,0x59,0x75,0x3a,0x71,0x20,0x8d, - 0x01,0x04,0x59,0x75,0xac,0x79,0x20,0x8d, - 0x01,0x04,0x59,0xa5,0xe8,0xf2,0x20,0x8d, - 0x01,0x04,0x59,0xbe,0x8e,0x38,0x20,0x8d, - 0x01,0x04,0x59,0xd8,0x5b,0x78,0x20,0x8d, - 0x01,0x04,0x59,0xf7,0xe0,0x1c,0x20,0x8d, - 0x01,0x04,0x5a,0x92,0xcf,0x43,0x20,0x8d, - 0x01,0x04,0x5a,0x9c,0x1a,0x94,0x20,0x8d, - 0x01,0x04,0x5a,0xa3,0xac,0x4e,0x20,0x8d, - 0x01,0x04,0x5a,0xc0,0x76,0xca,0x20,0x8d, - 0x01,0x04,0x5a,0xd0,0x9f,0x0b,0x20,0x8d, - 0x01,0x04,0x5a,0xf7,0x46,0x1f,0x20,0x8d, - 0x01,0x04,0x5b,0x56,0x19,0xcf,0x20,0x8d, - 0x01,0x04,0x5b,0x7b,0xb6,0xa4,0x20,0x8d, - 0x01,0x04,0x5b,0x7b,0xb7,0xdb,0x20,0x8d, - 0x01,0x04,0x5b,0x86,0x91,0xca,0x20,0x8d, - 0x01,0x04,0x5b,0x87,0x00,0xbb,0x20,0x8d, - 0x01,0x04,0x5b,0x98,0x7a,0x24,0x20,0x8d, - 0x01,0x04,0x5b,0xb8,0xae,0xbf,0x20,0x8d, - 0x01,0x04,0x5b,0xcc,0x95,0x05,0x20,0x8d, - 0x01,0x04,0x5b,0xce,0x11,0xc3,0x20,0x8d, - 0x01,0x04,0x5b,0xd1,0x33,0x83,0x20,0x8d, - 0x01,0x04,0x5b,0xd7,0x5b,0xfe,0x20,0x8d, - 0x01,0x04,0x5b,0xe7,0xb6,0x35,0x20,0x8d, - 0x01,0x04,0x5b,0xec,0xfb,0x89,0x20,0x8d, - 0x01,0x04,0x5b,0xec,0xfb,0x8b,0x20,0x8d, - 0x01,0x04,0x5b,0xed,0x58,0xda,0x20,0x8d, - 0x01,0x04,0x5c,0x1b,0x96,0x2e,0x20,0x8d, - 0x01,0x04,0x5c,0x1b,0x96,0x2f,0x20,0x8d, - 0x01,0x04,0x5c,0x2a,0x6e,0xdb,0x20,0x8d, - 0x01,0x04,0x5c,0x2b,0xbb,0x22,0x20,0x8d, + 0x01,0x04,0x58,0x55,0x58,0x85,0x20,0x8d, + 0x01,0x04,0x58,0x58,0x3a,0xfb,0x20,0x8d, + 0x01,0x04,0x58,0x63,0x47,0xd5,0x20,0x8d, + 0x01,0x04,0x58,0x77,0x80,0x24,0x20,0x8d, + 0x01,0x04,0x58,0x86,0x29,0x58,0x20,0x8d, + 0x01,0x04,0x58,0xd2,0x0f,0x18,0x20,0x8d, + 0x01,0x04,0x58,0xd4,0x35,0xf6,0x20,0x8d, + 0x01,0x04,0x58,0xda,0xe2,0x5b,0x20,0x8d, + 0x01,0x04,0x59,0x01,0x68,0x61,0x20,0x8d, + 0x01,0x04,0x59,0x27,0x6a,0x1a,0x20,0x8d, + 0x01,0x04,0x59,0xb3,0xf0,0x85,0x20,0x8d, + 0x01,0x04,0x59,0xcf,0x83,0x13,0x20,0x8d, + 0x01,0x04,0x59,0xe9,0xcf,0x43,0x20,0x8d, + 0x01,0x04,0x5a,0x1a,0x52,0x2d,0x20,0x8d, + 0x01,0x04,0x5a,0xad,0x76,0x6d,0x20,0x8d, + 0x01,0x04,0x5a,0xfa,0x0a,0xa5,0x20,0x8d, + 0x01,0x04,0x5b,0x5a,0xa6,0xcb,0x20,0x8d, + 0x01,0x04,0x5b,0x5c,0x90,0xe2,0x20,0x8d, + 0x01,0x04,0x5b,0x5c,0x9a,0x12,0x20,0x8d, + 0x01,0x04,0x5b,0xca,0x04,0x41,0x20,0x8d, + 0x01,0x04,0x5b,0xe4,0x2d,0x82,0x20,0x8d, + 0x01,0x04,0x5b,0xef,0x82,0x3e,0x20,0x8d, + 0x01,0x04,0x5b,0xf0,0x54,0x34,0x20,0x8d, + 0x01,0x04,0x5c,0x2a,0x6e,0xd6,0x20,0x8d, + 0x01,0x04,0x5c,0x54,0xbc,0xce,0x20,0x8d, + 0x01,0x04,0x5c,0xcd,0xe8,0x2f,0x20,0x8d, 0x01,0x04,0x5c,0xce,0x69,0x1f,0x20,0x8d, - 0x01,0x04,0x5c,0xe9,0x02,0x3b,0x20,0x8d, - 0x01,0x04,0x5c,0xf0,0xb5,0x2d,0x20,0x8d, - 0x01,0x04,0x5d,0x33,0x0d,0x78,0x20,0x8d, - 0x01,0x04,0x5d,0x39,0x51,0xa2,0x20,0x8d, - 0x01,0x04,0x5d,0x47,0x13,0x82,0x20,0x8d, - 0x01,0x04,0x5d,0x51,0xfe,0x9f,0x20,0x8d, - 0x01,0x04,0x5d,0x5a,0x52,0xe3,0x20,0x8d, - 0x01,0x04,0x5d,0x64,0x23,0xbd,0x20,0x8d, - 0x01,0x04,0x5d,0x67,0x0d,0x01,0x20,0x8d, - 0x01,0x04,0x5d,0x7b,0xb4,0xa4,0x20,0x8d, + 0x01,0x04,0x5c,0xf7,0x31,0xd2,0x20,0x8d, + 0x01,0x04,0x5d,0x10,0x2b,0xf1,0x20,0x8d, + 0x01,0x04,0x5d,0x26,0x7f,0xb3,0x20,0x8d, + 0x01,0x04,0x5d,0x73,0x1a,0x06,0x20,0x8d, 0x01,0x04,0x5d,0xb1,0xbc,0x4a,0x20,0x8d, - 0x01,0x04,0x5d,0xbc,0x66,0x35,0x20,0x8d, - 0x01,0x04,0x5e,0x13,0x07,0x37,0x20,0x8d, - 0x01,0x04,0x5e,0x3f,0x4b,0x4a,0x20,0x8d, - 0x01,0x04,0x5e,0x48,0x8d,0x3d,0x20,0x8d, - 0x01,0x04,0x5e,0x48,0x8f,0x2f,0x20,0x8d, - 0x01,0x04,0x5e,0x69,0x35,0x7c,0x20,0x8d, - 0x01,0x04,0x5e,0xb5,0x2e,0x6a,0x20,0x8d, - 0x01,0x04,0x5e,0xe7,0xfd,0x12,0x20,0x8d, - 0x01,0x04,0x5f,0x2a,0x8c,0x8e,0x20,0x8d, - 0x01,0x04,0x5f,0x52,0x82,0xdf,0x20,0x8d, - 0x01,0x04,0x5f,0x58,0x3d,0xb0,0x20,0x8d, + 0x01,0x04,0x5e,0x13,0x80,0xcc,0x20,0x8d, + 0x01,0x04,0x5e,0x83,0x00,0x49,0x20,0x8d, + 0x01,0x04,0x5e,0x88,0x02,0x7e,0x20,0x8d, + 0x01,0x04,0x5e,0x9c,0x80,0x99,0x20,0x8d, + 0x01,0x04,0x5e,0xcb,0x85,0xfb,0x20,0x8d, + 0x01,0x04,0x5e,0xd2,0x37,0x59,0x20,0x8d, + 0x01,0x04,0x5e,0xf1,0x5a,0xfb,0x20,0x8d, 0x01,0x04,0x5f,0x69,0xac,0xab,0x20,0x8d, - 0x01,0x04,0x5f,0x6e,0xea,0x5d,0x20,0x8d, - 0x01,0x04,0x5f,0xa4,0xb6,0x2c,0x20,0x8d, - 0x01,0x04,0x5f,0xbf,0x82,0x64,0x20,0x8d, - 0x01,0x04,0x60,0x03,0x35,0xfe,0x20,0x8d, - 0x01,0x04,0x61,0x4b,0x90,0x09,0x20,0x8d, - 0x01,0x04,0x62,0x11,0x5f,0x5d,0x20,0x8d, - 0x01,0x04,0x62,0x80,0xe6,0xba,0x20,0x8d, - 0x01,0x04,0x62,0xa3,0xf2,0x95,0x20,0x8d, - 0x01,0x04,0x62,0xe5,0x7e,0x17,0x20,0x8d, - 0x01,0x04,0x63,0xe9,0x14,0xd7,0x20,0x8d, - 0x01,0x04,0x63,0xf6,0x57,0x02,0x20,0x8d, - 0x01,0x04,0x65,0x33,0x8a,0xc2,0x20,0x8d, - 0x01,0x04,0x66,0x82,0x71,0x5e,0x20,0x8d, - 0x01,0x04,0x67,0x63,0xaa,0xd2,0x20,0x8d, - 0x01,0x04,0x67,0x63,0xaa,0xdc,0x20,0x8d, - 0x01,0x04,0x67,0x9c,0xa5,0xab,0x20,0x8d, - 0x01,0x04,0x67,0xdb,0xa9,0x31,0x20,0x8d, - 0x01,0x04,0x68,0xab,0xca,0xf4,0x20,0x8d, - 0x01,0x04,0x68,0xe1,0xdc,0x21,0x20,0x8d, - 0x01,0x04,0x68,0xf4,0x49,0x06,0x20,0x8d, - 0x01,0x04,0x68,0xf4,0x4f,0x83,0x20,0x8d, - 0x01,0x04,0x6c,0x31,0x41,0x84,0x20,0x8d, - 0x01,0x04,0x6d,0x56,0x3c,0x21,0x20,0x8d, - 0x01,0x04,0x6d,0x5b,0x8d,0x91,0x20,0x8d, - 0x01,0x04,0x6d,0x63,0x3f,0x9f,0x20,0x8d, - 0x01,0x04,0x6d,0x78,0xc2,0x88,0x20,0x8d, - 0x01,0x04,0x6d,0xc4,0x7c,0xb6,0x20,0x8d, - 0x01,0x04,0x6d,0xc9,0xa8,0x20,0x20,0x8d, + 0x01,0x04,0x5f,0xa9,0xc4,0xf7,0x20,0x8d, + 0x01,0x04,0x5f,0xd3,0x98,0x64,0x20,0x8d, + 0x01,0x04,0x5f,0xd5,0x91,0xda,0x20,0x8d, + 0x01,0x04,0x60,0x29,0x85,0x3a,0x20,0x8d, + 0x01,0x04,0x60,0x4a,0xb3,0x84,0x20,0x8d, + 0x01,0x04,0x61,0x71,0x8c,0xdf,0x20,0x8d, + 0x01,0x04,0x62,0x0d,0x4d,0x40,0x20,0x8d, + 0x01,0x04,0x62,0x9c,0x6c,0xd3,0x20,0x8d, + 0x01,0x04,0x63,0x5f,0x36,0x9f,0x20,0x8d, + 0x01,0x04,0x63,0xe5,0x6a,0xe1,0x20,0x8d, + 0x01,0x04,0x63,0xf0,0x62,0x24,0x20,0x8d, + 0x01,0x04,0x65,0x20,0x7f,0x8f,0x20,0x8d, + 0x01,0x04,0x65,0x64,0x8b,0xf9,0x20,0x8d, + 0x01,0x04,0x67,0x25,0xcd,0x2f,0x20,0x8d, + 0x01,0x04,0x67,0x2d,0xf7,0xca,0x20,0x8d, + 0x01,0x04,0x67,0x4c,0xcd,0xd5,0x20,0x8d, + 0x01,0x04,0x67,0x63,0xa9,0x6e,0x20,0x8d, + 0x01,0x04,0x67,0x65,0xcb,0x2c,0x20,0x8d, + 0x01,0x04,0x67,0xe7,0x2a,0x24,0x20,0x8d, + 0x01,0x04,0x67,0xe9,0x53,0x1c,0x20,0x8d, + 0x01,0x04,0x68,0x80,0x40,0x3a,0x20,0x8d, + 0x01,0x04,0x68,0x80,0xc9,0xb7,0x20,0x8d, + 0x01,0x04,0x68,0xac,0xeb,0xe3,0x20,0x8d, + 0x01,0x04,0x68,0xdb,0xd6,0xd3,0x20,0x8d, + 0x01,0x04,0x68,0xdd,0x22,0xe2,0x20,0x8d, + 0x01,0x04,0x68,0xe5,0x65,0x4e,0x20,0x8d, + 0x01,0x04,0x68,0xee,0xdc,0xc7,0x20,0x8d, + 0x01,0x04,0x6b,0x94,0x38,0x51,0x20,0x8d, + 0x01,0x04,0x6b,0x94,0x44,0xae,0x20,0x8d, + 0x01,0x04,0x6b,0x9b,0x43,0xd2,0x20,0x8d, + 0x01,0x04,0x6b,0xbf,0x21,0x52,0x20,0x8d, + 0x01,0x04,0x6c,0x1a,0x95,0xa1,0x20,0x8d, + 0x01,0x04,0x6c,0xe1,0xc3,0x35,0x20,0x8d, + 0x01,0x04,0x6d,0x96,0x81,0xe3,0x20,0x8d, + 0x01,0x04,0x6d,0xcf,0x4f,0xf8,0x20,0x8d, 0x01,0x04,0x6d,0xe0,0x54,0x95,0x20,0x8d, - 0x01,0x04,0x6f,0x5a,0x8c,0x2e,0x20,0x8d, - 0x01,0x04,0x70,0x8b,0x0a,0x19,0x20,0x8d, - 0x01,0x04,0x72,0x22,0x82,0xce,0x20,0x8d, - 0x01,0x04,0x74,0x3a,0xab,0x43,0x20,0x8d, + 0x01,0x04,0x6d,0xeb,0xf7,0x7a,0x20,0x8d, + 0x01,0x04,0x6f,0x5a,0x9e,0x7b,0x20,0x8d, + 0x01,0x04,0x6f,0x5a,0x9e,0x89,0x20,0x8d, + 0x01,0x04,0x73,0x8c,0x7c,0x63,0x20,0x8d, 0x01,0x04,0x74,0x56,0xc3,0xc0,0x20,0x8d, - 0x01,0x04,0x77,0x1f,0xb3,0xca,0x20,0x8d, - 0x01,0x04,0x77,0x2a,0x37,0xcb,0x20,0x8d, + 0x01,0x04,0x75,0x30,0x85,0x43,0x20,0x8d, + 0x01,0x04,0x76,0x18,0x25,0xfd,0x20,0x8d, 0x01,0x04,0x78,0xe2,0x27,0x64,0x20,0x8d, - 0x01,0x04,0x78,0xe2,0x27,0x67,0x20,0x8d, - 0x01,0x04,0x79,0x06,0x45,0x49,0x20,0x8d, - 0x01,0x04,0x79,0x63,0xf0,0x57,0x20,0x8d, - 0x01,0x04,0x7a,0x94,0x93,0x88,0x20,0x8d, - 0x01,0x04,0x7a,0xc7,0x28,0x15,0x20,0x8d, - 0x01,0x04,0x7b,0x3c,0xd5,0xc0,0x20,0x8d, - 0x01,0x04,0x7b,0xca,0xc1,0x79,0x20,0x8d, - 0x01,0x04,0x7c,0xaa,0xb6,0xc2,0x20,0x8d, - 0x01,0x04,0x7c,0xc5,0x36,0x71,0x20,0x8d, - 0x01,0x04,0x7d,0xa8,0x6e,0x1c,0x20,0x8d, - 0x01,0x04,0x7d,0xe3,0xb2,0x44,0x20,0x8d, + 0x01,0x04,0x79,0x62,0x16,0x93,0x20,0x8d, + 0x01,0x04,0x7a,0x28,0x19,0x39,0x20,0x8d, + 0x01,0x04,0x80,0x00,0x62,0xd6,0x20,0x8d, 0x01,0x04,0x80,0x00,0xbe,0x1a,0x20,0x8d, - 0x01,0x04,0x81,0x0d,0xbd,0xd7,0x20,0x8d, - 0x01,0x04,0x82,0x2c,0xb0,0x6f,0x20,0x8d, - 0x01,0x04,0x82,0xcc,0xa1,0x03,0x20,0x8d, - 0x01,0x04,0x83,0x99,0xe8,0x8b,0x20,0x8d, - 0x01,0x04,0x83,0xbc,0x28,0x2f,0x20,0x8d, + 0x01,0x04,0x80,0x02,0x0c,0x26,0x20,0x8d, + 0x01,0x04,0x81,0x0a,0x55,0x67,0x20,0x8d, + 0x01,0x04,0x81,0x50,0xc0,0x14,0x20,0x8d, + 0x01,0x04,0x81,0x7e,0xac,0x73,0x20,0x8d, + 0x01,0x04,0x82,0xb4,0xd3,0x7b,0x20,0x8d, + 0x01,0x04,0x82,0xfa,0x07,0xfc,0x20,0x8d, + 0x01,0x04,0x83,0x99,0xcb,0xcd,0x20,0x8d, + 0x01,0x04,0x83,0x99,0xe8,0xc7,0x20,0x8d, + 0x01,0x04,0x83,0x99,0xee,0x79,0x20,0x8d, + 0x01,0x04,0x85,0x03,0xf9,0x9b,0x20,0x8d, + 0x01,0x04,0x85,0x05,0xa5,0xc7,0x20,0x8d, + 0x01,0x04,0x85,0x7d,0x32,0xb4,0x20,0x8d, 0x01,0x04,0x86,0x41,0xc1,0x95,0x20,0x8d, - 0x01,0x04,0x87,0x13,0x29,0xd0,0x20,0x8d, - 0x01,0x04,0x87,0x13,0xfd,0x65,0x20,0x8d, - 0x01,0x04,0x87,0x17,0xcc,0x62,0x20,0x8d, - 0x01,0x04,0x87,0xb5,0xd7,0xed,0x20,0x8d, - 0x01,0x04,0x88,0x37,0x2e,0x0f,0x20,0x8d, - 0x01,0x04,0x88,0x3e,0x3a,0xe0,0x20,0x8d, - 0x01,0x04,0x88,0xaf,0x08,0xaf,0x20,0x8d, - 0x01,0x04,0x88,0xf4,0x13,0x7e,0x20,0x8d, - 0x01,0x04,0x89,0xe2,0x22,0x2e,0x20,0x8d, - 0x01,0x04,0x8a,0x3b,0x14,0xd1,0x20,0x8d, - 0x01,0x04,0x8b,0x3b,0x46,0xa3,0x20,0x8d, - 0x01,0x04,0x8c,0xee,0xdc,0x63,0x20,0x8d, - 0x01,0x04,0x8d,0xc1,0x44,0x0b,0x20,0x8d, - 0x01,0x04,0x8e,0x36,0xb5,0xda,0x20,0x8d, + 0x01,0x04,0x86,0xc3,0xc4,0x41,0x20,0x8d, + 0x01,0x04,0x88,0x31,0x1f,0x58,0x20,0x8d, + 0x01,0x04,0x88,0x3e,0x98,0xfb,0x20,0x8d, + 0x01,0x04,0x88,0xa9,0x34,0x8b,0x20,0x8d, + 0x01,0x04,0x8a,0x02,0x6e,0xd8,0x20,0x8d, + 0x01,0x04,0x8a,0x4b,0x83,0x30,0x20,0x8d, + 0x01,0x04,0x8c,0xba,0xc7,0x0e,0x20,0x8d, + 0x01,0x04,0x8d,0x00,0x9b,0x13,0x20,0x8d, 0x01,0x04,0x8e,0x73,0x8c,0x02,0x20,0x8d, - 0x01,0x04,0x8e,0xbc,0x7d,0xc8,0x20,0x8d, - 0x01,0x04,0x8f,0x6e,0xfc,0x7c,0x20,0x8d, - 0x01,0x04,0x90,0x18,0xec,0x40,0x20,0x8d, - 0x01,0x04,0x90,0x89,0x1d,0xb5,0x20,0x8d, - 0x01,0x04,0x92,0x47,0x45,0x67,0x20,0x8d, - 0x01,0x04,0x95,0x1c,0x9f,0x8d,0x20,0x8d, - 0x01,0x04,0x95,0x8f,0x20,0x1a,0x20,0x8d, - 0x01,0x04,0x95,0xca,0x4f,0xc7,0x20,0x8d, - 0x01,0x04,0x95,0xf8,0x01,0xfe,0x20,0x8d, - 0x01,0x04,0x97,0xf8,0xdd,0xc5,0x20,0x8d, - 0x01,0x04,0x98,0x2c,0x89,0x53,0x20,0x8d, - 0x01,0x04,0x98,0xe6,0xb4,0x73,0x20,0x8d, - 0x01,0x04,0x9a,0x1a,0x89,0x69,0x20,0x8d, - 0x01,0x04,0x9a,0x5c,0x6f,0x64,0x20,0x8d, - 0x01,0x04,0x9d,0x83,0x14,0xae,0x20,0x8d, - 0x01,0x04,0x9e,0x81,0x8c,0xc9,0x20,0x8d, - 0x01,0x04,0x9e,0xb5,0x72,0xc4,0x20,0x8d, - 0x01,0x04,0x9e,0xdc,0x55,0x52,0x20,0x8d, - 0x01,0x04,0x9e,0xdc,0x79,0x5d,0x20,0x8d, - 0x01,0x04,0x9f,0x02,0xbf,0xaf,0x20,0x8d, - 0x01,0x04,0x9f,0xe0,0xee,0x91,0x20,0x8d, - 0x01,0x04,0xa1,0x61,0xa7,0x0a,0x20,0x8d, - 0x01,0x04,0xa2,0xd5,0x77,0x0c,0x20,0x8d, - 0x01,0x04,0xa2,0xe2,0x3d,0x08,0x20,0x8d, - 0x01,0x04,0xa2,0xfe,0xab,0xd1,0x20,0x8d, - 0x01,0x04,0xa3,0x72,0x9f,0xcd,0x20,0x8d, - 0x01,0x04,0xa3,0xac,0x54,0x86,0x20,0x8d, - 0x01,0x04,0xa5,0xff,0xf1,0xb8,0x20,0x8d, - 0x01,0x04,0xa7,0xb3,0x93,0x9b,0x20,0x8d, - 0x01,0x04,0xa9,0x96,0xce,0xce,0x20,0x8d, - 0x01,0x04,0xaa,0x11,0x97,0xeb,0x20,0x8d, - 0x01,0x04,0xaa,0xfe,0x93,0x74,0x20,0x8d, - 0x01,0x04,0xac,0x5c,0x66,0x73,0x20,0x8d, - 0x01,0x04,0xac,0x69,0x15,0xd8,0x20,0x8d, - 0x01,0x04,0xac,0xdb,0xe5,0xfc,0x20,0x8d, - 0x01,0x04,0xac,0xfb,0x65,0x1b,0x20,0x8d, - 0x01,0x04,0xad,0x0c,0x77,0x85,0x20,0x8d, - 0x01,0x04,0xad,0x13,0xb0,0xe4,0x20,0x8d, + 0x01,0x04,0x8e,0xca,0x30,0x7c,0x20,0x8d, + 0x01,0x04,0x8f,0x00,0x8e,0x9c,0x20,0x8d, + 0x01,0x04,0x90,0x02,0x68,0x23,0x20,0x8d, + 0x01,0x04,0x90,0x02,0x68,0xbd,0x20,0x8d, + 0x01,0x04,0x90,0x7e,0x93,0xfc,0x20,0x8d, + 0x01,0x04,0x93,0x1c,0xd3,0x4b,0x20,0x8d, + 0x01,0x04,0x93,0x20,0x5f,0x3e,0x20,0x8d, + 0x01,0x04,0x95,0x07,0xd8,0xb2,0x20,0x8d, + 0x01,0x04,0x95,0x1c,0x74,0x22,0x20,0x8d, + 0x01,0x04,0x95,0x32,0x65,0x0f,0x20,0x8d, + 0x01,0x04,0x95,0x32,0x65,0x1c,0x20,0x8d, + 0x01,0x04,0x98,0x75,0x58,0x2b,0x20,0x8d, + 0x01,0x04,0x98,0xa5,0x26,0xa0,0x20,0x8d, + 0x01,0x04,0x99,0x5c,0x5d,0x72,0x20,0x8d, + 0x01,0x04,0x9a,0x07,0x01,0x72,0x20,0x8d, + 0x01,0x04,0x9a,0x1a,0x82,0x5f,0x20,0x8d, + 0x01,0x04,0x9a,0x1a,0x9a,0x49,0x20,0x8d, + 0x01,0x04,0x9a,0x26,0xa7,0x98,0x20,0x8d, + 0x01,0x04,0x9a,0x41,0x0e,0x13,0x20,0x8d, + 0x01,0x04,0x9b,0x04,0x8e,0x21,0x20,0x8d, + 0x01,0x04,0x9d,0x8f,0x15,0x66,0x20,0x8d, + 0x01,0x04,0x9d,0x93,0x83,0xfb,0x20,0x8d, + 0x01,0x04,0x9e,0xf8,0x22,0x8d,0x20,0x8d, + 0x01,0x04,0x9f,0x8a,0x57,0x12,0x20,0x8d, + 0x01,0x04,0x9f,0xc4,0xe3,0xc4,0x20,0x8d, + 0x01,0x04,0x9f,0xf6,0x19,0x35,0x20,0x8d, + 0x01,0x04,0xa0,0x10,0x6e,0x06,0x20,0x8d, + 0x01,0x04,0xa0,0x50,0x0c,0x10,0x20,0x8d, + 0x01,0x04,0xa0,0x50,0x61,0x42,0x20,0x8d, + 0x01,0x04,0xa1,0x61,0x97,0x09,0x20,0x8d, + 0x01,0x04,0xa2,0x00,0xe2,0x3c,0x20,0x8d, + 0x01,0x04,0xa2,0x37,0x7a,0x5d,0x20,0x8d, + 0x01,0x04,0xa2,0xdb,0x26,0x5e,0x20,0x8d, + 0x01,0x04,0xa2,0xf5,0xc4,0x2d,0x20,0x8d, + 0x01,0x04,0xa4,0x98,0xa7,0xd0,0x20,0x8d, + 0x01,0x04,0xa5,0x16,0xe5,0x58,0x20,0x8d, + 0x01,0x04,0xa6,0x46,0xd3,0x4e,0x20,0x8d, + 0x01,0x04,0xa6,0x4e,0xf1,0x14,0x20,0x8d, + 0x01,0x04,0xa6,0x4e,0xf1,0x19,0x20,0x8d, + 0x01,0x04,0xa7,0x58,0x0b,0xcb,0x20,0x8d, + 0x01,0x04,0xa7,0xf8,0xb9,0xc4,0x20,0x8d, + 0x01,0x04,0xa9,0x9b,0xaa,0xd3,0x20,0x8d, + 0x01,0x04,0xab,0x65,0x49,0x80,0x20,0x8d, + 0x01,0x04,0xac,0x51,0xb6,0xf0,0x20,0x8d, + 0x01,0x04,0xac,0x5c,0x1f,0x2d,0x20,0x8d, + 0x01,0x04,0xac,0x5d,0x6a,0x55,0x20,0x8d, + 0x01,0x04,0xac,0xe9,0xd3,0xab,0x20,0x8d, + 0x01,0x04,0xac,0xea,0x5f,0x23,0x20,0x8d, + 0x01,0x04,0xac,0xf1,0x46,0xec,0x20,0x8d, + 0x01,0x04,0xad,0x42,0xc5,0x13,0x20,0x8d, + 0x01,0x04,0xad,0x57,0xea,0xdc,0x20,0x8d, 0x01,0x04,0xad,0xb5,0x23,0x32,0x20,0x8d, - 0x01,0x04,0xad,0xd4,0x62,0x00,0x20,0x8d, - 0x01,0x04,0xad,0xf1,0xe3,0xf3,0x20,0x8d, - 0x01,0x04,0xad,0xf6,0x1f,0x72,0x20,0x8d, - 0x01,0x04,0xae,0x14,0x39,0x1e,0x20,0x8d, - 0x01,0x04,0xaf,0x1b,0xf7,0x68,0x20,0x8d, - 0x01,0x04,0xaf,0x88,0xae,0xae,0x20,0x8d, - 0x01,0x04,0xb0,0x09,0x11,0x79,0x20,0x8d, - 0x01,0x04,0xb0,0x25,0x52,0x53,0x20,0x8d, + 0x01,0x04,0xad,0xb7,0x82,0x2f,0x20,0x8d, + 0x01,0x04,0xad,0xc5,0xf4,0x9d,0x20,0x8d, + 0x01,0x04,0xae,0x15,0x4c,0x08,0x20,0x8d, + 0x01,0x04,0xae,0x39,0x88,0x48,0x20,0x8d, + 0x01,0x04,0xae,0x3f,0xab,0x4c,0x20,0x8d, + 0x01,0x04,0xae,0x58,0xf3,0x5e,0x20,0x8d, + 0x01,0x04,0xaf,0x6e,0x73,0x78,0x20,0x8d, 0x01,0x04,0xb0,0x4a,0x88,0xed,0x20,0x8d, + 0x01,0x04,0xb0,0x63,0x02,0x5a,0x20,0x8d, + 0x01,0x04,0xb0,0x72,0xf8,0xe1,0x20,0x8d, 0x01,0x04,0xb0,0x76,0xdc,0x1d,0x20,0x8d, - 0x01,0x04,0xb0,0x8a,0xe9,0xa6,0x20,0x8d, - 0x01,0x04,0xb1,0x20,0x32,0xa7,0x20,0x8d, - 0x01,0x04,0xb2,0x15,0x76,0xb2,0x20,0x8d, - 0x01,0x04,0xb2,0x29,0x0b,0xfe,0x20,0x8d, - 0x01,0x04,0xb2,0x4f,0x53,0x93,0x20,0x8d, - 0x01,0x04,0xb2,0x58,0xbd,0xfe,0x20,0x8d, - 0x01,0x04,0xb2,0x9a,0xde,0x68,0x20,0x8d, - 0x01,0x04,0xb2,0x9f,0x62,0x85,0x20,0x8d, - 0x01,0x04,0xb2,0xc6,0x17,0x78,0x20,0x8d, - 0x01,0x04,0xb2,0xfa,0xe8,0x6f,0x20,0x8d, - 0x01,0x04,0xb6,0xe5,0x91,0xa1,0x20,0x8d, + 0x01,0x04,0xb0,0x7e,0x74,0x07,0x20,0x8d, + 0x01,0x04,0xb0,0x88,0xf3,0x3f,0x20,0x8d, + 0x01,0x04,0xb0,0xcd,0x9e,0xc6,0x20,0x8d, + 0x01,0x04,0xb2,0x26,0x06,0x34,0x20,0x8d, 0x01,0x04,0xb7,0x58,0xdf,0xd0,0x20,0x8d, - 0x01,0x04,0xb7,0x81,0xb2,0xcd,0x20,0x8d, - 0x01,0x04,0xb9,0x19,0x30,0xb8,0x20,0x8d, + 0x01,0x04,0xb8,0x38,0x7a,0x45,0x20,0x8d, + 0x01,0x04,0xb8,0x5f,0x20,0x82,0x20,0x8d, + 0x01,0x04,0xb8,0x69,0x83,0xb5,0x20,0x8d, + 0x01,0x04,0xb8,0xab,0xd0,0x6d,0x20,0x8d, + 0x01,0x04,0xb9,0x08,0x6a,0xb3,0x20,0x8d, + 0x01,0x04,0xb9,0x0b,0x3d,0x21,0x20,0x8d, + 0x01,0x04,0xb9,0x13,0x1e,0xf2,0x20,0x8d, 0x01,0x04,0xb9,0x1a,0x63,0xab,0x20,0x8d, + 0x01,0x04,0xb9,0x1f,0x88,0xa6,0x20,0x8d, 0x01,0x04,0xb9,0x1f,0x88,0xf6,0x20,0x8d, - 0x01,0x04,0xb9,0x34,0x5d,0x2d,0x20,0x8d, - 0x01,0x04,0xb9,0x45,0x35,0x99,0x20,0x8d, - 0x01,0x04,0xb9,0x54,0xe0,0x74,0x20,0x8d, - 0x01,0x04,0xb9,0x6b,0x53,0x37,0x20,0x8d, - 0x01,0x04,0xb9,0x74,0x5e,0xef,0x20,0x8d, - 0x01,0x04,0xb9,0x8c,0xd1,0x9f,0x20,0x8d, + 0x01,0x04,0xb9,0x3f,0x61,0xd8,0x20,0x8d, + 0x01,0x04,0xb9,0x40,0x7d,0x10,0x20,0x8d, + 0x01,0x04,0xb9,0x41,0x5d,0x68,0x20,0x8d, + 0x01,0x04,0xb9,0x44,0x43,0x2a,0x20,0x8d, + 0x01,0x04,0xb9,0x46,0x2b,0xc1,0x20,0x8d, + 0x01,0x04,0xb9,0x4e,0xd1,0x1c,0x20,0x8d, + 0x01,0x04,0xb9,0x58,0xe5,0xfe,0x20,0x8d, + 0x01,0x04,0xb9,0x70,0x90,0x77,0x20,0x8d, + 0x01,0x04,0xb9,0x89,0xad,0x7d,0x20,0x8d, + 0x01,0x04,0xb9,0x8c,0xf6,0x8c,0x20,0x8d, + 0x01,0x04,0xb9,0x90,0x53,0x83,0x20,0x8d, 0x01,0x04,0xb9,0x94,0x03,0xe3,0x20,0x8d, - 0x01,0x04,0xb9,0x98,0x8a,0x4a,0x20,0x8d, - 0x01,0x04,0xb9,0x99,0xc4,0x0e,0x20,0x8d, - 0x01,0x04,0xb9,0x99,0xc4,0xa2,0x20,0x8d, - 0x01,0x04,0xb9,0x9c,0x25,0x1e,0x20,0x8d, - 0x01,0x04,0xb9,0x9c,0x9a,0x81,0x20,0x8d, - 0x01,0x04,0xb9,0x9e,0x71,0xac,0x20,0x8d, - 0x01,0x04,0xb9,0xa5,0xaa,0x13,0x20,0x8d, - 0x01,0x04,0xb9,0xbe,0x18,0x48,0x20,0x8d, - 0x01,0x04,0xb9,0xc7,0xd1,0x34,0x20,0x8d, - 0x01,0x04,0xb9,0xcb,0x29,0x94,0x20,0x8d, + 0x01,0x04,0xb9,0x96,0xa2,0x6f,0x20,0x8d, + 0x01,0x04,0xb9,0x9c,0xca,0x23,0x20,0x8d, + 0x01,0x04,0xb9,0xa3,0x2c,0x24,0x20,0x8d, + 0x01,0x04,0xb9,0xc5,0x1e,0x42,0x20,0x8d, + 0x01,0x04,0xb9,0xc5,0xa0,0x3d,0x20,0x8d, 0x01,0x04,0xb9,0xd1,0x0c,0x4c,0x20,0x8d, - 0x01,0x04,0xb9,0xd2,0x7d,0x21,0x20,0x8d, - 0x01,0x04,0xb9,0xe9,0xbd,0xd2,0x20,0x8d, - 0x01,0x04,0xb9,0xfa,0x24,0x42,0x20,0x8d, - 0x01,0x04,0xb9,0xfe,0x61,0xa4,0x20,0x8d, - 0x01,0x04,0xba,0xeb,0x56,0xf9,0x20,0x8d, - 0x01,0x04,0xbc,0x1b,0x4f,0xeb,0x20,0x8d, - 0x01,0x04,0xbc,0x23,0xa7,0x0e,0x20,0x8d, - 0x01,0x04,0xbc,0x44,0x35,0x2c,0x20,0x8d, - 0x01,0x04,0xbc,0x77,0x43,0x89,0x20,0x8d, - 0x01,0x04,0xbc,0x7f,0xf3,0x29,0x20,0x8d, + 0x01,0x04,0xb9,0xef,0xdd,0x17,0x20,0x8d, + 0x01,0x04,0xb9,0xf3,0xda,0x13,0x20,0x8d, + 0x01,0x04,0xb9,0xf3,0xda,0x6a,0x20,0x8d, + 0x01,0x04,0xb9,0xf8,0xa0,0xa3,0x20,0x8d, + 0x01,0x04,0xbc,0x0c,0x95,0xd8,0x20,0x8d, + 0x01,0x04,0xbc,0x3f,0x9e,0xc0,0x20,0x8d, + 0x01,0x04,0xbc,0x8a,0x58,0x2f,0x20,0x8d, 0x01,0x04,0xbc,0x8a,0x70,0x3c,0x20,0x8d, - 0x01,0x04,0xbc,0x8e,0xc7,0x11,0x20,0x8d, - 0x01,0x04,0xbc,0x9b,0x48,0xa0,0x20,0x8d, - 0x01,0x04,0xbc,0xd6,0x81,0x34,0x20,0x8d, - 0x01,0x04,0xbc,0xd6,0x81,0x8b,0x20,0x8d, - 0x01,0x04,0xbc,0xd7,0x3e,0x7a,0x20,0x8d, - 0x01,0x04,0xbc,0xed,0xa7,0x33,0x20,0x8d, - 0x01,0x04,0xbc,0xf6,0xe0,0x0c,0x20,0x8d, - 0x01,0x04,0xbd,0x06,0xdd,0x25,0x20,0x8d, - 0x01,0x04,0xbe,0x02,0x92,0x5a,0x20,0x8d, - 0x01,0x04,0xbe,0x11,0x12,0xbe,0x20,0x8d, - 0x01,0x04,0xbe,0xd2,0x62,0xfd,0x20,0x8d, - 0x01,0x04,0xc0,0x03,0x0b,0x18,0x20,0x8d, - 0x01,0x04,0xc0,0x45,0x35,0x12,0x20,0x8d, - 0x01,0x04,0xc0,0x92,0x89,0x2c,0x20,0x8d, - 0x01,0x04,0xc1,0x16,0x80,0x0c,0x20,0x8d, - 0x01,0x04,0xc1,0x27,0x8e,0x59,0x20,0x8d, - 0x01,0x04,0xc1,0x2e,0x4a,0xfc,0x20,0x8d, - 0x01,0x04,0xc1,0x2e,0x4a,0xfe,0x20,0x8d, - 0x01,0x04,0xc1,0x5f,0xf9,0x03,0x20,0x8d, - 0x01,0x04,0xc1,0x95,0xb0,0xc8,0x20,0x8d, - 0x01,0x04,0xc1,0x97,0x9b,0x7a,0x20,0x8d, - 0x01,0x04,0xc1,0xbb,0x5a,0x7a,0x20,0x8d, - 0x01,0x04,0xc1,0xc4,0x25,0x3e,0x20,0x8d, - 0x01,0x04,0xc2,0x23,0xb8,0x5f,0x20,0x8d, - 0x01,0x04,0xc2,0xa5,0x1e,0x14,0x20,0x8d, - 0x01,0x04,0xc2,0xbf,0xe8,0x99,0x20,0x8d, - 0x01,0x04,0xc3,0x20,0x6c,0xa4,0x20,0x8d, - 0x01,0x04,0xc3,0x38,0x3f,0x0b,0x20,0x8d, + 0x01,0x04,0xbc,0xd5,0x5c,0x27,0x20,0x8d, + 0x01,0x04,0xbc,0xf3,0x47,0x91,0x20,0x8d, + 0x01,0x04,0xbd,0x20,0x88,0x09,0x20,0x8d, + 0x01,0x04,0xbe,0x35,0x64,0x22,0x20,0x8d, + 0x01,0x04,0xbe,0x40,0x86,0x34,0x20,0x8d, + 0x01,0x04,0xbf,0x0d,0x80,0x3a,0x20,0x8d, + 0x01,0x04,0xbf,0xfb,0x20,0xa2,0x20,0x8d, + 0x01,0x04,0xbf,0xff,0xdd,0x25,0x20,0x8d, + 0x01,0x04,0xc0,0x03,0x0b,0x14,0x20,0x8d, + 0x01,0x04,0xc0,0x03,0x0b,0x1a,0x20,0x8d, + 0x01,0x04,0xc0,0x22,0x57,0x56,0x20,0x8d, + 0x01,0x04,0xc0,0xa1,0x30,0x2f,0x20,0x8d, + 0x01,0x04,0xc0,0xbb,0x79,0x2e,0x20,0x8d, + 0x01,0x04,0xc0,0xe3,0x49,0x09,0x20,0x8d, + 0x01,0x04,0xc0,0xf3,0xd7,0x66,0x20,0x8d, + 0x01,0x04,0xc1,0x16,0x80,0x17,0x20,0x8d, + 0x01,0x04,0xc1,0x48,0x20,0xbb,0x20,0x8d, + 0x01,0x04,0xc1,0x54,0x74,0x16,0x20,0x8d, + 0x01,0x04,0xc1,0xb0,0x01,0x4a,0x20,0x8d, + 0x01,0x04,0xc1,0xc8,0xce,0x0e,0x20,0x8d, + 0x01,0x04,0xc1,0xda,0x76,0x0d,0x20,0x8d, + 0x01,0x04,0xc1,0xde,0x82,0x0e,0x20,0x8d, + 0x01,0x04,0xc2,0x00,0x9d,0x06,0x20,0x8d, + 0x01,0x04,0xc2,0x0e,0xf6,0x09,0x20,0x8d, + 0x01,0x04,0xc2,0x43,0x40,0xe5,0x20,0x8d, + 0x01,0x04,0xc2,0x43,0xd0,0xbf,0x20,0x8d, 0x01,0x04,0xc3,0x38,0x3f,0x0c,0x20,0x8d, - 0x01,0x04,0xc3,0x7b,0xd9,0x3f,0x20,0x8d, - 0x01,0x04,0xc3,0x80,0xf8,0x99,0x20,0x8d, - 0x01,0x04,0xc3,0x8c,0xe2,0x9a,0x20,0x8d, - 0x01,0x04,0xc3,0xa0,0xde,0x51,0x20,0x8d, - 0x01,0x04,0xc3,0xce,0x69,0x07,0x20,0x8d, + 0x01,0x04,0xc3,0x9a,0xac,0xb1,0x20,0x8d, + 0x01,0x04,0xc3,0xb5,0xf5,0x95,0x20,0x8d, + 0x01,0x04,0xc3,0xbd,0x61,0x26,0x20,0x8d, + 0x01,0x04,0xc5,0x9b,0x06,0x2b,0x20,0x8d, + 0x01,0x04,0xc6,0x1b,0xae,0x8c,0x20,0x8d, + 0x01,0x04,0xc6,0x62,0x75,0xee,0x20,0x8d, + 0x01,0x04,0xc6,0x9a,0x5d,0x6e,0x20,0x8d, + 0x01,0x04,0xc7,0x07,0x90,0x97,0x20,0x8d, 0x01,0x04,0xc7,0x24,0xfd,0xfc,0x20,0x8d, - 0x01,0x04,0xc7,0x3a,0x64,0x73,0x20,0x8d, - 0x01,0x04,0xca,0x5a,0xf2,0x5d,0x20,0x8d, - 0x01,0x04,0xca,0x70,0xee,0x80,0x20,0x8d, - 0x01,0x04,0xca,0xba,0x26,0x63,0x20,0x8d, - 0x01,0x04,0xcb,0x0c,0x00,0xa7,0x20,0x8d, - 0x01,0x04,0xcb,0x0c,0x0a,0xe0,0x20,0x8d, - 0x01,0x04,0xcb,0xd2,0xc1,0x15,0x20,0x8d, - 0x01,0x04,0xcc,0xe4,0x8e,0xd3,0x20,0x8d, - 0x01,0x04,0xcd,0xb2,0xb6,0x85,0x20,0x8d, - 0x01,0x04,0xce,0x37,0xb2,0x9d,0x20,0x8d, - 0x01,0x04,0xce,0xc0,0xcb,0x00,0x20,0x8d, - 0x01,0x04,0xcf,0x62,0xfd,0x58,0x20,0x8d, - 0x01,0x04,0xcf,0x73,0x54,0x2f,0x20,0x8d, - 0x01,0x04,0xcf,0xff,0xc1,0x2f,0x20,0x8d, - 0x01,0x04,0xd0,0x68,0x5c,0x4a,0x20,0x8d, - 0x01,0x04,0xd1,0x26,0xf4,0x57,0x20,0x8d, - 0x01,0x04,0xd1,0xcc,0x1d,0x12,0x20,0x8d, + 0x01,0x04,0xc8,0x7a,0xb5,0x1a,0x20,0x8d, + 0x01,0x04,0xc8,0xb4,0xc5,0xbc,0x20,0x8d, + 0x01,0x04,0xca,0x07,0xfe,0xfa,0x20,0x8d, + 0x01,0x04,0xca,0xba,0x29,0xdb,0x20,0x8d, + 0x01,0x04,0xcb,0x0b,0x48,0x76,0x20,0x8d, + 0x01,0x04,0xcb,0x0b,0x48,0xc7,0x20,0x8d, + 0x01,0x04,0xcb,0x22,0x3a,0x2b,0x20,0x8d, + 0x01,0x04,0xcb,0x33,0x0b,0xa7,0x20,0x8d, + 0x01,0x04,0xcc,0x0f,0x0b,0x23,0x20,0x8d, + 0x01,0x04,0xcc,0xc2,0xdc,0x27,0x20,0x8d, + 0x01,0x04,0xcc,0xc2,0xdc,0x28,0x20,0x8d, + 0x01,0x04,0xce,0x7d,0xa9,0xa4,0x20,0x8d, + 0x01,0x04,0xce,0xcc,0x6a,0x08,0x20,0x8d, + 0x01,0x04,0xcf,0x42,0x47,0x2e,0x20,0x8d, + 0x01,0x04,0xcf,0x5a,0xc0,0x36,0x20,0x8d, + 0x01,0x04,0xcf,0xb6,0x92,0x82,0x20,0x8d, + 0x01,0x04,0xd0,0x5d,0xe7,0xf0,0x20,0x8d, + 0x01,0x04,0xd1,0x8d,0x25,0x39,0x20,0x8d, + 0x01,0x04,0xd1,0xb1,0x8a,0xf5,0x20,0x8d, 0x01,0x04,0xd1,0xcd,0xcc,0xda,0x20,0x8d, - 0x01,0x04,0xd1,0xed,0x85,0x36,0x20,0x8d, - 0x01,0x04,0xd2,0x06,0x5f,0x7f,0x20,0x8d, - 0x01,0x04,0xd2,0xcd,0x92,0x72,0x20,0x8d, 0x01,0x04,0xd3,0xdd,0x2a,0x8f,0x20,0x8d, - 0x01,0x04,0xd4,0x05,0x9d,0x28,0x20,0x8d, - 0x01,0x04,0xd4,0x33,0x88,0x32,0x20,0x8d, + 0x01,0x04,0xd4,0x0a,0xe5,0xf0,0x20,0x8d, + 0x01,0x04,0xd4,0x1d,0x29,0x9e,0x20,0x8d, + 0x01,0x04,0xd4,0x33,0x81,0x3c,0x20,0x8d, + 0x01,0x04,0xd4,0x44,0xda,0x7c,0x20,0x8d, 0x01,0x04,0xd4,0x56,0x20,0x6a,0x20,0x8d, - 0x01,0x04,0xd4,0xa2,0x98,0x95,0x20,0x8d, - 0x01,0x04,0xd4,0xe3,0x96,0x93,0x20,0x8d, - 0x01,0x04,0xd4,0xe3,0x9b,0xaa,0x20,0x8d, - 0x01,0x04,0xd4,0xfb,0xa2,0xbe,0x20,0x8d, - 0x01,0x04,0xd5,0x6d,0xec,0x81,0x20,0x8d, - 0x01,0x04,0xd5,0x8d,0x9a,0xc9,0x20,0x8d, - 0x01,0x04,0xd5,0xc1,0x53,0xfb,0x20,0x8d, - 0x01,0x04,0xd5,0xc1,0x53,0xfc,0x20,0x8d, - 0x01,0x04,0xd5,0xca,0xe1,0x7a,0x20,0x8d, + 0x01,0x04,0xd4,0x9e,0x85,0xb9,0x20,0x8d, + 0x01,0x04,0xd5,0xa5,0x5f,0x8e,0x20,0x8d, + 0x01,0x04,0xd5,0xae,0x9c,0x51,0x20,0x8d, + 0x01,0x04,0xd5,0xae,0x9c,0x56,0x20,0x8d, + 0x01,0x04,0xd5,0xd9,0xd2,0x5a,0x20,0x8d, + 0x01,0x04,0xd5,0xe3,0x93,0xf4,0x20,0x8d, 0x01,0x04,0xd8,0x53,0x96,0x8e,0x20,0x8d, - 0x01,0x04,0xd8,0xba,0xec,0x62,0x20,0x8d, - 0x01,0x04,0xd8,0xe8,0x21,0x18,0x20,0x8d, + 0x01,0x04,0xd8,0xe2,0x80,0xbd,0x20,0x8d, + 0x01,0x04,0xd9,0x0b,0xf0,0x04,0x20,0x8d, + 0x01,0x04,0xd9,0x14,0x83,0x40,0x20,0x8d, 0x01,0x04,0xd9,0x40,0x2f,0x8a,0x20,0x8d, 0x01,0x04,0xd9,0x40,0x2f,0xc8,0x20,0x8d, - 0x01,0x04,0xd9,0x4c,0x3d,0x4e,0x20,0x8d, - 0x01,0x04,0xd9,0x5c,0x37,0xf6,0x20,0x8d, - 0x01,0x04,0xd9,0x71,0x79,0xa9,0x20,0x8d, 0x01,0x04,0xd9,0x9b,0xf4,0xaa,0x20,0x8d, - 0x01,0x04,0xd9,0xaa,0x7c,0xaa,0x20,0x8d, - 0x01,0x04,0xd9,0xad,0xec,0x19,0x20,0x8d, - 0x01,0x04,0xd9,0xb4,0xc0,0x74,0x20,0x8d, 0x01,0x04,0xd9,0xb4,0xdd,0xa2,0x20,0x8d, - 0x01,0x04,0xda,0x2b,0x7b,0xec,0x20,0x8d, - 0x01,0x04,0xdb,0x4d,0x4f,0x80,0x20,0x8d, - 0x01,0x04,0xdf,0x12,0xde,0xd2,0x20,0x8d, - 0x01,0x04,0xdf,0xa7,0x4b,0xa5,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x16,0x20,0x55,0x66,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x2c,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x16,0x20,0x0a,0x21,0x00,0x00,0xda,0x5e,0xd3,0xff,0xfe,0xe3,0x68,0xa0,0x20,0x8d, + 0x01,0x04,0xd9,0xe6,0x2a,0x37,0x20,0x8d, + 0x01,0x04,0xdb,0x4f,0xc8,0xe9,0x20,0x8d, + 0x01,0x04,0xdc,0x5c,0x8d,0x54,0x20,0x8d, + 0x01,0x04,0xde,0xef,0xa6,0x6c,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x13,0xd8,0x1c,0x01,0x00,0x21,0x02,0x15,0x17,0xff,0xfe,0x63,0x2a,0x7e,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x15,0x28,0x01,0x11,0xff,0xff,0x02,0x14,0x00,0x00,0x00,0x00,0x02,0x07,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x16,0x20,0x54,0x2c,0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x18,0xb8,0x00,0x00,0x01,0x00,0x00,0x00,0xb0,0x0b,0x04,0x20,0x00,0x69,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x19,0xf0,0x00,0x00,0x4f,0x89,0x54,0x00,0x04,0xff,0xfe,0xa0,0x38,0x37,0x20,0x8d, 0x02,0x10,0x20,0x01,0x19,0xf0,0x44,0x01,0x0e,0x8a,0x54,0x00,0x04,0xff,0xfe,0x8e,0xd3,0x98,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x19,0xf0,0x50,0x00,0x1a,0x80,0x54,0x00,0x04,0xff,0xfe,0x71,0xaa,0xc5,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x19,0xf0,0x00,0x05,0x2b,0x12,0x54,0x00,0x04,0xff,0xfe,0x6e,0x3a,0xfe,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x19,0xf0,0x00,0x05,0x5b,0x81,0x5e,0x6f,0x69,0xff,0xfe,0x57,0x94,0xd0,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x19,0xf0,0x68,0x01,0x06,0xec,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x19,0xf0,0xc8,0x00,0x2c,0xe5,0x54,0x00,0x04,0xff,0xfe,0xd7,0x66,0x3d,0x20,0x8d, 0x02,0x10,0x20,0x01,0x1b,0xc0,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x1c,0x03,0x39,0x11,0xd9,0x00,0x4b,0x0c,0x05,0xf2,0x13,0x8a,0x52,0x12,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x1c,0x04,0x13,0x08,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x85,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x1c,0x04,0x40,0x08,0x63,0x00,0x8a,0x5f,0x26,0x78,0x11,0x4b,0xa6,0x60,0x20,0x8d, 0x02,0x10,0x20,0x01,0x40,0x60,0x44,0x19,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0x8f,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x03,0x0e,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x04,0x03,0x3d,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x04,0x05,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x08,0x83,0xcf,0x19,0x5b,0xb2,0x02,0x92,0x71,0xcc,0x5b,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x08,0xed,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x0a,0x69,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x0a,0x6b,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x1b,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x1b,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x09,0x0b,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x0a,0x08,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x1b,0x05,0xa6,0x02,0x16,0x3e,0xff,0xfe,0x24,0x11,0x62,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x75,0xe9,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x10,0x04,0x24,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0x52,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0xba,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x03,0x03,0x14,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x04,0x03,0x0c,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x07,0x00,0x1c,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x07,0x00,0x70,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x0c,0x04,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x28,0x50,0x02,0x06,0x00,0x80,0xbe,0x7b,0xff,0xfe,0xc4,0x9c,0x43,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x1a,0x34,0x00,0x02,0xa8,0x04,0x86,0xff,0xfe,0xc2,0x86,0x3a,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x26,0x04,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x7c,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x28,0x0b,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x71,0x03,0x58,0x60,0x83,0xbe,0x0b,0xcb,0xaa,0x0a,0x97,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x07,0x0b,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, 0x02,0x10,0x20,0x01,0x04,0x70,0x88,0xff,0x00,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x8c,0xa0,0x00,0x02,0x76,0x46,0xa0,0xff,0xfe,0x9b,0xe6,0x62,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x8a,0x71,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x20,0x8d, 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x0a,0x0c,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x0c,0x10,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x04,0x70,0xda,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x03,0x20,0x8d, 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x30,0xb7,0x1d,0x7b,0x6f,0xec,0x4c,0x5c,0x20,0x8d, 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x08,0x8e,0xb4,0xff,0x2a,0xd0,0x69,0x9b,0x20,0x8d, 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x9c,0x1c,0xcc,0x31,0x9f,0xe8,0x55,0x05,0x20,0x8d, @@ -545,1245 +1080,1314 @@ static const uint8_t chainparams_seed_main[] = { 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0xfd,0x76,0xc1,0xd3,0x18,0x54,0x5b,0xd9,0x20,0x8d, 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x01,0x00,0x00,0x00,0x00,0x76,0x76,0x80,0x90,0x20,0x8d, 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x01,0xb9,0x77,0xbd,0x71,0x46,0x12,0x8e,0x40,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x4d,0xd0,0xaf,0x0e,0x35,0x64,0x00,0x00,0x00,0x69,0x00,0x90,0x83,0x33,0x20,0x8d, 0x02,0x10,0x20,0x01,0x4d,0xd0,0xaf,0x0e,0x35,0x64,0x00,0x00,0x00,0x00,0x00,0x69,0x00,0x01,0x20,0x8d, 0x02,0x10,0x20,0x01,0x4d,0xd0,0xaf,0x0e,0x35,0x64,0x00,0x00,0x00,0x00,0x00,0x69,0x00,0x90,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x05,0x60,0x44,0x1f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x05,0xa8,0x40,0xc7,0xf5,0x00,0x7a,0x0d,0x0d,0x50,0x25,0x5e,0xdb,0xac,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x05,0x69,0x50,0x79,0xab,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x05,0xa8,0x40,0xc7,0xf5,0x00,0x26,0x01,0x7c,0xdc,0x1a,0x2d,0x66,0x1c,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x05,0xa8,0x40,0xc7,0xf5,0x01,0xe0,0xaf,0x00,0x1c,0x14,0x68,0xe2,0x72,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x05,0xa8,0x40,0xdb,0x20,0x00,0x86,0x68,0xa7,0x02,0x0c,0x89,0xbd,0xd4,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x05,0xa8,0x40,0xdb,0x20,0x00,0x86,0x7b,0x8a,0xa6,0x20,0x10,0x87,0x9a,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x05,0xa8,0x60,0xc0,0xd5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x20,0x8d, 0x02,0x10,0x20,0x01,0x06,0x38,0xa0,0x00,0x41,0x40,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x47,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x38,0xa0,0x00,0xb1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0x3d,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x48,0x28,0x00,0x01,0x31,0x4b,0x1f,0xf6,0xfc,0x20,0xf7,0xf9,0x9f,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x78,0x06,0x8c,0xff,0xfb,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x95,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x78,0x0d,0x78,0x22,0xd0,0x50,0x65,0xc1,0xff,0xfe,0xf2,0x3f,0x65,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x7c,0x12,0x20,0x08,0x08,0x00,0x00,0x00,0x00,0x93,0xe5,0x08,0x1f,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x7c,0x12,0x54,0x00,0xd1,0xa7,0xb7,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x7c,0x12,0x54,0x00,0xd2,0x6b,0x9c,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, 0x02,0x10,0x20,0x01,0x06,0x7c,0x26,0xb4,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x06,0x7c,0x04,0x40,0x06,0x88,0x00,0x91,0x02,0x36,0x02,0x51,0x01,0x37,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x06,0x7c,0x04,0x40,0x06,0x88,0x00,0x91,0x02,0x36,0x02,0x51,0x01,0x39,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x06,0x7c,0x2d,0xb8,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x20,0x8d, 0x02,0x10,0x20,0x01,0x07,0xc0,0x23,0x10,0x00,0x00,0xf8,0x16,0x3e,0xff,0xfe,0x6c,0x4f,0x58,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x08,0x61,0x0c,0x62,0x2f,0xd0,0xca,0x7f,0x54,0xff,0xfe,0xce,0x06,0xd9,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x07,0xd0,0x84,0x10,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x88,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x80,0x03,0xd1,0x17,0x35,0x00,0xbf,0xc5,0x7e,0x90,0x9d,0xa5,0xa8,0xc0,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x08,0x18,0xdf,0x59,0x58,0x00,0xf8,0xa4,0xce,0xff,0xfe,0xfd,0xd6,0x3a,0x20,0x8d, 0x02,0x10,0x20,0x01,0x08,0x71,0x02,0x3d,0xd5,0xd1,0x5a,0x47,0xca,0xff,0xfe,0x71,0x0c,0x8d,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x08,0x71,0x02,0x5f,0xef,0x0d,0x5e,0x55,0xda,0xd6,0xfe,0x43,0x1e,0x63,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x08,0xb0,0x13,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x08,0xe0,0x14,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x08,0xf8,0x1b,0x69,0x15,0xe5,0xda,0x9e,0xf3,0xff,0xfe,0x75,0xd1,0x0d,0x20,0x8d, 0x02,0x10,0x20,0x01,0x09,0x10,0x10,0x9d,0x2c,0x03,0xd2,0x17,0xc2,0xff,0xfe,0x07,0x2c,0xd9,0x20,0x8d, + 0x02,0x10,0x20,0x01,0xb0,0x11,0x80,0x13,0x3a,0x06,0x0e,0x6a,0x7f,0x23,0x65,0xd3,0xf1,0xdf,0x20,0x8d, + 0x02,0x10,0x20,0x01,0xb0,0x30,0x24,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0x07,0x02,0xe9,0x5b,0xb0,0xa2,0xd5,0x2d,0xb3,0x8a,0xf4,0x04,0xbf,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0x07,0x5d,0x26,0x7f,0xb3,0x6a,0xd1,0x35,0x0a,0xb6,0x5e,0x88,0xdd,0x20,0x8d, 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x61,0x78,0x11,0x04,0x89,0xd2,0xda,0x0e,0x07,0x1a,0xf7,0x20,0x8d, - 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x6b,0x80,0x74,0x32,0xe8,0x92,0x43,0xa3,0x37,0xe6,0x0a,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x6d,0x0c,0xaf,0x3c,0x06,0x69,0x3f,0x73,0xa9,0xe7,0x1b,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x74,0x51,0xd8,0xc2,0x7e,0x42,0x7e,0xfe,0x37,0x63,0x56,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x74,0x51,0xd8,0xf3,0x1f,0x0f,0xdc,0x1c,0x90,0x67,0xac,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0x07,0x0a,0xa7,0xf9,0x3a,0x21,0xb8,0xee,0xe1,0x49,0x73,0xed,0xf9,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x12,0x01,0x07,0x01,0xca,0x1f,0x66,0xff,0xfe,0xc9,0x22,0x1c,0x20,0x8d, 0x02,0x10,0x20,0x01,0x0b,0xc8,0x12,0x01,0x07,0x15,0xca,0x1f,0x66,0xff,0xfe,0xc9,0x5f,0xf0,0x20,0x8d, 0x02,0x10,0x20,0x01,0x0b,0xc8,0x12,0x01,0x07,0x1a,0x2e,0x59,0xe5,0xff,0xfe,0x42,0x52,0xf4,0x20,0x8d, 0x02,0x10,0x20,0x01,0x0b,0xc8,0x16,0x00,0x00,0x00,0x02,0x08,0xa2,0xff,0xfe,0x0c,0x8a,0x2e,0x20,0x8d, - 0x02,0x10,0x20,0x03,0x00,0xdc,0x2f,0x4a,0xeb,0x00,0x4e,0xcc,0x6a,0xff,0xfe,0x25,0xc9,0xa3,0x20,0x8d, - 0x02,0x10,0x20,0x03,0x00,0xf6,0x3f,0x31,0x06,0x00,0x4c,0x9f,0x76,0x20,0x83,0x24,0xd4,0xa7,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x08,0x48,0x50,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x09,0x40,0x40,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x09,0x53,0x80,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0x02,0x20,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0x0f,0x90,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0x3d,0xb0,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0x3f,0x10,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0x49,0xa0,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0x56,0xd0,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x00,0x61,0x80,0x01,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0x56,0xe0,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x10,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x3e,0x54,0x6b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x60,0x05,0x00,0x1d,0x02,0x08,0xa2,0xff,0xfe,0x0c,0x6c,0xc2,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x06,0x10,0x00,0x09,0x46,0xa8,0x42,0xff,0xfe,0x0c,0xd3,0x85,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x07,0x00,0x23,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x07,0x01,0x04,0x09,0xb6,0x83,0x51,0xff,0xfe,0x06,0x75,0xf4,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x07,0x01,0x04,0x0d,0xae,0x16,0x2d,0xff,0xfe,0xa6,0xe8,0x68,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0d,0x08,0x00,0xd9,0x7a,0x02,0x9e,0x6b,0x00,0xff,0xfe,0x56,0xe9,0xb3,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0d,0xf0,0xa2,0x80,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0e,0x68,0x54,0x25,0x28,0x34,0x61,0x8e,0x90,0x69,0xa9,0x77,0x5c,0x66,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0e,0xe0,0x4b,0x4f,0xd4,0x80,0x02,0xe0,0x4c,0xff,0xfe,0x08,0x89,0x98,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0f,0x40,0x09,0x5c,0x8d,0x55,0x70,0x38,0xf1,0x46,0xd2,0xd4,0x01,0x18,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0f,0x40,0x09,0x5c,0x8d,0x55,0x72,0x70,0xfc,0xff,0xfe,0x05,0x03,0xcd,0x20,0x8d, + 0x02,0x10,0x20,0x01,0x0f,0x40,0x09,0x87,0x11,0x82,0x00,0x6f,0xa4,0x6e,0xec,0x5a,0x48,0xaa,0x20,0x8d, + 0x02,0x10,0x20,0x03,0x00,0xd5,0xb7,0x03,0xeb,0x00,0xb2,0x41,0x6f,0xff,0xfe,0x10,0x31,0x2c,0x20,0x8d, + 0x02,0x10,0x20,0x03,0x00,0xdc,0x2f,0x4a,0xc2,0x00,0x4e,0xcc,0x6a,0xff,0xfe,0x25,0xc9,0xa3,0x20,0x8d, + 0x02,0x10,0x20,0x03,0x00,0xe6,0x7f,0x42,0xa9,0x00,0xe6,0x5f,0x01,0xff,0xfe,0xac,0xcb,0xfc,0x20,0x8d, + 0x02,0x10,0x20,0x03,0x00,0xec,0x2f,0x04,0xb1,0x00,0x02,0x11,0x32,0xff,0xfe,0xf7,0xbe,0xef,0x20,0x8d, + 0x02,0x10,0x20,0x03,0x00,0xf0,0xdf,0x08,0xec,0x02,0xaa,0xa1,0x59,0xff,0xfe,0x57,0x77,0x79,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x24,0x11,0x3e,0x05,0xcc,0x00,0x04,0x6a,0x17,0x44,0x4d,0x0f,0xd2,0x6b,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x24,0x11,0xa3,0xe1,0x49,0x00,0x85,0xc8,0x62,0xde,0xe8,0xcc,0x68,0x75,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x40,0x53,0x12,0x03,0x3f,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x01,0x34,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x01,0x4e,0xb0,0x01,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x3e,0xe1,0xd6,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x4e,0x95,0xf3,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x5a,0x68,0x5c,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x89,0x05,0x00,0x00,0x00,0x00,0xf0,0x3c,0x94,0xff,0xfe,0xcc,0x14,0x66,0x20,0x8d, + 0x02,0x10,0x24,0x00,0x89,0x07,0x00,0x00,0x00,0x00,0xf0,0x3c,0x94,0xff,0xfe,0xd9,0x96,0x96,0x20,0x8d, + 0x02,0x10,0x24,0x01,0x25,0x00,0x02,0x04,0x11,0x49,0x01,0x33,0x01,0x25,0x00,0x50,0x01,0x80,0x20,0x8d, 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x20,0x20,0x8d, - 0x02,0x10,0x24,0x02,0xe2,0x80,0x3d,0x17,0x09,0x45,0x18,0x89,0xd3,0xc6,0x8e,0x85,0xd3,0xc4,0x20,0x8d, - 0x02,0x10,0x24,0x03,0x62,0x00,0x88,0x21,0x2f,0xdf,0x39,0x03,0xa2,0xb1,0x00,0x9f,0xc8,0x97,0x20,0x8d, + 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x01,0x10,0x20,0x8d, + 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x01,0x20,0x20,0x8d, + 0x02,0x10,0x24,0x01,0xd0,0x02,0x21,0x03,0x04,0x00,0x02,0x11,0x32,0xff,0xfe,0x9e,0x7a,0xe3,0x20,0x8d, + 0x02,0x10,0x24,0x01,0xd0,0x02,0x39,0x02,0x07,0x00,0xd7,0x2c,0x5e,0x22,0x4e,0x95,0x38,0x9d,0x20,0x8d, + 0x02,0x10,0x24,0x01,0xd0,0x02,0x06,0x02,0x78,0x00,0x28,0x9b,0x8d,0xab,0xd5,0x0e,0xde,0xa2,0x20,0x8d, + 0x02,0x10,0x24,0x02,0xa7,0xc0,0x81,0x00,0xa0,0x15,0x00,0x00,0x00,0x00,0x06,0xf2,0x79,0xa5,0x20,0x8d, + 0x02,0x10,0x24,0x02,0xb8,0x01,0x28,0x7c,0x08,0x00,0x12,0x18,0x45,0xcf,0x2d,0x05,0xcb,0xe4,0x20,0x8d, + 0x02,0x10,0x24,0x03,0x58,0x0c,0xc5,0x05,0x00,0x00,0x69,0x55,0x67,0xd3,0x62,0x29,0x88,0xe7,0x20,0x8d, + 0x02,0x10,0x24,0x03,0x58,0x16,0xc8,0xa3,0x00,0x00,0x26,0x77,0x03,0xff,0xfe,0x03,0x94,0x22,0x20,0x8d, + 0x02,0x10,0x24,0x03,0x71,0xc0,0x20,0x00,0xb3,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x20,0x8d, + 0x02,0x10,0x24,0x03,0x71,0xc0,0x20,0x00,0xb3,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x20,0x8d, + 0x02,0x10,0x24,0x03,0x71,0xc0,0x20,0x00,0xb3,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x93,0x20,0x8d, + 0x02,0x10,0x24,0x04,0x44,0x08,0x63,0x97,0x82,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x50,0x20,0x8d, + 0x02,0x10,0x24,0x05,0x65,0x82,0x0d,0xe0,0x44,0x00,0x08,0xce,0x2b,0x80,0x29,0x60,0x7b,0x4e,0x20,0x8d, + 0x02,0x10,0x24,0x05,0x65,0x82,0x0d,0xe0,0x44,0x00,0x00,0x0f,0x85,0x4d,0x50,0x57,0x4f,0xc9,0x20,0x8d, + 0x02,0x10,0x24,0x05,0xaa,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x8d, + 0x02,0x10,0x24,0x06,0x30,0x03,0x20,0x02,0x3a,0x69,0x38,0x7e,0x3c,0x9a,0x81,0x66,0x10,0x6b,0x20,0x8d, 0x02,0x10,0x24,0x06,0x34,0x00,0x02,0x16,0x8b,0x00,0x02,0x11,0x32,0xff,0xfe,0xca,0x33,0x6b,0x20,0x8d, - 0x02,0x10,0x24,0x06,0xda,0x14,0x03,0x35,0xb6,0x00,0xeb,0x14,0x05,0xfd,0x20,0x72,0x36,0x53,0x20,0x8d, - 0x02,0x10,0x24,0x06,0xda,0x1c,0x05,0x0b,0xcd,0x00,0x3c,0xae,0x17,0x28,0xec,0xfc,0x43,0x34,0x20,0x8d, - 0x02,0x10,0x24,0x06,0xda,0x1c,0x05,0x0b,0xcd,0x03,0x36,0xd6,0x13,0xfa,0xeb,0xa8,0x65,0x43,0x20,0x8d, - 0x02,0x10,0x24,0x06,0xda,0x1e,0x0a,0x4e,0x8a,0x03,0xd9,0x0a,0xfb,0xb0,0x23,0xd3,0xcc,0xb4,0x20,0x8d, + 0x02,0x10,0x24,0x06,0x8c,0x00,0x00,0x00,0x34,0x22,0x01,0x33,0x00,0x18,0x02,0x28,0x01,0x08,0x20,0x8d, + 0x02,0x10,0x24,0x06,0xda,0x12,0x0c,0xe1,0xf0,0x00,0xaf,0xcd,0x2e,0x3a,0x11,0xf6,0x67,0xc0,0x20,0x8d, + 0x02,0x10,0x24,0x06,0xda,0x12,0x0c,0xe1,0xf0,0x01,0x2f,0x6e,0x08,0x91,0x55,0xf0,0x55,0xe1,0x20,0x8d, + 0x02,0x10,0x24,0x06,0xda,0x12,0x0c,0xe1,0xf0,0x01,0x89,0x74,0x8c,0x19,0xba,0xe2,0x52,0x13,0x20,0x8d, + 0x02,0x10,0x24,0x06,0xda,0x12,0x0c,0xe1,0xf0,0x01,0xa7,0x91,0xac,0x49,0x22,0xa4,0x0f,0xd2,0x20,0x8d, + 0x02,0x10,0x24,0x06,0xda,0x1a,0x05,0xb2,0xea,0x00,0xf1,0x7a,0x13,0x19,0xba,0xed,0x15,0x82,0x20,0x8d, + 0x02,0x10,0x24,0x06,0xda,0x1a,0x05,0xb2,0xea,0x01,0x05,0x8c,0x05,0xfb,0xae,0x7c,0x48,0x4c,0x20,0x8d, 0x02,0x10,0x24,0x07,0x36,0x40,0x21,0x07,0x12,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x24,0x07,0x70,0x00,0x9f,0x71,0x2d,0x00,0x1c,0x5a,0x52,0x92,0x51,0x08,0xc7,0x34,0x20,0x8d, - 0x02,0x10,0x24,0x08,0x82,0x07,0x26,0x55,0xfa,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0b,0x20,0x8d, - 0x02,0x10,0x24,0x08,0x82,0x07,0x54,0x56,0xd8,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xc6,0x20,0x8d, - 0x02,0x10,0x24,0x09,0x02,0x50,0x60,0xa0,0x26,0x00,0xa9,0x71,0x1c,0xdd,0x3d,0x5b,0x65,0x4d,0x20,0x8d, + 0x02,0x10,0x24,0x07,0xc8,0x00,0x4f,0x12,0x05,0xe7,0x95,0xe3,0x4b,0xf5,0x0b,0x37,0x86,0xf7,0x20,0x8d, + 0x02,0x10,0x24,0x08,0x82,0x07,0x54,0x55,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x04,0x20,0x8d, + 0x02,0x10,0x24,0x09,0x8a,0x28,0x0e,0xc1,0x68,0x40,0xf7,0xa3,0x88,0xc8,0xca,0xcc,0xfe,0x0a,0x20,0x8d, + 0x02,0x10,0x24,0x09,0x8a,0x7c,0x1e,0x42,0x2a,0x50,0x45,0xd9,0x11,0xd8,0x0b,0x04,0xcb,0xd7,0x20,0x8d, 0x02,0x10,0x24,0x0d,0x00,0x1a,0x04,0xb1,0xe7,0x00,0x00,0x19,0xd9,0xef,0x07,0xf3,0x8e,0x75,0x20,0x8d, - 0x02,0x10,0x26,0x00,0x17,0x00,0x39,0x48,0x08,0x2f,0xce,0x04,0xd3,0x82,0x52,0x26,0x4c,0xac,0x20,0x8d, - 0x02,0x10,0x26,0x00,0x1f,0x16,0x0a,0x08,0xb9,0x00,0x4b,0xfe,0x2f,0x81,0xae,0x31,0x05,0xf5,0x20,0x8d, + 0x02,0x10,0x24,0x0e,0x03,0x8a,0x3e,0x3a,0xcf,0x00,0xa7,0x71,0x2e,0x91,0x51,0xa7,0x2f,0xb4,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x31,0x01,0xb0,0x0f,0x2c,0x96,0x27,0xa0,0x45,0x2c,0xf1,0x86,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x38,0xd5,0x14,0x0f,0xf6,0x4d,0x30,0xff,0xfe,0x63,0x50,0x4e,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x04,0x88,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x21,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x53,0x9e,0xb0,0x0f,0x50,0x54,0x00,0xff,0xfe,0x1b,0x29,0x13,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x54,0x53,0x06,0x9e,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x09,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x5a,0xf3,0x2c,0x10,0x46,0xa8,0x42,0xff,0xfe,0x08,0x58,0x35,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x06,0xb0,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0x94,0x4c,0xe0,0x0f,0x2a,0x27,0xf6,0x64,0x18,0x01,0x59,0x9f,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0xec,0x7b,0x57,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x17,0x00,0xec,0x7b,0x57,0x30,0xf2,0xb6,0x1e,0xff,0xfe,0x70,0x75,0x83,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x00,0x4c,0xc4,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x20,0x06,0x5f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x30,0xa2,0x5e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0xb0,0x3a,0xf2,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0xb0,0x3a,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0xc0,0x22,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0xe0,0x41,0xfa,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x41,0xa0,0xaf,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x00,0x54,0x00,0x06,0xe4,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x19,0x01,0x81,0x80,0x05,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x14,0x04,0x0e,0xe3,0x00,0xce,0xa2,0x19,0xef,0xfa,0x3a,0xe1,0x25,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x16,0x0a,0x08,0xb9,0x00,0x23,0x21,0xe0,0x69,0xcd,0xe4,0x67,0xfb,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x64,0xd9,0x16,0x03,0x44,0x36,0x87,0x1e,0x2b,0xfe,0x74,0x03,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x66,0xfc,0xd7,0x00,0x9b,0x71,0x0f,0x45,0xf3,0xc9,0xc4,0x3b,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x66,0xfc,0xd7,0x01,0xd6,0x8d,0xea,0x70,0x77,0xa0,0x40,0x72,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x71,0x9a,0xe3,0x01,0x77,0x3d,0x13,0x75,0x24,0xfb,0xbf,0x24,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x71,0x9a,0xe3,0x02,0x27,0x58,0x80,0x42,0x92,0x9f,0xa3,0x84,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x71,0x9a,0xe3,0x02,0x4c,0x90,0xe1,0xe6,0x2a,0x59,0x82,0xc4,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x71,0x9a,0xe3,0x02,0xe6,0xc0,0x88,0x78,0x40,0x1c,0x27,0xc2,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x71,0x9a,0xe3,0x02,0xef,0x0c,0x40,0xab,0x0f,0x8f,0x6d,0x6c,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x1f,0x18,0x71,0x9a,0xe3,0x02,0xfa,0x9e,0x86,0xad,0xe4,0x63,0xae,0x17,0x20,0x8d, 0x02,0x10,0x26,0x00,0x1f,0x1c,0x02,0xd3,0x24,0x01,0x69,0x89,0xb1,0xfd,0xd2,0xa6,0xfb,0xc8,0x20,0x8d, - 0x02,0x10,0x26,0x00,0x1f,0x1e,0x02,0xfe,0x36,0x01,0x63,0xa8,0xeb,0xf6,0x83,0xe4,0x19,0x32,0x20,0x8d, 0x02,0x10,0x26,0x00,0x21,0x04,0x10,0x03,0xc5,0xab,0xdc,0x5e,0x90,0xff,0xfe,0x18,0x1d,0x08,0x20,0x8d, - 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x4b,0x0c,0x52,0x20,0x8d, - 0x02,0x10,0x26,0x00,0x3c,0x00,0xe0,0x02,0x2e,0x32,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xc8,0x20,0x8d, - 0x02,0x10,0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x94,0xff,0xfe,0xcc,0xc9,0x9c,0x20,0x8d, - 0x02,0x10,0x26,0x00,0x6c,0x4e,0x0a,0x00,0x0c,0xd0,0x42,0x8d,0x5c,0xff,0xfe,0x58,0x48,0x84,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x92,0x27,0x45,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x94,0xff,0xfe,0xb7,0x4d,0xd7,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x94,0xff,0xfe,0xd1,0x1d,0x3d,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0xe6,0x21,0x46,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x5d,0x09,0xfb,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x94,0xff,0xfe,0x12,0x89,0x38,0x20,0x8d, 0x02,0x10,0x26,0x00,0x6c,0x54,0x71,0x00,0x1a,0xd1,0xc9,0x2e,0x03,0x6d,0x06,0x51,0xbd,0x18,0x20,0x8d, - 0x02,0x10,0x26,0x01,0x01,0x84,0x03,0x00,0x15,0x6c,0xba,0x4c,0x00,0x30,0x09,0xda,0x6c,0x06,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x6c,0x67,0x21,0x00,0x06,0x70,0xb1,0x79,0xbe,0x4c,0x8c,0xca,0xe8,0xf0,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x6c,0x67,0x8a,0x3f,0xe1,0x91,0x42,0x61,0x86,0xff,0xfe,0x4f,0x0a,0xac,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x70,0xff,0xea,0xad,0xbe,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x88,0x01,0x2f,0x80,0x00,0xb2,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x1c,0x20,0x8d, + 0x02,0x10,0x26,0x00,0x88,0x06,0x23,0x00,0x04,0x60,0xa0,0xe6,0x7e,0x10,0xc3,0xa8,0xbb,0x47,0x20,0x8d, + 0x02,0x10,0x26,0x01,0x01,0x52,0x49,0x7f,0x2a,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7b,0x20,0x8d, 0x02,0x10,0x26,0x01,0x01,0x85,0x83,0x02,0x12,0xf0,0x1a,0xb2,0x28,0x40,0x9d,0xe4,0x15,0x50,0x20,0x8d, + 0x02,0x10,0x26,0x01,0x01,0x8c,0x90,0x02,0x3d,0xe5,0x02,0x19,0xd1,0xff,0xfe,0x75,0xdc,0x2f,0x20,0x8d, + 0x02,0x10,0x26,0x01,0x01,0x9c,0x41,0x7e,0x3a,0x11,0x20,0xe7,0xb3,0xff,0xfe,0xcf,0x0a,0x99,0x20,0x8d, + 0x02,0x10,0x26,0x01,0x02,0x43,0x08,0x20,0x58,0x24,0x42,0x16,0x08,0xde,0xe0,0x4a,0xfb,0x54,0x20,0x8d, + 0x02,0x10,0x26,0x01,0x02,0x80,0x5c,0x00,0x04,0x3d,0x4a,0xba,0x4e,0xff,0xfe,0xf8,0x6e,0x5d,0x20,0x8d, + 0x02,0x10,0x26,0x01,0x06,0x03,0x53,0x00,0x83,0xb7,0x00,0x00,0x00,0xff,0xfe,0x00,0x42,0x09,0x20,0x8d, + 0x02,0x10,0x26,0x02,0xfe,0xc3,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x20,0x8d, + 0x02,0x10,0x26,0x02,0xfe,0xc3,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x73,0x20,0x8d, + 0x02,0x10,0x26,0x02,0xff,0xb6,0x00,0x04,0x4d,0x3d,0xf8,0x16,0x3e,0xff,0xfe,0xc6,0x0c,0x15,0x20,0x8d, + 0x02,0x10,0x26,0x02,0xff,0xb6,0x00,0x04,0x73,0x9e,0xf8,0x16,0x3e,0xff,0xfe,0x00,0xc2,0xb3,0x20,0x8d, + 0x02,0x10,0x26,0x02,0xff,0xb6,0x00,0x04,0x7b,0x8e,0xf8,0x16,0x3e,0xff,0xfe,0x9d,0x9d,0xc2,0x20,0x8d, + 0x02,0x10,0x26,0x02,0xff,0xc5,0x02,0x00,0x1e,0x01,0x24,0x1d,0xe5,0x89,0x96,0x50,0xc7,0x73,0x20,0x8d, 0x02,0x10,0x26,0x03,0x30,0x03,0x01,0x1b,0xe1,0x00,0x02,0x0c,0x29,0xff,0xfe,0x38,0xbb,0xc0,0x20,0x8d, - 0x02,0x10,0x26,0x03,0x30,0x04,0x06,0xa1,0x38,0x00,0x85,0x1f,0x58,0x4d,0x7a,0xba,0xaf,0xfb,0x20,0x8d, - 0x02,0x10,0x26,0x03,0x30,0x24,0x18,0xee,0x80,0x00,0x02,0x0e,0xc4,0xff,0xfe,0xd1,0xef,0x15,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x03,0x01,0x1b,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,0x02,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x04,0x07,0x17,0x58,0x00,0x48,0x5b,0x39,0xff,0xfe,0xab,0x1d,0x54,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x05,0x15,0x03,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0xf2,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x07,0x07,0x01,0x80,0x00,0xb7,0xd9,0x9e,0x1e,0x8e,0x0d,0x52,0xfa,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x0a,0x09,0x12,0x62,0x7a,0xbe,0x24,0x11,0xff,0xfe,0x7b,0x39,0xc3,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x15,0x0e,0x21,0x68,0x00,0x15,0xb3,0xd6,0x92,0xa5,0x36,0x12,0xff,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x24,0x1c,0x07,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8c,0x2d,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x30,0x24,0x20,0x05,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf4,0x1b,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x60,0x11,0xaf,0x41,0x72,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x60,0x80,0x90,0x03,0x2f,0xbc,0x60,0xb1,0x6a,0x4e,0xe3,0x64,0xc8,0x5d,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x80,0x01,0x33,0x00,0x7d,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x48,0x20,0x8d, 0x02,0x10,0x26,0x03,0x80,0x80,0x1f,0x07,0x6f,0xdd,0x7d,0xe2,0xd9,0x69,0x78,0xc9,0xb7,0xea,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x80,0x81,0x6c,0x00,0x00,0x77,0x02,0x15,0x5d,0xff,0xfe,0x02,0x15,0x55,0x20,0x8d, + 0x02,0x10,0x26,0x03,0x80,0xa0,0x07,0x00,0x18,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x20,0x8d, 0x02,0x10,0x26,0x04,0x40,0x80,0x10,0x36,0x80,0xb1,0x50,0xe1,0x43,0xff,0xfe,0x0e,0x9d,0xf5,0x20,0x8d, + 0x02,0x10,0x26,0x04,0x45,0x00,0x00,0x06,0x02,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x20,0x8d, + 0x02,0x10,0x26,0x04,0x86,0xc0,0x30,0x01,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x73,0x20,0x8d, + 0x02,0x10,0x26,0x04,0x0a,0x00,0x00,0x03,0x20,0x98,0x02,0x16,0x3e,0xff,0xfe,0x28,0xc4,0x47,0x20,0x8d, + 0x02,0x10,0x26,0x04,0x0a,0x00,0x00,0x50,0x00,0x39,0xc5,0x14,0xbe,0xcd,0xbe,0xce,0xad,0x3a,0x20,0x8d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1c,0x96,0xe0,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1d,0x46,0xc0,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1d,0xef,0x80,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1d,0xfe,0xa0,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x08,0x49,0x60,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0x31,0xe0,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0xc5,0x60,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x10,0x80,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x21,0xc0,0x20,0x00,0x00,0x11,0x02,0x04,0x01,0x94,0x02,0x20,0x00,0x40,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x59,0xc8,0x18,0x00,0x25,0x96,0xc2,0x6c,0xe7,0x80,0x26,0xfd,0xfc,0xf8,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x59,0xc8,0x2a,0x99,0x9d,0x00,0x53,0x77,0x73,0x33,0xef,0xde,0x0d,0x32,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x59,0xc8,0x06,0x1f,0x39,0x00,0x2e,0xfd,0xa1,0xff,0xfe,0xdc,0xf8,0xd4,0x20,0x8d, 0x02,0x10,0x26,0x05,0x64,0x00,0x00,0x30,0xf2,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, - 0x02,0x10,0x26,0x05,0x64,0x00,0x00,0x30,0xfd,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x8d, - 0x02,0x10,0x26,0x05,0xc0,0x00,0x2a,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x64,0x40,0x30,0x01,0x00,0x2f,0x3e,0xec,0xef,0xff,0xfe,0x91,0xf8,0x40,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x64,0x40,0x30,0x01,0x00,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x64,0x40,0x30,0x01,0x00,0x49,0x7e,0xc2,0x55,0xff,0xfe,0xa8,0x31,0xcc,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x64,0x40,0x30,0x01,0x00,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x26,0x05,0x6f,0x80,0x00,0x00,0x00,0x07,0xfc,0x1b,0xcc,0xff,0xfe,0x8a,0xd8,0x22,0x20,0x8d, + 0x02,0x10,0x26,0x05,0xae,0x00,0x02,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x03,0x20,0x8d, 0x02,0x10,0x26,0x06,0x6d,0x00,0x01,0x00,0x51,0x02,0x03,0xd2,0xf0,0x6a,0xc2,0xe8,0x0a,0x54,0x20,0x8d, - 0x02,0x10,0x26,0x07,0x53,0x00,0x00,0x60,0x2e,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x26,0x07,0x53,0x00,0x00,0x61,0x08,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x07,0x53,0x00,0x02,0x03,0x46,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x26,0x07,0x53,0x00,0x00,0x60,0x31,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x14,0x25,0xb5,0x20,0x8d, 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x21,0x9c,0x2f,0x20,0x8d, 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x21,0xbf,0x32,0x20,0x8d, 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x33,0x4d,0x1b,0x20,0x8d, 0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x3d,0x04,0x01,0x20,0x8d, - 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x0d,0x30,0x15,0x20,0x8d, - 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x03,0x26,0x6c,0x20,0x8d, - 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x09,0x93,0x0b,0x20,0x8d, - 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x0b,0x30,0x11,0x20,0x8d, - 0x02,0x10,0x28,0x00,0x01,0x50,0x01,0x1d,0x24,0x26,0x06,0x2b,0xb1,0x64,0x70,0x4a,0x69,0x62,0x20,0x8d, - 0x02,0x10,0x28,0x00,0x03,0x00,0x82,0x51,0x0b,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x20,0x8d, - 0x02,0x10,0x28,0x00,0x03,0x00,0x82,0x51,0x0b,0x50,0x0e,0x92,0x64,0xf5,0x22,0xaf,0xc3,0x1e,0x20,0x8d, - 0x02,0x10,0x28,0x00,0x00,0x40,0x00,0x15,0x06,0xad,0x48,0xe8,0x22,0x00,0xa8,0x82,0xe0,0x8e,0x20,0x8d, + 0x02,0x10,0x26,0x07,0xf2,0xc0,0xe0,0x45,0xf2,0xe0,0xfe,0x4c,0x0f,0xbb,0x6c,0x99,0x12,0x20,0x20,0x8d, + 0x02,0x10,0x26,0x07,0xf2,0xc0,0xf0,0x0e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x20,0x8d, + 0x02,0x10,0x26,0x07,0xf2,0xf8,0xad,0x40,0xea,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x07,0xfd,0xc0,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xca,0x20,0x8d, + 0x02,0x10,0x26,0x07,0xfe,0xa8,0x60,0x1e,0x7d,0x01,0xbe,0x24,0x11,0xff,0xfe,0x89,0x27,0xf3,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x01,0x1c,0x50,0x01,0x11,0x18,0xd2,0x67,0xe5,0xff,0xfe,0xe9,0xe6,0x73,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x01,0x1c,0x50,0x01,0x21,0x99,0xd2,0x67,0xe5,0xff,0xfe,0xe9,0xe6,0x73,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0x06,0x20,0x03,0x01,0x05,0x06,0x7c,0x16,0xff,0xfe,0x51,0x58,0xbf,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0x6e,0xa0,0x00,0x00,0x01,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x42,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x09,0x74,0x2a,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x0d,0x7f,0x1d,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x06,0x49,0xc8,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x0b,0x38,0x8a,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xca,0xa0,0x00,0xbe,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xca,0xa0,0x00,0xbe,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xca,0xa0,0x00,0xbe,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xca,0xa0,0x00,0xbe,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x20,0x8d, + 0x02,0x10,0x26,0x20,0x00,0xca,0xa0,0x00,0xbe,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x20,0x8d, + 0x02,0x10,0x28,0x00,0x01,0x50,0x01,0x1d,0x10,0x93,0xc9,0xe3,0x1e,0xf4,0x0b,0xc4,0x25,0x0d,0x20,0x8d, + 0x02,0x10,0x28,0x00,0x00,0x40,0x00,0x17,0x02,0x4f,0x4d,0x95,0xe1,0x30,0x7f,0x97,0x90,0xf2,0x20,0x8d, + 0x02,0x10,0x28,0x00,0x00,0x40,0x00,0x18,0x07,0xd1,0xa2,0x36,0xbc,0xff,0xfe,0x58,0xb6,0xec,0x20,0x8d, + 0x02,0x10,0x28,0x00,0x00,0x40,0x00,0x74,0x4b,0x8b,0xf6,0x73,0xdb,0x63,0x6f,0x6f,0x23,0x10,0x20,0x8d, 0x02,0x10,0x28,0x03,0x51,0x80,0x41,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x28,0x03,0x98,0x00,0x94,0x47,0x84,0xbb,0xca,0xb8,0xd2,0xf5,0x38,0x8c,0x9a,0x57,0x20,0x8d, + 0x02,0x10,0x28,0x03,0x98,0x00,0x94,0x47,0x84,0xbb,0xb8,0x7f,0x1d,0xf2,0xff,0x01,0x1c,0x28,0x20,0x8d, + 0x02,0x10,0x28,0x03,0x98,0x00,0xa0,0x07,0x83,0x91,0x1f,0xd7,0xc2,0x63,0xa5,0x5b,0xb9,0xfb,0x20,0x8d, + 0x02,0x10,0x28,0x04,0x01,0x4c,0x65,0xd7,0x8e,0xa5,0x60,0x60,0x21,0x02,0x6b,0xa6,0x56,0x14,0x20,0x8d, 0x02,0x10,0x28,0x04,0x01,0x4d,0x7e,0x33,0x83,0xb0,0x6e,0x41,0x1c,0xcc,0xcf,0x20,0xaf,0xf9,0x20,0x8d, + 0x02,0x10,0x28,0x04,0x22,0x9c,0x82,0x00,0x18,0xd6,0x01,0x4a,0xd8,0xc8,0xb4,0xdd,0x3f,0x25,0x20,0x8d, 0x02,0x10,0x28,0x04,0x04,0x31,0xe0,0x38,0xcd,0x01,0xaa,0xa1,0x59,0xff,0xfe,0x0d,0x44,0xb8,0x20,0x8d, - 0x02,0x10,0x28,0x04,0x0d,0x57,0x45,0x0d,0x0f,0x00,0xa4,0x22,0x98,0x28,0xb0,0x0e,0x91,0xe9,0x20,0x8d, - 0x02,0x10,0x28,0x06,0x02,0xf0,0x50,0x20,0xd2,0x87,0x4d,0xcd,0x62,0x04,0x90,0x9b,0x41,0x25,0x20,0x8d, + 0x02,0x10,0x28,0x04,0x0d,0x41,0xe0,0x28,0x59,0x00,0x0a,0xea,0x42,0x36,0x2d,0x76,0x1e,0xb9,0x20,0x8d, + 0x02,0x10,0x28,0x04,0x0d,0x45,0xcb,0x22,0xef,0x00,0xf8,0x9c,0xd0,0x38,0x2a,0x36,0xa3,0xfa,0x20,0x8d, + 0x02,0x10,0x28,0x04,0x0d,0x57,0x4b,0x3d,0x7d,0x00,0x75,0x2d,0x1d,0x78,0x6b,0x32,0xf7,0x1c,0x20,0x8d, + 0x02,0x10,0x28,0x04,0x0d,0x57,0x59,0x49,0x18,0x00,0x02,0xa0,0x98,0xff,0xfe,0x79,0x33,0x9b,0x20,0x8d, + 0x02,0x10,0x28,0x04,0x0f,0xec,0xd2,0xd8,0x61,0x00,0xfa,0x63,0x2e,0xcd,0x48,0xa0,0x2f,0x34,0x20,0x8d, + 0x02,0x10,0x28,0x06,0x10,0x3e,0x00,0x1b,0x48,0x35,0xa7,0x87,0x2e,0xa5,0x90,0x25,0xaa,0xa7,0x20,0x8d, + 0x02,0x10,0x28,0x06,0x02,0x67,0x14,0x8a,0x1d,0x10,0xdc,0x4b,0x36,0x94,0x42,0x3b,0xb6,0xb4,0x20,0x8d, + 0x02,0x10,0x28,0x06,0x02,0xf0,0x80,0xe1,0xe1,0x7b,0x35,0x29,0x08,0xaa,0x09,0x0c,0x50,0x9a,0x20,0x8d, + 0x02,0x10,0x28,0x06,0x02,0xf0,0xa4,0x81,0xc5,0x85,0x06,0x03,0x47,0x8e,0x57,0xf9,0x40,0x9e,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x11,0x69,0x01,0x14,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x11,0x90,0xc0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xbe,0x13,0x37,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x11,0xc0,0x00,0x60,0x02,0x94,0xc4,0x8f,0xbe,0xff,0xfe,0x15,0xa9,0x7f,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x12,0x98,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0x42,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x12,0xe0,0x01,0x01,0x00,0x99,0x02,0x0c,0x29,0xff,0xfe,0x29,0xd0,0x3f,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x13,0x98,0x00,0x04,0x2a,0x03,0x3e,0xec,0xef,0xff,0xfe,0x05,0xd9,0x3e,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x13,0x98,0x00,0x04,0x2a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x03,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x13,0xa0,0x30,0x15,0x00,0x01,0x00,0x85,0x00,0x14,0x00,0x79,0x00,0x26,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x6a,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x1a,0x08,0xff,0xff,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x1f,0x40,0x50,0x01,0x01,0x08,0x5d,0x17,0x77,0x03,0xb0,0xf5,0x41,0x33,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x1f,0x40,0x50,0x01,0x03,0x86,0xde,0xad,0xbe,0xef,0xb1,0xac,0xc0,0xfe,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x23,0xc5,0xfe,0x80,0x73,0x01,0xd6,0xae,0x52,0xff,0xfe,0xd5,0x56,0xa5,0x20,0x8d, 0x02,0x10,0x2a,0x00,0x23,0xc6,0x5c,0x8a,0x5c,0x00,0xc0,0x5a,0x4d,0xff,0xfe,0x65,0x9d,0x69,0x20,0x8d, - 0x02,0x10,0x2a,0x00,0x60,0x20,0x45,0x03,0x37,0x00,0x50,0x54,0x00,0xff,0xfe,0x90,0x64,0x0e,0x20,0x8d, - 0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x89,0x20,0x00,0x50,0x54,0x00,0xff,0xfe,0xfc,0x5e,0xd8,0x20,0x8d, - 0x02,0x10,0x2a,0x00,0x8a,0x60,0xe0,0x12,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x4d,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x59,0x80,0x00,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x35,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x60,0x20,0x49,0x14,0x57,0x00,0xdb,0x31,0xca,0x50,0x07,0x97,0xc4,0x68,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x60,0x20,0x50,0x9e,0xa4,0x00,0x02,0x11,0x32,0xff,0xfe,0x5c,0x36,0x9c,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x06,0x0e,0x00,0x07,0x9e,0x9a,0xd6,0x91,0x81,0xeb,0xb8,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x89,0x20,0x00,0x00,0x42,0xc0,0xff,0xfe,0xa8,0xb2,0x09,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x4e,0xb7,0xc0,0x00,0x00,0x00,0x00,0x20,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x8a,0x60,0xe0,0x12,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0xa0,0x40,0x01,0x99,0x84,0xfa,0x1a,0xc0,0x4d,0xff,0xfe,0x41,0x3e,0x93,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0xbb,0xa0,0x12,0x04,0x37,0x00,0x02,0x1e,0x06,0xff,0xfe,0x4a,0x53,0x78,0x20,0x8d, 0x02,0x10,0x2a,0x00,0xbb,0xe0,0x00,0x00,0x22,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x46,0x20,0x8d, - 0x02,0x10,0x2a,0x00,0xd5,0x20,0x00,0x09,0x93,0x00,0x42,0x0b,0x54,0x4e,0x80,0x19,0x6d,0x3a,0x20,0x8d, - 0x02,0x10,0x2a,0x00,0xfd,0x40,0x00,0x0c,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0xd4,0xe0,0x00,0xff,0xfc,0x02,0x9e,0x6b,0x00,0xff,0xfe,0x17,0x61,0x15,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0xd8,0x80,0x00,0x05,0x00,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0xd3,0x29,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x0e,0xe2,0x4d,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x00,0x0e,0xe2,0x4d,0x00,0x06,0xb0,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x02,0x38,0x42,0x5f,0x46,0x00,0xbb,0xb8,0x16,0xd6,0xe9,0x07,0xcb,0x6f,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x02,0x39,0x02,0x65,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x02,0x61,0x02,0x18,0x3f,0x00,0x8d,0x0f,0x21,0x05,0xc6,0x57,0x4a,0xe7,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x4b,0x00,0x80,0x7c,0x31,0x00,0x0a,0x36,0xc9,0xff,0xfe,0x7e,0xde,0x5f,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x4b,0x00,0xb9,0x06,0xf1,0x00,0xd8,0x12,0x4f,0x64,0xa9,0x31,0x19,0xb7,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x4b,0x00,0xb9,0x06,0xf1,0x00,0xde,0xa6,0x32,0xff,0xfe,0xd5,0xf1,0x42,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x4b,0x00,0xbf,0x1b,0x72,0x00,0xd8,0x26,0x7d,0x6f,0x0b,0x13,0x27,0x6c,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x71,0x16,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x71,0x1f,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x00,0x72,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x02,0x42,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x42,0x20,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x61,0x42,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x72,0x4c,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x1a,0xa9,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x1a,0xaf,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x2b,0x02,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x5a,0x44,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x42,0x42,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x52,0x1c,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x71,0x5c,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x1a,0xaa,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x4a,0x51,0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x5a,0x16,0xcb,0x87,0x6a,0xbc,0xe7,0xb3,0xc8,0x11,0x8a,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x5a,0x25,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xff,0x01,0xf0,0x85,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xff,0x01,0xf0,0x91,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xff,0x01,0xf0,0xec,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xff,0x00,0xf0,0xcc,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x04,0xff,0x00,0xf0,0xe4,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x05,0xa8,0x03,0x03,0x13,0xac,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x05,0xa8,0x03,0x08,0x43,0x33,0x40,0x74,0x6a,0xff,0xfe,0x9c,0xf5,0xd2,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x07,0xa7,0x00,0x02,0x28,0x04,0xae,0x1f,0x6b,0xff,0xfe,0x9d,0x6c,0x94,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x07,0xc8,0xaa,0xac,0x00,0x89,0x50,0x54,0x00,0xff,0xfe,0xb7,0xf5,0xcb,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x07,0xc8,0xaa,0xc2,0x01,0x80,0x50,0x54,0x00,0xff,0xfe,0x56,0x8d,0x10,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x87,0x40,0x00,0x01,0x07,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0xe5,0xcb,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x87,0x40,0x00,0x01,0xff,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x28,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x87,0x40,0x00,0x01,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x8c,0x6a,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0xcb,0x00,0x07,0x90,0xf5,0x00,0x11,0x0b,0xb4,0x46,0x22,0x60,0x7d,0x2c,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0xcb,0x10,0x03,0x36,0xcb,0x00,0x61,0xac,0xd1,0x5d,0x4a,0xc0,0x2c,0xbd,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0xcb,0x10,0x03,0x36,0xcb,0x00,0xd2,0x37,0x45,0xff,0xfe,0xc5,0x2c,0xd0,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0xcb,0x15,0x80,0x4c,0x80,0x00,0x02,0x1e,0x06,0xff,0xfe,0x51,0x2c,0x32,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x01,0x85,0x55,0xf0,0xa0,0xba,0x9e,0xaf,0x98,0x53,0x92,0xb7,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x03,0x01,0x70,0x10,0xb8,0x7d,0xe1,0x4b,0xce,0xa9,0xb9,0x98,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0xcb,0x00,0x13,0x9e,0x0a,0x00,0x14,0x2d,0xfe,0xc1,0xd0,0xdf,0xda,0x18,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0xcb,0x00,0x14,0x28,0xea,0x00,0x8a,0x4c,0x1b,0x72,0xf9,0x59,0x0c,0xa4,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0xcb,0x10,0x02,0x49,0x73,0x00,0x00,0x0b,0x00,0x0c,0x00,0x0b,0x00,0x0c,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x01,0xc1,0xa3,0xe0,0x44,0x3b,0xbc,0xab,0x77,0x78,0xb0,0x3b,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x02,0x52,0x6b,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x03,0xb3,0x14,0x20,0x7c,0xa0,0x3a,0x9a,0x5c,0xc3,0xb6,0x44,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x00,0x05,0x93,0x90,0xbf,0x35,0x4d,0x41,0x8a,0x2a,0x05,0x70,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x05,0x7b,0x00,0xa0,0x70,0x39,0x12,0xe3,0x65,0x47,0x28,0x49,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x08,0x3d,0xdd,0x30,0x24,0x6a,0x4a,0xf7,0x53,0xf4,0x8d,0x65,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x09,0xe9,0xc2,0x40,0x8e,0x3a,0xaf,0x64,0x04,0xf0,0x8f,0x79,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x0b,0x0f,0x37,0xe0,0xa1,0x3f,0x0e,0x65,0xac,0x42,0x8e,0x36,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x00,0xb5,0x7f,0x50,0xc2,0x57,0xa5,0x5b,0x48,0x46,0x97,0xe1,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x0b,0xf6,0x8d,0x70,0x02,0x0c,0x29,0xff,0xfe,0x30,0x4f,0xd2,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x00,0xb7,0x7d,0xb0,0x02,0x4e,0x01,0xff,0xfe,0xaa,0xe1,0x83,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x0d,0xb3,0x66,0xa0,0x92,0xe1,0x04,0xc4,0x8c,0xe9,0x2b,0x5d,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x00,0xdf,0xb9,0xa0,0xb6,0x2e,0x99,0xff,0xfe,0xce,0x13,0x95,0x20,0x8d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x0e,0x6e,0x6b,0xb0,0x02,0xe0,0x4c,0xff,0xfe,0x68,0x02,0x32,0x20,0x8d, 0x02,0x10,0x2a,0x01,0x0e,0x11,0x10,0x0c,0x00,0x70,0x39,0xf3,0xe3,0xc9,0x83,0x2f,0x03,0x7a,0x20,0x8d, - 0x02,0x10,0x2a,0x01,0x0e,0x34,0xec,0x1d,0x71,0x00,0x8a,0xae,0xdd,0xff,0xfe,0x02,0x41,0x59,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0x12,0x10,0x7c,0x92,0x51,0x00,0x02,0x11,0x32,0xff,0xfe,0xae,0x15,0x2d,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0x12,0x10,0x86,0xbf,0xf1,0x00,0xa9,0xac,0xd0,0x41,0x1f,0x8e,0x69,0x25,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x1c,0x04,0xd9,0x00,0x86,0xe5,0x21,0x35,0x4f,0x88,0x08,0x2e,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x20,0x0a,0x3c,0x00,0xb5,0x59,0x6c,0x65,0x10,0xcb,0x37,0x65,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x3c,0x3a,0x56,0x00,0x61,0xe6,0xa8,0x11,0xef,0x0b,0xf9,0xc2,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x48,0x57,0xed,0x00,0x4c,0x86,0x3d,0x1c,0xdb,0x1a,0x46,0x0d,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x4a,0xba,0xe8,0x00,0x21,0xec,0x03,0x46,0xa2,0x9f,0x90,0xbe,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x60,0xe0,0x08,0x00,0x8d,0x6e,0x13,0x4d,0xa0,0xca,0xef,0x24,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x78,0x23,0xde,0x00,0x02,0x11,0x32,0xff,0xfe,0xae,0x15,0x2d,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x12,0x10,0x84,0xea,0xf6,0x00,0x50,0x3e,0x6f,0x19,0xc2,0xc1,0x9c,0xa6,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x13,0xb8,0xf0,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x01,0x68,0x20,0x00,0x00,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x01,0x68,0x42,0x0b,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x01,0x68,0x42,0x0b,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x01,0x68,0x62,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x1c,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x01,0x68,0x67,0x5e,0x00,0x00,0xe6,0x5f,0x01,0xff,0xfe,0x09,0x35,0x91,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x01,0x68,0xb5,0xcf,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x17,0x48,0xf7,0xdf,0x95,0xb1,0x96,0xc6,0x91,0xff,0xfe,0x1d,0xe0,0xb6,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x21,0xb4,0x20,0x89,0x91,0x00,0x10,0x6b,0x0c,0x6b,0xc3,0x28,0xbe,0x4e,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x21,0xb4,0xc8,0x20,0xc3,0x00,0x31,0x26,0xc9,0x60,0xf3,0x56,0xaa,0xb5,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x22,0xa0,0xbb,0xb3,0xdc,0x10,0x50,0xe1,0x57,0xff,0xfe,0x70,0x94,0x92,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0x24,0x7a,0x02,0x15,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0x2c,0x60,0xf1,0x03,0x07,0xc0,0x1a,0x31,0xbf,0xff,0xfe,0xcc,0x5d,0x91,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x24,0x7a,0x02,0x15,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x24,0x7a,0x02,0x2d,0xc0,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x24,0x7a,0x02,0x43,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x27,0x80,0x90,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x27,0x80,0x90,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x29,0xb8,0xdc,0x01,0x37,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x4d,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x2f,0x05,0x63,0x07,0x01,0x00,0x00,0xfd,0xac,0x4b,0x7f,0x1a,0x1d,0x95,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x31,0x02,0x4d,0x5c,0xf0,0x00,0xde,0xa6,0x32,0xff,0xfe,0xbb,0xb9,0xcb,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0x31,0x02,0xbc,0x00,0x10,0xe9,0x0c,0xa5,0x9d,0xff,0xfe,0xa9,0x1c,0xbb,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x31,0x02,0xc3,0x24,0x10,0x49,0x0c,0xa5,0x9d,0xff,0xfe,0xa9,0x1c,0xbb,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x03,0x90,0x90,0x00,0x00,0x00,0xaa,0xa1,0x59,0xff,0xfe,0x43,0xb5,0x7b,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x6d,0x40,0x30,0x55,0xb2,0x01,0xde,0xa6,0x32,0xff,0xfe,0x44,0x4b,0x25,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x6e,0xa0,0xd1,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0xa9,0x21,0xe2,0x57,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x07,0x68,0xf9,0x2b,0xdb,0x46,0x5e,0x46,0x77,0x2b,0x07,0x1d,0x29,0xb7,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7a,0x01,0x00,0x00,0x00,0x00,0x00,0x91,0x02,0x28,0x00,0x45,0x01,0x30,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7b,0x40,0x50,0xd1,0xe7,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7b,0x40,0x59,0x28,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7b,0x40,0xb0,0xdf,0x8f,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7b,0x40,0xb9,0x45,0x35,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7b,0x40,0xc3,0xb5,0xf5,0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7b,0x40,0xd4,0x18,0x69,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x7b,0x40,0xd4,0x18,0x6d,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x80,0x70,0xf1,0x81,0xf6,0x00,0x0b,0xcb,0x02,0xd1,0xd7,0x90,0x78,0xff,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0x80,0x71,0x63,0x80,0xc5,0x00,0x72,0x85,0xc2,0xff,0xfe,0xb5,0xa3,0x9c,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0x80,0x84,0x20,0x21,0x73,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0xe6,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x80,0x71,0x63,0x80,0xc5,0x00,0xd2,0x50,0x99,0xff,0xfe,0x14,0xaf,0xb2,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x80,0x84,0x20,0x21,0x73,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0xe6,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x81,0x08,0x28,0xc0,0x5d,0x60,0xda,0x3a,0xdd,0xff,0xfe,0x45,0x4c,0xb5,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x81,0x08,0x8a,0xc0,0x05,0xdb,0xd2,0x50,0x99,0xff,0xfe,0x9e,0x79,0x2a,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x81,0x0b,0x18,0x1f,0xfa,0x8e,0x1c,0xc7,0xc5,0x28,0x4a,0x59,0x63,0x34,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x83,0x08,0x81,0x88,0x51,0x00,0x6d,0x8b,0x45,0x31,0x43,0x31,0xee,0xe2,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x83,0x88,0xe3,0x02,0x79,0x80,0x6f,0x85,0xa0,0xb3,0x4b,0x4d,0x8b,0x0f,0x20,0x8d, 0x02,0x10,0x2a,0x02,0x83,0x88,0xe5,0xc3,0x4a,0x80,0x02,0x01,0x2e,0xff,0xfe,0x82,0xb3,0xcc,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xa3,0x1a,0xe0,0x3d,0x94,0x00,0x3f,0x18,0x27,0x29,0x0c,0x86,0xd7,0x54,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x09,0x08,0xc2,0x00,0x6d,0x00,0xca,0xad,0x5e,0x32,0x35,0xe7,0x31,0x57,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xa4,0x57,0x1a,0x1b,0xff,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x33,0x20,0x8d, 0x02,0x10,0x2a,0x02,0xa4,0x5a,0x94,0xcd,0xf0,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, 0x02,0x10,0x2a,0x02,0xa4,0x65,0x80,0xf4,0x00,0x01,0xf3,0x69,0x4e,0xf5,0xaa,0x12,0x75,0x66,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xa4,0x66,0x4d,0x4f,0x00,0x01,0x84,0x71,0xfe,0x5d,0x0c,0xff,0xd5,0x24,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xa4,0x68,0x61,0xf8,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xa4,0x69,0x2d,0x51,0x00,0x01,0x92,0x1b,0x0e,0xff,0xfe,0x8c,0x79,0x75,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xa4,0x69,0x3e,0xda,0x00,0x01,0x7e,0x83,0x34,0xff,0xfe,0xb6,0x13,0xf3,0x20,0x8d, 0x02,0x10,0x2a,0x02,0xab,0x88,0x02,0x0b,0xce,0x00,0x02,0x23,0x24,0xff,0xfe,0x56,0x62,0x02,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x20,0x16,0x23,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x62,0x56,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x62,0x56,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x62,0x56,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x62,0x58,0x56,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x62,0x73,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x62,0x73,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x62,0x80,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x34,0x73,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x02,0xc2,0x07,0x30,0x06,0x31,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x0a,0xb8,0x02,0x01,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x26,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x0a,0xb8,0x02,0x01,0x04,0x03,0xb8,0x7a,0x46,0xa1,0xae,0xce,0x21,0xed,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x0a,0xf8,0xfa,0xb0,0x08,0x08,0x00,0x85,0x02,0x34,0x01,0x45,0x01,0x32,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x0b,0x48,0x02,0x07,0x00,0x02,0x83,0x33,0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x0b,0x48,0x02,0x07,0x00,0x02,0x83,0x33,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x31,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x61,0x31,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x70,0x37,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x72,0x28,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x79,0x66,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x81,0x64,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x88,0x93,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x30,0x13,0x36,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x43,0x55,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xc2,0x07,0x30,0x02,0x74,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0xcb,0x43,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x78,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x0e,0x5e,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x20,0x8d, + 0x02,0x10,0x2a,0x02,0x0e,0x98,0x00,0x20,0x15,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x28,0x00,0x68,0x74,0x11,0x53,0xff,0xfe,0x4c,0x02,0x1d,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x02,0x01,0xe3,0xc8,0xb7,0xee,0xff,0xfe,0xb0,0xd2,0x6c,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x5d,0x0b,0xd4,0xa8,0xbf,0x78,0xff,0xfe,0x98,0x7e,0xa4,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x5d,0x0e,0xa7,0x94,0x4c,0x6b,0xff,0xfe,0xad,0xb1,0xf1,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x5f,0x0c,0xfc,0x14,0xc3,0x0e,0xff,0xfe,0xb5,0x1c,0x1a,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x63,0x0d,0xc7,0xd4,0x18,0x2d,0xff,0xfe,0xf3,0x94,0xd9,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x09,0x07,0xd9,0xc8,0x8f,0x1d,0xff,0xfe,0x4e,0x04,0x4d,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0x60,0x00,0x08,0x70,0x00,0x00,0x00,0x46,0x00,0x23,0x00,0x87,0x02,0x18,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x01,0x00,0xe0,0x00,0x00,0x00,0x00,0x03,0x68,0xd0,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x01,0x00,0xe0,0x00,0x00,0x00,0x00,0x06,0xaa,0x70,0x01,0x20,0x8d, 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x07,0x20,0x8d, - 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x10,0x20,0x8d, - 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x11,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x0f,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x14,0x20,0x8d, 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x16,0x20,0x8d, - 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x1d,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x1b,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x1c,0x20,0x8d, 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x20,0x20,0x8d, 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x22,0x20,0x8d, 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x23,0x20,0x8d, - 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x9a,0x20,0x8d, - 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x9d,0x20,0x8d, + 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x9c,0x20,0x8d, 0x02,0x10,0x2a,0x03,0x0e,0xc0,0x00,0x00,0x09,0x28,0x00,0x00,0x00,0x00,0x07,0x01,0x07,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x04,0xee,0x41,0x00,0x86,0x50,0xb6,0xfa,0x75,0xa4,0xff,0xfe,0x3c,0x24,0x3f,0x20,0x8d, - 0x02,0x10,0x2a,0x05,0xd0,0x12,0x04,0x2a,0x57,0x03,0x4d,0xc5,0x81,0x16,0x78,0x7c,0xe0,0x16,0x20,0x8d, - 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x01,0xf6,0xab,0xdd,0x5e,0x40,0x39,0xb4,0x6c,0x20,0x8d, - 0x02,0x10,0x2a,0x05,0xd0,0x18,0x0a,0x75,0x6c,0x00,0xc0,0x5b,0x4d,0x0a,0x36,0x58,0x10,0x30,0x20,0x8d, - 0x02,0x10,0x2a,0x07,0x9a,0x07,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x07,0xd8,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x0e,0x20,0x8d, - 0x02,0x10,0x2a,0x0a,0xef,0x40,0x0e,0x44,0x9b,0x01,0x27,0x46,0xca,0x1e,0x67,0x88,0x35,0x1c,0x20,0x8d, + 0x02,0x10,0x2a,0x04,0x35,0x43,0x10,0x00,0x23,0x10,0xe8,0x78,0x79,0xff,0xfe,0x3c,0x17,0x29,0x20,0x8d, + 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x02,0x22,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x02,0x49,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x03,0xc4,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x04,0x16,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x05,0x35,0x80,0xd1,0x01,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x2a,0x05,0x4c,0xc0,0x00,0x00,0x03,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x05,0x6d,0x40,0xb9,0x4e,0xd1,0x00,0x02,0x30,0x48,0xff,0xfe,0xdf,0x14,0x32,0x20,0x8d, + 0x02,0x10,0x2a,0x05,0xd0,0x1e,0x01,0xb1,0x6c,0x03,0x53,0x69,0xfd,0x23,0xe6,0x2f,0xa2,0x57,0x20,0x8d, + 0x02,0x10,0x2a,0x05,0xf4,0x80,0x2c,0x00,0x10,0x0c,0x54,0x00,0x04,0xff,0xfe,0xd7,0xde,0xad,0x20,0x8d, + 0x02,0x10,0x2a,0x05,0xf4,0x80,0x30,0x00,0x2b,0x4e,0x54,0x00,0x04,0xff,0xfe,0xd7,0x42,0x06,0x20,0x8d, + 0x02,0x10,0x2a,0x06,0xdd,0x00,0x00,0x10,0x00,0x00,0x02,0x25,0x90,0xff,0xfe,0x33,0x56,0xe8,0x20,0x8d, + 0x02,0x10,0x2a,0x06,0xdd,0x01,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x06,0xe8,0x81,0x34,0x08,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x07,0x72,0x00,0xff,0xff,0x00,0x00,0x30,0x16,0xd5,0xff,0xfe,0x5e,0x11,0x14,0x20,0x8d, + 0x02,0x10,0x2a,0x07,0x72,0x00,0xff,0xff,0x00,0x00,0x60,0xd1,0x0e,0xff,0xfe,0x09,0x38,0x86,0x20,0x8d, + 0x02,0x10,0x2a,0x07,0x72,0x00,0xff,0xff,0x00,0x00,0xb0,0xa5,0x23,0xff,0xfe,0x34,0xd2,0x92,0x20,0x8d, + 0x02,0x10,0x2a,0x07,0x72,0x00,0xff,0xff,0x00,0x00,0xc4,0x3e,0x80,0xff,0xfe,0x3c,0xe0,0xcd,0x20,0x8d, + 0x02,0x10,0x2a,0x07,0x72,0x00,0xff,0xff,0x00,0x00,0xf4,0xd3,0x0a,0xff,0xfe,0xbe,0xad,0x99,0x20,0x8d, + 0x02,0x10,0x2a,0x07,0xb2,0x42,0x10,0x00,0x13,0x00,0xf2,0x50,0x8f,0x0a,0xcd,0xba,0x4d,0x76,0x20,0x8d, + 0x02,0x10,0x2a,0x07,0xd8,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x7e,0x20,0x8d, + 0x02,0x10,0x2a,0x09,0x26,0x81,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x20,0x8d, + 0x02,0x10,0x2a,0x0a,0x31,0xc0,0x01,0x00,0x00,0x00,0x88,0x8f,0x90,0xff,0xfe,0x2c,0x76,0x1b,0x20,0x8d, + 0x02,0x10,0x2a,0x0a,0x45,0x80,0x10,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x0a,0x4c,0xc0,0x01,0x00,0x03,0x7b,0xc4,0x4a,0x2f,0xff,0xfe,0x10,0x2d,0x3c,0x20,0x8d, + 0x02,0x10,0x2a,0x0a,0x4c,0xc0,0x00,0x01,0x03,0x40,0x14,0x60,0xfd,0xff,0xfe,0xb2,0x29,0x94,0x20,0x8d, + 0x02,0x10,0x2a,0x0b,0x48,0x80,0x00,0x00,0x00,0x00,0x26,0x6e,0x96,0xff,0xfe,0xdb,0x7c,0xdc,0x20,0x8d, + 0x02,0x10,0x2a,0x0b,0xf3,0x00,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, 0x02,0x10,0x2a,0x0b,0xf4,0xc0,0x00,0xc1,0x92,0x0e,0xb2,0x5a,0xda,0xff,0xfe,0x87,0x77,0xb4,0x20,0x8d, + 0x02,0x10,0x2a,0x0c,0xb6,0x41,0x06,0xf0,0x01,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d, + 0x02,0x10,0x2a,0x0e,0x8f,0x02,0x21,0xd1,0x01,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x0e,0xcb,0x00,0x70,0x0b,0x00,0x00,0xcb,0x0f,0x0c,0xba,0x41,0xb2,0x28,0xb3,0x20,0x8d, + 0x02,0x10,0x2a,0x0e,0xe7,0x01,0x10,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x8d, + 0x02,0x10,0x2a,0x0f,0xb7,0x80,0x03,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d, + 0x02,0x10,0x2a,0x0f,0xdf,0x00,0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x62,0x20,0x8d, + 0x02,0x10,0x2a,0x0f,0xe5,0x86,0x00,0x0f,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x20,0x8d, + 0x02,0x10,0x2a,0x10,0x37,0x81,0x2c,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x10,0x37,0x81,0x3a,0x73,0x00,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x20,0x8d, + 0x02,0x10,0x2a,0x10,0x37,0x81,0x3a,0x73,0x00,0x25,0xa1,0x77,0xad,0x25,0xb1,0x4a,0x17,0x6a,0x20,0x8d, + 0x02,0x10,0x2a,0x10,0x37,0x81,0x3f,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x10,0x37,0x81,0x08,0x4b,0x00,0x01,0x80,0x02,0x99,0xd3,0x19,0x1f,0xc7,0x38,0x20,0x8d, 0x02,0x10,0x2a,0x10,0xc9,0x41,0x01,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xf0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x02,0x10,0x2a,0x12,0xa3,0x02,0x00,0x01,0xa1,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0xb5,0xca,0x20,0x8d, - 0x02,0x10,0x2c,0x0f,0xf4,0xa8,0x00,0x0b,0xb1,0x08,0x80,0x7d,0xb2,0xd6,0x91,0x46,0x38,0xbe,0x20,0x8d, - 0x02,0x10,0x2c,0x0f,0xf4,0xa8,0x00,0x0b,0xb1,0x08,0xc4,0x58,0x5c,0x61,0xdc,0xca,0xcb,0x10,0x20,0x8d, - 0x05,0x20,0x46,0x3e,0x67,0x73,0x9d,0xe3,0xc3,0xc7,0xeb,0x2c,0x6a,0xad,0x13,0x49,0x1e,0xaf,0x9d,0x0a,0xf7,0x79,0xbb,0x58,0x05,0xe7,0xd1,0x69,0x52,0x46,0x5c,0xb3,0x03,0xca,0x00,0x00, - 0x05,0x20,0x4e,0xb5,0xd6,0xc5,0x8d,0x1d,0xaa,0x84,0x1d,0xe4,0xfa,0x03,0xe6,0x33,0xa7,0xfe,0xb6,0x23,0x7b,0x56,0x88,0x7f,0x56,0xd9,0xc5,0x73,0xeb,0xcf,0xea,0x84,0xde,0x6c,0x00,0x00, - 0x05,0x20,0x4e,0x99,0xdd,0x79,0x70,0x95,0x13,0x59,0xf8,0x3e,0xba,0xf8,0x87,0xe4,0x29,0x55,0x55,0x42,0x0a,0x38,0x26,0xea,0xa3,0x1a,0xce,0xf2,0x40,0x3a,0xe6,0x14,0xf9,0x7f,0x00,0x00, - 0x05,0x20,0x4e,0x9f,0x82,0x37,0x07,0x73,0xdf,0x24,0x92,0xe4,0x6e,0x5b,0x7a,0x9a,0x11,0x14,0xb8,0x1a,0x57,0x8d,0x94,0x85,0x37,0x58,0xcf,0x37,0x85,0x91,0xb9,0xdb,0x6e,0x11,0x00,0x00, - 0x05,0x20,0x4e,0xe9,0x2b,0xba,0xb7,0xfd,0x14,0xbf,0x73,0xb4,0xff,0xd3,0x41,0xe9,0x8f,0x64,0x55,0xf8,0xe0,0xfd,0xc0,0x2e,0xd7,0x7a,0x22,0x25,0x3f,0xf3,0xc1,0x77,0x55,0x26,0x00,0x00, - 0x05,0x20,0x4f,0x34,0x39,0x35,0x2b,0x37,0x2b,0x5d,0xee,0x72,0x39,0xa5,0xd4,0xe0,0xe0,0x67,0x9e,0xb2,0xee,0x54,0x4e,0xa4,0xdd,0x2b,0xc4,0xb7,0x26,0xc1,0x67,0x65,0x78,0x21,0x00,0x00, - 0x05,0x20,0x4f,0x26,0x98,0x96,0xed,0xb0,0x98,0x13,0xa9,0x17,0x64,0x16,0xd7,0x4c,0xc8,0x69,0xcb,0x73,0x14,0x75,0x48,0x0f,0x1f,0x61,0xbf,0x4f,0xe2,0xa0,0x8e,0x0d,0x31,0xf8,0x00,0x00, - 0x05,0x20,0x48,0x76,0x8a,0x23,0xe6,0x8b,0x56,0x91,0xa5,0x92,0xcf,0xe0,0x1a,0x4a,0x71,0x5f,0x6a,0xdd,0xa1,0xfb,0xa3,0xda,0xac,0x84,0x04,0x30,0x10,0xa5,0xc5,0x02,0xf8,0x8e,0x00,0x00, - 0x05,0x20,0x48,0x59,0x09,0x98,0xe7,0x07,0xcf,0x21,0x58,0x36,0x7a,0x3e,0xf9,0x68,0x6d,0x31,0xe1,0xa0,0xd6,0xe9,0x69,0x48,0x1e,0x99,0x6d,0x33,0x6a,0x64,0xb0,0x80,0x12,0x81,0x00,0x00, - 0x05,0x20,0x48,0xf9,0xb7,0x8b,0x4b,0xfe,0xc8,0xaf,0x1d,0x5a,0x9b,0xfc,0x74,0x60,0x03,0x07,0xc8,0x3f,0xd6,0x47,0x83,0xb4,0x5a,0xdc,0x26,0x06,0x86,0x0c,0x2c,0x46,0x39,0x71,0x00,0x00, - 0x05,0x20,0x48,0xfd,0xbb,0x1c,0x81,0x1f,0x71,0x45,0xcb,0xf1,0xdf,0x18,0x8d,0xad,0xad,0xa5,0x0f,0x0b,0xde,0x3c,0x5b,0x65,0xef,0xea,0x79,0x5a,0x23,0x4e,0x55,0x5f,0x3d,0xa3,0x00,0x00, - 0x05,0x20,0x49,0x3c,0x9a,0x79,0x07,0xc0,0x6e,0xce,0xd9,0x56,0xe8,0xc0,0x48,0x24,0x93,0xff,0x17,0x21,0x55,0x1c,0x5c,0xbb,0x66,0xf6,0xc5,0xfa,0x90,0x01,0x64,0xa6,0x30,0x0b,0x00,0x00, - 0x05,0x20,0x49,0x10,0x39,0x4d,0x76,0x1a,0xe7,0xed,0xad,0x34,0xf8,0x9a,0x9d,0x30,0xfc,0x2b,0x8b,0x89,0x25,0xa2,0xd5,0x85,0x54,0x2d,0xe7,0xc3,0x5f,0x11,0xfd,0x36,0xf7,0x18,0x00,0x00, - 0x05,0x20,0x49,0x1d,0x7e,0xb6,0x34,0xa3,0x9c,0xf2,0x0e,0x45,0x7d,0x1c,0x8f,0x2a,0xc4,0xb3,0x0e,0x10,0xc9,0xa7,0x2f,0xd4,0x80,0xea,0x1e,0x70,0x0b,0x51,0x1e,0xf5,0x63,0x5b,0x00,0x00, - 0x05,0x20,0x49,0x2f,0xbc,0x2a,0xda,0x6b,0x2d,0xf7,0x58,0xe6,0x0c,0xd0,0xee,0x95,0x75,0xfd,0x25,0xed,0x70,0x37,0xb3,0xf9,0xe6,0xc7,0xf1,0x3b,0x26,0x4a,0x26,0x2c,0x9d,0x6b,0x00,0x00, - 0x05,0x20,0x49,0x46,0x7f,0x75,0x1c,0x69,0xde,0x6e,0x38,0x2d,0x71,0x38,0x08,0x23,0x75,0xcd,0x42,0x8f,0x17,0x19,0x4a,0x74,0x42,0x7e,0x5b,0x83,0x34,0x60,0x89,0xab,0x5a,0xab,0x00,0x00, - 0x05,0x20,0x49,0xf5,0x0b,0xa9,0x30,0x69,0x93,0xa6,0x76,0x6d,0xd1,0x04,0x04,0x0c,0xb0,0x00,0xb8,0x0b,0x19,0xac,0x51,0xa4,0x04,0xb6,0x6e,0x84,0xbb,0x08,0x61,0x33,0x7f,0x71,0x00,0x00, - 0x05,0x20,0x49,0xfe,0x4a,0xf0,0x1d,0xc9,0x72,0xc2,0x60,0x8a,0x43,0x4f,0x30,0xc0,0xa8,0xf0,0xbf,0x73,0xd4,0x5c,0x64,0x86,0xfc,0x23,0xdf,0x4e,0xe5,0x75,0xfa,0x3c,0xe5,0x15,0x00,0x00, - 0x05,0x20,0x4a,0x02,0x0b,0x7f,0x0d,0x0b,0x6f,0x42,0x42,0x58,0xfa,0xbe,0x9c,0x55,0xc9,0xf2,0xc7,0x90,0xd0,0x4a,0x7b,0xcb,0x7e,0xd9,0xd9,0x9f,0xd8,0x59,0xa0,0xf8,0xed,0x45,0x00,0x00, - 0x05,0x20,0x4a,0x04,0x2e,0xaa,0xd8,0xe4,0xeb,0xc4,0xe9,0xad,0xf1,0x8a,0x14,0x4b,0xe4,0xf0,0xef,0x8d,0x28,0x75,0x24,0xf7,0x97,0xdc,0x61,0xc3,0xff,0xc3,0xf4,0xcf,0x6d,0xe9,0x00,0x00, - 0x05,0x20,0x4a,0x18,0x3c,0x0c,0x59,0x9f,0x89,0xa5,0x88,0x84,0xcb,0x9e,0xd5,0xf0,0xa6,0xcf,0xe1,0xa4,0x92,0x10,0x3a,0xe0,0x0b,0xc4,0xc4,0x6e,0xf6,0xea,0x5d,0x5d,0xfd,0xd1,0x00,0x00, - 0x05,0x20,0x4a,0x40,0xd3,0x2f,0xc7,0xe3,0xf1,0xa7,0x8f,0x46,0xb0,0x18,0x78,0x2e,0x58,0x66,0x28,0xe1,0x31,0xe8,0x73,0x48,0x86,0xe4,0xbd,0x08,0x7b,0x0a,0xd4,0x69,0xce,0x60,0x00,0x00, - 0x05,0x20,0x4a,0xbb,0xec,0xec,0xa4,0x0b,0xc4,0xef,0x44,0x2a,0x7e,0x73,0x5d,0xa6,0x59,0x2f,0x1f,0x7e,0xd3,0x33,0x63,0xaf,0x95,0x3e,0x52,0xfb,0x2e,0xdc,0xc1,0x6f,0x90,0xd6,0x00,0x00, - 0x05,0x20,0x4a,0x8b,0x40,0x25,0xdc,0x06,0x2a,0xed,0x44,0x35,0xec,0x06,0x9e,0x73,0x70,0xf0,0x07,0x06,0x35,0xd1,0x60,0x4f,0x22,0xe8,0xbf,0x8a,0xdf,0xd9,0xeb,0x97,0x73,0x06,0x00,0x00, - 0x05,0x20,0x4a,0xaa,0x4c,0x6a,0xa5,0x1c,0xdd,0xaa,0x0a,0x83,0x47,0x12,0xb3,0x48,0x2f,0x62,0xd7,0x2d,0xd2,0xcc,0x5a,0x92,0xe6,0x94,0xea,0xee,0x18,0x86,0xaa,0xd9,0xb2,0x35,0x00,0x00, - 0x05,0x20,0x4a,0xf9,0x58,0xf5,0x40,0x17,0xda,0x9c,0x2e,0x68,0xab,0x7f,0x49,0xf4,0x05,0xc4,0x3a,0x87,0xe4,0x5d,0xb3,0xae,0xbe,0x77,0x5b,0x23,0x1c,0x3b,0xa2,0xe2,0x46,0xf3,0x00,0x00, - 0x05,0x20,0x4b,0x08,0x12,0xae,0x87,0x8a,0xfc,0x01,0xf5,0xf3,0xe2,0x1e,0x4a,0x97,0x66,0xd8,0x39,0x38,0x8a,0x9f,0x05,0xc0,0xb7,0xd0,0x2f,0x52,0x23,0xec,0xae,0xce,0xab,0x3b,0x00,0x00, - 0x05,0x20,0x4b,0x47,0x1e,0xa3,0x90,0x3d,0xe5,0xe0,0x03,0x41,0x85,0x68,0x58,0x9a,0x73,0x87,0x88,0xd0,0x57,0x06,0x3a,0x3b,0xc1,0xc0,0xb4,0x55,0x35,0x06,0xca,0x63,0x80,0x3a,0x00,0x00, - 0x05,0x20,0x4b,0x9e,0x8b,0x6a,0x74,0x7f,0x4f,0xdb,0x9f,0x47,0xb1,0x0b,0xc7,0x15,0x66,0x92,0x81,0x60,0xbc,0xac,0x95,0xa8,0x1d,0x21,0xd2,0x64,0x1c,0x22,0x25,0x09,0x1f,0x0a,0x00,0x00, - 0x05,0x20,0x4c,0x49,0x19,0xed,0xda,0x89,0xc2,0xa7,0xc2,0x98,0x0d,0x8d,0xf9,0xc3,0x81,0x1d,0x57,0x72,0x1f,0xcb,0x6a,0xc5,0x1e,0x8c,0x64,0xba,0xa8,0x6a,0x55,0x1a,0x5e,0x9f,0x00,0x00, - 0x05,0x20,0x4c,0x5c,0x1a,0x10,0x46,0x65,0x29,0x06,0x3c,0x72,0x0d,0xec,0x18,0x11,0x63,0x9e,0xbf,0xbe,0x88,0xc2,0x23,0x1a,0x67,0x02,0x4d,0x08,0x54,0x3c,0xea,0x85,0x1a,0xd9,0x00,0x00, - 0x05,0x20,0x4c,0x6a,0x6d,0x6a,0xf5,0x0b,0x13,0x88,0xaa,0x06,0xfb,0x23,0xed,0x6b,0x27,0x68,0xc1,0xb4,0x26,0x74,0x07,0xba,0x28,0x34,0xd6,0x8d,0x48,0xdf,0xc8,0xbd,0xc8,0xff,0x00,0x00, - 0x05,0x20,0x4c,0x8d,0xc1,0xca,0xf5,0x32,0x45,0x0c,0xec,0x5a,0x81,0xa7,0x64,0x71,0x0f,0xda,0xf8,0xde,0x1d,0x77,0x70,0xc3,0x53,0x51,0x56,0x02,0x1f,0x81,0x59,0xda,0xf6,0x68,0x00,0x00, - 0x05,0x20,0x4c,0xf7,0xda,0x58,0x2b,0xed,0xaf,0xf7,0xb9,0xb8,0xbb,0x98,0xa9,0x45,0x29,0x97,0xf3,0x8e,0xe3,0x0c,0xac,0xe8,0x3d,0xb5,0x8e,0x34,0xfe,0x24,0x7e,0xf7,0x5b,0x35,0x00,0x00, - 0x05,0x20,0x4d,0x40,0xe3,0xef,0x62,0x78,0xb2,0xff,0x6b,0xcb,0x1d,0xa3,0xc0,0x64,0xfc,0x38,0x7a,0x24,0xb2,0xeb,0x0e,0x76,0x38,0x6c,0x57,0x44,0x86,0xbc,0xb7,0xf9,0xd7,0x49,0x00,0x00, - 0x05,0x20,0x4d,0x56,0x9f,0xc3,0x17,0x13,0x1c,0xb2,0xff,0xd6,0x69,0x31,0x56,0x0e,0xf1,0x7a,0x09,0x99,0x5d,0x48,0x43,0x00,0xfb,0x5c,0x23,0x0a,0x2d,0xa7,0x9e,0xab,0xc2,0x42,0x00,0x00, - 0x05,0x20,0x4d,0xa0,0xba,0xc1,0x85,0xab,0x86,0xd8,0xc9,0x63,0x26,0x90,0x38,0x4f,0x5d,0x85,0xd1,0x8a,0x9a,0x03,0x5c,0x75,0x0e,0x51,0xc3,0xec,0xbc,0xb5,0x31,0x64,0x63,0xf0,0x00,0x00, - 0x05,0x20,0x4d,0xd2,0x2f,0xb8,0x9a,0xe5,0x6e,0x32,0x3d,0x45,0xaa,0xf7,0xee,0xc0,0xb6,0x8d,0xc4,0x01,0xe8,0xbb,0x4f,0x36,0x56,0x96,0x82,0x3c,0xeb,0x08,0x2a,0x03,0xd4,0x73,0x00,0x00, - 0x05,0x20,0x57,0x18,0x23,0xf7,0x6c,0xfe,0xb3,0x5f,0xa4,0x63,0x06,0xde,0xe0,0x6b,0x2d,0xf8,0x51,0xb4,0x80,0x50,0xb1,0x43,0xce,0xbc,0x84,0x02,0xee,0x13,0xe2,0x43,0x76,0x45,0x00,0x00, - 0x05,0x20,0x57,0x1e,0x99,0xf9,0x9a,0xe8,0xc5,0x76,0xbb,0x74,0x19,0x15,0xe8,0x82,0x4e,0x76,0x7b,0x99,0xc1,0xb8,0xb0,0x36,0x5d,0x3a,0xcf,0xa8,0x93,0x9a,0xa2,0x46,0xfb,0x4c,0x00,0x00, - 0x05,0x20,0x57,0x41,0x19,0x7c,0xf2,0x89,0x68,0x10,0x0e,0x2e,0x27,0x4f,0xf7,0x61,0xe9,0x6c,0x2c,0x8f,0x57,0x55,0xbd,0xf1,0xe8,0xb1,0xb2,0xfe,0x68,0x12,0xfb,0xc0,0x45,0x43,0x00,0x00, - 0x05,0x20,0x57,0x88,0x49,0x1e,0x4a,0xe5,0x4b,0xbe,0x07,0xa6,0x2b,0x62,0x0c,0xf1,0xfd,0x80,0x7d,0x21,0x57,0x8a,0xb7,0x88,0x85,0xcc,0x81,0x22,0xfa,0x4b,0xdb,0xca,0x23,0xdf,0x00,0x00, - 0x05,0x20,0x57,0x8d,0x3f,0x72,0xe1,0xc7,0x50,0x66,0x2d,0xbd,0x39,0x45,0x4c,0xc9,0xf3,0xd4,0xda,0x34,0x33,0x31,0x1d,0x53,0xee,0xe1,0xdf,0xf1,0xf5,0xa3,0x77,0x07,0x5d,0x52,0x00,0x00, - 0x05,0x20,0x57,0xd4,0x26,0xc6,0x04,0xde,0x03,0x0a,0x6a,0xdb,0x28,0x16,0x8f,0xe4,0x97,0x9f,0x9a,0x0f,0xbb,0xae,0xf7,0x63,0x7f,0x17,0xae,0x86,0x41,0xa5,0xb9,0xb2,0x8e,0x3c,0x00,0x00, - 0x05,0x20,0x50,0x41,0x61,0x20,0x98,0x22,0xed,0x64,0x4e,0x29,0x75,0xbb,0xbf,0xe5,0xec,0x1a,0x9a,0x2b,0x22,0x1c,0xd4,0x4e,0x93,0x03,0x16,0xeb,0xbf,0x4e,0xfb,0x4c,0x56,0xb6,0x00,0x00, - 0x05,0x20,0x50,0xa0,0xa7,0x4c,0xef,0x59,0x18,0x05,0x21,0xe5,0x79,0x00,0x9b,0xb2,0x9c,0xbc,0xa5,0x97,0x82,0xef,0x7c,0x4d,0x3a,0x57,0xb3,0x31,0x46,0x08,0x11,0x26,0xd4,0xa1,0x00,0x00, - 0x05,0x20,0x50,0xe2,0x20,0xc7,0xd6,0x36,0x82,0x9f,0x39,0x0f,0x90,0x49,0x0c,0x78,0x2f,0xdd,0x7e,0x38,0x3e,0x67,0xf0,0x8e,0x4a,0xa3,0x12,0x65,0x5d,0xc0,0x8e,0x60,0xf9,0x46,0x00,0x00, - 0x05,0x20,0x51,0x0e,0xe9,0x30,0xca,0xff,0x8b,0x76,0xa7,0x16,0x82,0x53,0xe6,0xc2,0x5c,0x71,0xcd,0xc3,0xca,0x93,0x5a,0x47,0x94,0xbb,0x92,0x95,0x8f,0x75,0xa7,0xab,0xec,0xc4,0x00,0x00, - 0x05,0x20,0x51,0xef,0x1a,0x38,0x0e,0x67,0xd3,0x47,0x09,0x4a,0x76,0xa6,0x1b,0xc1,0xdb,0x0b,0x62,0x96,0x3a,0x09,0x38,0xdc,0x01,0xe3,0x78,0xc4,0x79,0x00,0x0b,0x3c,0x93,0x99,0x00,0x00, - 0x05,0x20,0x52,0x40,0x0d,0xe5,0x6f,0xe4,0x90,0xf2,0xdd,0x0a,0x51,0x26,0x6a,0xae,0xfc,0x75,0xe1,0xd7,0x2b,0xbf,0x41,0x6e,0x46,0x85,0x04,0xb3,0x25,0x12,0x5b,0xcb,0x15,0xbf,0x00,0x00, - 0x05,0x20,0x52,0x6b,0x1c,0x98,0x4a,0x04,0x83,0xdf,0xe2,0x07,0x5d,0x2a,0x90,0xae,0xfa,0x69,0xaf,0x29,0xd1,0x85,0x37,0xa9,0x42,0xe7,0xac,0x17,0xf3,0x82,0x4d,0x49,0x5c,0x7e,0x00,0x00, - 0x05,0x20,0x52,0x90,0x79,0x1f,0x45,0x05,0xb4,0x6b,0xa1,0x7e,0x44,0xf8,0x65,0xb9,0x7c,0xa6,0xfe,0x21,0x46,0x94,0xcc,0xa9,0x2c,0x21,0x50,0xa6,0x58,0xa2,0x95,0x3b,0xb3,0x7d,0x00,0x00, - 0x05,0x20,0x53,0x36,0x1e,0xa7,0xc2,0x84,0x45,0x02,0x58,0x6f,0xa5,0x48,0x80,0xbe,0x76,0xe9,0x8d,0x4b,0x2a,0x76,0x03,0x77,0xe4,0xad,0xd6,0xe5,0xf0,0xa7,0x9b,0x43,0x34,0x7c,0x00,0x00, - 0x05,0x20,0x53,0xde,0x27,0x47,0xbc,0x52,0x8c,0x4f,0x08,0xd0,0xe7,0xdb,0x92,0x55,0x65,0x89,0xc3,0x74,0x34,0xc2,0x49,0x58,0xad,0x11,0x8a,0x88,0xc0,0x44,0xbd,0x17,0x54,0x07,0x00,0x00, - 0x05,0x20,0x54,0x94,0x81,0xae,0x6c,0x0a,0x0c,0xfd,0x12,0x6f,0xe3,0xc6,0xbf,0x7d,0x44,0xd4,0x32,0x94,0xdb,0xde,0xb4,0x00,0x88,0xe6,0x3c,0xb3,0x74,0x07,0xc3,0x8e,0xf8,0x54,0x00,0x00, - 0x05,0x20,0x54,0xaf,0x74,0x35,0x24,0xdf,0x7f,0x91,0x4d,0x4e,0x0d,0x9b,0x79,0x63,0x9c,0x18,0xd1,0x58,0x7f,0x0f,0xd3,0x76,0xde,0x99,0xcf,0x57,0x1c,0xa4,0x47,0x55,0x31,0xc0,0x00,0x00, - 0x05,0x20,0x54,0xe8,0x0d,0xa7,0x9b,0x42,0x6e,0x73,0x9c,0xa4,0x5a,0x64,0xfd,0xe9,0x43,0x45,0x10,0x2e,0xb5,0x6d,0x2b,0x55,0x7d,0x90,0x0b,0xc7,0xdc,0x9a,0x83,0x95,0xb2,0x9d,0x00,0x00, - 0x05,0x20,0x55,0x33,0x4f,0xec,0xd9,0xaa,0xda,0xe3,0x70,0x43,0x98,0xd5,0xf2,0x0c,0x34,0x95,0xe3,0xc7,0xa0,0xca,0x6d,0x6c,0x6d,0x05,0x2e,0xf2,0xf9,0xea,0x1a,0x46,0x64,0x67,0x00,0x00, - 0x05,0x20,0x55,0xb7,0x5f,0x1a,0x1d,0x91,0x18,0x69,0xf0,0xc6,0xf2,0x27,0x46,0x6e,0x13,0x06,0x16,0x06,0xe1,0xc5,0xfd,0x9b,0xe0,0xb4,0x2d,0x30,0xc8,0x1c,0x72,0xe8,0xbd,0x1c,0x00,0x00, - 0x05,0x20,0x5e,0xfd,0xc6,0xd0,0x76,0x72,0x7d,0xb2,0x93,0xad,0x92,0x58,0xd4,0x22,0x8d,0xf6,0xc9,0xbc,0x08,0x70,0x8a,0x70,0xa6,0x84,0xa8,0xbd,0xe7,0x12,0x76,0x4f,0xbf,0xcc,0x00,0x00, - 0x05,0x20,0x5e,0xc0,0x23,0xf6,0xc1,0x1d,0xf6,0xde,0xb6,0x1d,0xdc,0xab,0xe9,0x80,0xc8,0x4c,0x43,0x22,0x6d,0xb6,0x06,0x8c,0xa8,0x67,0xae,0x4f,0xc0,0x82,0xe0,0x08,0xcb,0xc5,0x00,0x00, - 0x05,0x20,0x5f,0x4a,0x89,0x83,0x91,0xfb,0x50,0x88,0xec,0xf7,0x65,0x3e,0xcc,0x8a,0xd1,0x41,0xae,0x86,0xaa,0x2d,0xe3,0xa0,0x42,0x30,0x23,0x51,0x80,0xef,0xab,0x58,0xcc,0xce,0x00,0x00, - 0x05,0x20,0x5f,0x5c,0x15,0x2b,0xf9,0xcb,0x9f,0xb6,0xe6,0x6d,0x9f,0x90,0x9a,0x1b,0x3c,0x72,0xa1,0x2c,0x1c,0xe1,0xeb,0xbc,0x65,0x06,0x0e,0x9c,0xcd,0x0c,0xe7,0x22,0x35,0x56,0x00,0x00, - 0x05,0x20,0x58,0x11,0xbe,0xef,0x99,0xf6,0x65,0xa9,0xd1,0x59,0x45,0xc6,0x03,0x44,0x48,0x26,0x68,0xcd,0x05,0x58,0xa0,0x24,0xad,0x4a,0x37,0x4c,0x5b,0xef,0xe2,0x9c,0x17,0x7e,0x00,0x00, - 0x05,0x20,0x58,0x50,0x5d,0xb0,0xc6,0xd0,0x74,0x88,0xf4,0x6a,0xcf,0xe9,0xe4,0x02,0x63,0x8d,0x11,0xa3,0xe8,0x1e,0xe5,0x56,0xc2,0x94,0x45,0x34,0x1a,0xf4,0xd2,0xb6,0xc8,0x2e,0x00,0x00, - 0x05,0x20,0x59,0x29,0xbf,0x85,0xf3,0xa5,0x29,0xdd,0xff,0xec,0x47,0xc4,0x1e,0xcf,0x55,0x95,0x38,0x72,0x48,0x2b,0xc5,0xd7,0xdc,0xbe,0x6d,0x6a,0xb9,0x57,0x0c,0xee,0xad,0x88,0x00,0x00, - 0x05,0x20,0x59,0x69,0x5c,0xe7,0x22,0x25,0x10,0xae,0xd3,0xaf,0x68,0xf4,0x8f,0x7c,0x0c,0x21,0x88,0xbe,0xd0,0x1a,0x8c,0x5a,0xd1,0x5d,0x58,0xc0,0xbe,0x13,0xcc,0x90,0xfe,0xc0,0x00,0x00, - 0x05,0x20,0x59,0x9e,0xe4,0xbd,0xc8,0xbf,0xf2,0x3f,0x0c,0xef,0x77,0x4e,0x38,0xb6,0xcc,0xe5,0x09,0x84,0xd5,0x1f,0x98,0x5d,0x3e,0x42,0x50,0xc0,0x55,0xba,0x3e,0x8e,0x13,0x5e,0x00,0x00, - 0x05,0x20,0x59,0xff,0x04,0xb9,0x81,0x13,0x10,0x45,0x56,0xbe,0x6a,0x33,0xd2,0x15,0x71,0xef,0x44,0xd1,0xed,0xd7,0xbf,0xdb,0x4a,0x4b,0xd5,0x61,0x0f,0x02,0xb8,0x71,0xf7,0xf2,0x00,0x00, - 0x05,0x20,0x59,0xe8,0xfa,0x6d,0xd6,0x3d,0x05,0xf8,0x5a,0xb8,0x28,0x32,0x65,0x04,0x4c,0x8f,0xe4,0x97,0xf6,0x10,0xbb,0xe5,0xfd,0xea,0xb8,0xee,0xab,0xef,0x96,0x4d,0xe9,0xa9,0x00,0x00, - 0x05,0x20,0x5a,0x39,0x5a,0x3a,0xa0,0x2d,0xd3,0x12,0xf7,0x8a,0xa9,0x4d,0xb6,0x26,0x26,0xd3,0x08,0x19,0x78,0x83,0x7a,0xfb,0x88,0xc7,0x43,0x71,0xc6,0x3a,0x99,0x97,0x4e,0x2b,0x00,0x00, - 0x05,0x20,0x5a,0x29,0xfe,0x8a,0xaa,0x9d,0x78,0x81,0x04,0x53,0x37,0xf5,0x6f,0xb6,0xe1,0x57,0x08,0x80,0xcf,0xf6,0x03,0x11,0x92,0x8d,0x08,0xe3,0x99,0x9f,0x98,0x4a,0x27,0x6b,0x00,0x00, - 0x05,0x20,0x5b,0x16,0x5d,0xe1,0x38,0x37,0x06,0x98,0x87,0xf6,0x9e,0x59,0x10,0xf0,0xa1,0x53,0xa3,0x00,0x83,0xea,0xe2,0xea,0xaf,0x82,0xfc,0x73,0x01,0x8e,0x30,0x38,0x9d,0x1e,0x00,0x00, - 0x05,0x20,0x5b,0xc0,0xbf,0x7e,0xc7,0x8b,0x90,0xfd,0x8b,0x58,0x4f,0x0b,0x70,0x83,0x09,0xe7,0x87,0xb9,0xc7,0xae,0x96,0x20,0xe3,0x78,0x8b,0xeb,0x7c,0x29,0xaa,0x63,0x68,0x15,0x00,0x00, - 0x05,0x20,0x5b,0xc8,0xa9,0xb9,0xb1,0xd5,0x30,0x87,0x1e,0x99,0x46,0xfb,0x23,0xcd,0x3b,0x70,0x01,0xff,0xc5,0x4b,0x64,0x24,0x8a,0xd3,0x03,0xba,0x85,0x75,0x10,0x1a,0x1d,0xa9,0x00,0x00, - 0x05,0x20,0x5b,0xca,0x5c,0x11,0x32,0x55,0xac,0x07,0xe8,0xce,0xfb,0x98,0xc6,0x47,0x04,0xbe,0x81,0x49,0xad,0x4c,0x13,0x5a,0xf5,0x6a,0x6c,0xf0,0x11,0x3b,0x88,0x0b,0xb4,0x4e,0x00,0x00, - 0x05,0x20,0x5b,0xe0,0xa3,0x04,0x8a,0xd8,0x91,0xbb,0x72,0x0e,0x0b,0xc9,0x02,0x3d,0x2e,0x8e,0xc3,0x45,0x67,0xbd,0xec,0x72,0xb6,0x18,0xe2,0x57,0x1d,0xfb,0x58,0x3f,0x02,0x72,0x00,0x00, - 0x05,0x20,0x5b,0xe2,0x66,0x28,0x5c,0xec,0xc9,0xf9,0x2a,0xff,0x89,0x4a,0xfc,0xff,0x42,0x07,0x45,0xbc,0x8c,0xdb,0x98,0x02,0x85,0x48,0x61,0x70,0x1d,0xdb,0x72,0xc2,0x25,0x3a,0x00,0x00, - 0x05,0x20,0x5c,0x1b,0xbd,0x28,0xc8,0x17,0x04,0x86,0x8b,0x10,0x5e,0x02,0xfb,0x07,0x16,0x14,0x5d,0x61,0x5d,0x92,0x11,0x44,0xce,0x32,0x13,0xe1,0x4c,0xfd,0x72,0x12,0xde,0x37,0x00,0x00, - 0x05,0x20,0x5c,0x40,0x7f,0x80,0x43,0x91,0x9c,0xfc,0x04,0xdc,0xdc,0x8e,0x01,0xda,0xc8,0xaf,0x90,0x62,0x64,0x16,0xf7,0x11,0xe4,0x87,0xac,0xa4,0x06,0x6f,0x8d,0x87,0x4e,0xd6,0x00,0x00, - 0x05,0x20,0x5c,0xbb,0xa4,0xff,0x86,0xb4,0xe5,0x18,0x1d,0x66,0x80,0x80,0x8d,0x09,0x2b,0xd4,0x44,0x8a,0x95,0x01,0xfa,0x72,0xea,0x8b,0x9c,0xef,0x0f,0xe9,0xc3,0x68,0xf2,0xbf,0x00,0x00, - 0x05,0x20,0x5c,0xba,0xe9,0xbf,0xac,0xc0,0x59,0x78,0x48,0x04,0x02,0x07,0xfb,0x2d,0xd1,0x46,0xa8,0xa4,0x10,0x87,0x8f,0xb9,0xc0,0x0d,0x25,0xb0,0xef,0x4b,0xfd,0x37,0x5d,0x4c,0x00,0x00, - 0x05,0x20,0x5c,0xe6,0x36,0x85,0x74,0xae,0x03,0x90,0xa6,0x1d,0xd4,0xfb,0x50,0x8d,0x4a,0xdb,0xeb,0x91,0x7b,0x38,0x46,0x9c,0x94,0x7f,0x09,0x1b,0xc4,0x69,0x9b,0x3f,0xde,0x83,0x00,0x00, - 0x05,0x20,0x5d,0x1a,0xab,0x05,0x64,0xb2,0xe7,0x58,0x72,0x4f,0x9f,0xd3,0xda,0x69,0xa5,0x7c,0x30,0xd1,0xd4,0xc4,0x7a,0xfe,0x41,0xa9,0x11,0xa6,0xf5,0xa6,0x32,0x6f,0xc6,0x97,0x00,0x00, - 0x05,0x20,0x5d,0x46,0x18,0x02,0xa6,0x1b,0x99,0xd3,0xf4,0x64,0x6d,0x94,0xc1,0xda,0x4b,0x2e,0x6e,0x25,0x17,0xc4,0x18,0xec,0x55,0x91,0x61,0x71,0xbf,0x33,0x3b,0x4c,0xfd,0x24,0x00,0x00, - 0x05,0x20,0x5d,0x93,0x10,0x3d,0x45,0x25,0xd3,0x84,0xc0,0xba,0x8c,0x47,0x1e,0x18,0xe7,0xbb,0x17,0x1d,0xa4,0x78,0x34,0x9c,0xd2,0x4c,0xd3,0x39,0x0c,0xba,0xb2,0x34,0xed,0xfd,0x00,0x00, - 0x05,0x20,0x5e,0x0d,0xaf,0x49,0x2a,0x15,0xfa,0x82,0x0f,0xa0,0xe0,0x3e,0x91,0xdd,0x85,0x23,0xd6,0x51,0x36,0x97,0xd9,0x69,0x7e,0xc6,0x57,0xca,0x99,0xd6,0x18,0x21,0x92,0xd7,0x00,0x00, - 0x05,0x20,0x5e,0x20,0xcc,0x1a,0x22,0xf1,0xa8,0x9b,0x83,0x97,0x5b,0x6d,0x05,0x53,0x75,0x99,0x54,0x18,0xcb,0x23,0x42,0x23,0x20,0x19,0xbe,0xb8,0xf5,0x8b,0x71,0x55,0x70,0xe3,0x00,0x00, - 0x05,0x20,0x5e,0x69,0x4f,0x31,0x33,0xa7,0xea,0x3e,0xf4,0x7a,0x0a,0x1e,0x74,0x09,0x07,0xa1,0x50,0xf7,0x03,0xf5,0xc6,0x19,0xeb,0x95,0xaa,0x63,0x17,0x10,0x6e,0x68,0xca,0x10,0x00,0x00, - 0x05,0x20,0x66,0x95,0xf0,0x25,0x09,0xd5,0xaa,0x62,0xbe,0x41,0x36,0xf5,0x9a,0x3a,0x21,0x92,0x67,0xfd,0x23,0x04,0xdb,0xb3,0x9f,0x0c,0x38,0xbc,0xd3,0xdf,0x96,0xff,0xbc,0xa1,0x00,0x00, - 0x05,0x20,0x66,0xce,0xb6,0x27,0x46,0xce,0x84,0xee,0x9a,0x9c,0x94,0xb7,0x64,0xf0,0x3f,0x20,0x48,0x6d,0x5c,0x2a,0x8c,0x7d,0xd7,0x1a,0xf5,0x3b,0x7f,0xea,0x5d,0xa0,0xec,0x18,0x00,0x00, - 0x05,0x20,0x67,0x1d,0xa5,0x34,0x71,0xff,0x44,0xbb,0x91,0x96,0x0c,0x3a,0xcf,0x55,0xae,0x57,0xc8,0x88,0x48,0xe5,0xe6,0xac,0x94,0xd4,0x06,0xf8,0xe7,0x6b,0xcc,0x05,0xb9,0xe2,0x00,0x00, - 0x05,0x20,0x67,0x82,0xfc,0x36,0xea,0xae,0x95,0x3b,0x5d,0x46,0xf3,0xf4,0x6c,0x50,0x69,0x29,0xc7,0x47,0x87,0xca,0xa6,0x40,0x12,0x40,0x6d,0x12,0x94,0x35,0x17,0x8a,0xba,0x56,0x00,0x00, - 0x05,0x20,0x61,0x3d,0x7d,0x3f,0x8c,0xf2,0x6d,0xb1,0x5d,0x1a,0xba,0xf8,0x0d,0xfe,0x9c,0x74,0x72,0xca,0xee,0xe3,0x73,0xe3,0xd9,0xea,0xa6,0xb2,0x58,0x0a,0x22,0x90,0x8b,0x33,0x00,0x00, - 0x05,0x20,0x61,0x7d,0x36,0x2c,0x86,0x7f,0xe8,0x60,0x7b,0xc2,0x18,0x08,0xbe,0xef,0xfe,0xa0,0x33,0xc8,0x0f,0x76,0x00,0xa8,0x7e,0x73,0x15,0x23,0xc1,0xb5,0x06,0x9c,0x2a,0xb6,0x00,0x00, - 0x05,0x20,0x61,0xcd,0x72,0x0b,0xbf,0x97,0x8f,0xf2,0x22,0xe6,0x23,0x24,0x63,0xac,0x54,0x3b,0x0c,0x7f,0xb3,0xef,0xfb,0xcf,0x01,0xf5,0x59,0x63,0x39,0x67,0x56,0x2f,0xd3,0xe1,0x00,0x00, - 0x05,0x20,0x62,0x5f,0x45,0x80,0x05,0x1e,0x28,0x06,0xba,0x92,0x59,0x5e,0x91,0x4a,0xb4,0x62,0x38,0x41,0xcc,0x4a,0x2d,0x36,0x52,0xb7,0x68,0x78,0x02,0xab,0xa7,0x92,0x6e,0xfb,0x00,0x00, - 0x05,0x20,0x62,0xc0,0xa3,0xcb,0x88,0xb8,0xa1,0x6a,0xab,0x95,0x77,0x04,0x4d,0xad,0xc0,0xef,0x2c,0xc1,0xac,0xa8,0x69,0x95,0xfd,0xa5,0xce,0x54,0x54,0x18,0x83,0xcf,0x7c,0x39,0x00,0x00, - 0x05,0x20,0x63,0x55,0x06,0xee,0x3c,0x4b,0x0d,0xea,0xc5,0x8b,0x7c,0x40,0x12,0x35,0xa3,0xc1,0x67,0xac,0xe9,0x36,0xf1,0xb8,0xd9,0x35,0xcb,0x9f,0x37,0xc1,0x39,0x0a,0x5b,0x31,0x00,0x00, - 0x05,0x20,0x63,0x62,0x11,0x6e,0x08,0xe6,0x68,0xad,0x4f,0x26,0x3b,0x31,0xde,0xa9,0xeb,0x05,0x9a,0x24,0x1f,0xc9,0x53,0x27,0xfe,0xc0,0x59,0x2d,0x35,0xf2,0x36,0x9b,0x30,0x88,0x00,0x00, - 0x05,0x20,0x63,0x63,0x12,0x14,0x81,0x86,0xf1,0x78,0xe8,0x15,0x7c,0x5f,0xb0,0x63,0xf6,0xe6,0xa5,0x7d,0x7d,0x09,0xaf,0xa5,0x34,0xad,0x39,0x7d,0x9c,0x76,0x95,0xaa,0x36,0xbc,0x00,0x00, - 0x05,0x20,0x63,0xb5,0xf9,0xfa,0xd8,0x67,0xbd,0xe0,0xee,0xc5,0x05,0x0e,0xd1,0xc1,0xc2,0x09,0x26,0x39,0x4a,0x57,0x54,0x88,0xff,0x5f,0x83,0x13,0xe8,0x7e,0x8e,0xe4,0xff,0x9c,0x00,0x00, - 0x05,0x20,0x63,0xbc,0xc7,0xea,0x78,0x63,0x01,0xd5,0xea,0x56,0x70,0x7c,0xa8,0x67,0x21,0xd7,0x44,0x26,0x18,0x42,0x2a,0x7a,0xf4,0x0b,0xce,0x62,0x54,0xa9,0xd7,0x96,0xa9,0x35,0x00,0x00, - 0x05,0x20,0x63,0xd1,0xf0,0xa2,0xa1,0x8e,0x9f,0x8b,0x48,0xc0,0x94,0x97,0x6e,0xd8,0x9f,0xf7,0x99,0xfe,0xfd,0xd2,0xd7,0xbd,0xf3,0xec,0xf0,0x69,0xc4,0x59,0x82,0x59,0x1d,0x76,0x00,0x00, - 0x05,0x20,0x63,0xe0,0x1d,0xa4,0x6c,0x1a,0x02,0x08,0xc4,0xab,0xc2,0x10,0xae,0xd9,0x3b,0x22,0x91,0x3b,0xbc,0x9a,0x74,0x10,0x4c,0xcd,0x60,0xbe,0xe8,0xe6,0x5e,0x4f,0x34,0xab,0x00,0x00, - 0x05,0x20,0x64,0x1c,0x2a,0x1e,0xfb,0x85,0x85,0x62,0xd2,0x88,0x6f,0x35,0x8a,0x1e,0x70,0x33,0x3f,0xe1,0xc5,0x6c,0x2d,0x72,0x85,0x17,0xf4,0x8b,0xa7,0xfe,0xc2,0xdb,0xc2,0x9e,0x00,0x00, - 0x05,0x20,0x64,0x42,0x7b,0x79,0xd6,0xff,0xc2,0x98,0x30,0x3e,0xfc,0x69,0x10,0xa8,0x4b,0xe5,0xe5,0xa7,0x09,0x3c,0x7c,0xd1,0xe3,0xb7,0x3c,0xb0,0xa4,0x6f,0x04,0x74,0xb4,0xf0,0x00,0x00, - 0x05,0x20,0x64,0x70,0xf4,0xc7,0x45,0x01,0x92,0x73,0x7b,0x3c,0x45,0xe3,0xfd,0x97,0xad,0x7a,0x89,0x87,0x5e,0x49,0x03,0x04,0x3a,0xf6,0x82,0xf3,0x93,0xd7,0x23,0x58,0x5c,0xab,0x00,0x00, - 0x05,0x20,0x64,0x92,0xbe,0x03,0xec,0x1b,0xff,0x7d,0x04,0x4b,0x5b,0x03,0x7a,0x44,0xe5,0x64,0xef,0x57,0x2f,0x0a,0x73,0x73,0xce,0xbe,0x4c,0x3f,0xd3,0xe7,0xbe,0x65,0xc6,0x3a,0x00,0x00, - 0x05,0x20,0x64,0xd7,0x96,0xde,0x18,0x07,0x5a,0x1a,0x61,0xd1,0xc0,0x73,0x45,0xf0,0x4f,0x1a,0xe2,0xda,0xae,0x27,0x02,0xef,0xa2,0x38,0xd6,0x48,0x89,0xd4,0xef,0x49,0x97,0x6c,0x00,0x00, - 0x05,0x20,0x65,0x7e,0x1e,0x70,0x74,0x05,0xe0,0xfc,0x84,0x79,0x9b,0x62,0x3a,0xb5,0x3e,0xc3,0xe4,0xff,0xe0,0xf2,0xe6,0x76,0x31,0x6a,0x1e,0xe2,0x5d,0x5f,0x3e,0x28,0x9b,0x12,0x00,0x00, - 0x05,0x20,0x65,0x65,0xd0,0x6e,0x5e,0x89,0x8a,0x1a,0xd4,0xd0,0xe7,0x2d,0x9c,0x0f,0xbf,0xa9,0x7a,0xf8,0xed,0x22,0x99,0xc5,0xd8,0x0d,0xdf,0xed,0xcc,0x9e,0x49,0x72,0x67,0xe7,0x00,0x00, - 0x05,0x20,0x65,0x85,0x07,0x13,0x4b,0xa7,0xe9,0xe7,0x1a,0xce,0xff,0xd5,0x1e,0xca,0x3c,0xb5,0xfc,0xfb,0xb5,0xd3,0x50,0xc8,0x25,0x6f,0x18,0x49,0x4f,0xca,0x29,0x78,0x9a,0x74,0x00,0x00, - 0x05,0x20,0x65,0x89,0x53,0xf6,0x3d,0x1a,0xb2,0x31,0xad,0xda,0x72,0xfc,0x17,0x25,0xe3,0x1c,0xb6,0xa6,0xbb,0x97,0x83,0xb1,0xe7,0xfa,0x8b,0x40,0xf6,0xf0,0x01,0x86,0x8c,0xd6,0x00,0x00, - 0x05,0x20,0x65,0xb0,0x9c,0x8e,0x26,0x9e,0x1e,0x1b,0x27,0x14,0x5d,0xb8,0x82,0x92,0x64,0x4e,0x7d,0x7a,0x4a,0x12,0x9d,0x73,0x85,0xe6,0x72,0x79,0xde,0x6d,0x47,0x59,0x2f,0xe8,0x00,0x00, - 0x05,0x20,0x66,0x3d,0xe9,0xd2,0xb9,0x2e,0x31,0xe5,0x28,0x23,0x24,0x2a,0x62,0xbd,0x5b,0xbd,0x1d,0x72,0x46,0x82,0xbc,0xff,0xb9,0xdb,0xd6,0xbd,0x76,0x80,0x37,0x4f,0xd4,0x9b,0x00,0x00, - 0x05,0x20,0x6e,0xcb,0xc6,0x98,0x32,0xd2,0x0d,0x57,0xed,0x3a,0xfd,0x64,0x8f,0xcc,0xe6,0xa4,0x2e,0xec,0x54,0x25,0x23,0x41,0x03,0x9b,0x0f,0xa4,0x07,0x9e,0xa1,0xd5,0x22,0xb4,0x00,0x00, - 0x05,0x20,0x6e,0xca,0x0d,0x62,0x85,0xda,0x36,0xe7,0x8d,0x53,0x45,0xb1,0x7c,0x9c,0x2f,0xa0,0xc5,0x49,0xff,0x75,0x02,0xee,0x38,0xae,0x24,0xd5,0xe5,0xa7,0x38,0x8f,0x18,0xc0,0x00,0x00, - 0x05,0x20,0x6f,0x3e,0x4e,0x19,0x45,0xed,0xe8,0x91,0x01,0x8d,0x90,0x22,0x5a,0x63,0xfc,0xdf,0x4e,0x59,0x1a,0x5c,0xc9,0xda,0x31,0x5c,0x16,0xd1,0x2a,0x02,0xb7,0xd1,0xd4,0x58,0x00,0x00, - 0x05,0x20,0x6f,0x1b,0xf0,0xa2,0xa9,0x0e,0x98,0x52,0x99,0x6b,0xd5,0x16,0xfb,0x60,0x3c,0x66,0x9c,0xe6,0x57,0xb1,0x75,0xe6,0x34,0xf8,0x2c,0x58,0x78,0x23,0x3c,0xbb,0xb0,0xd2,0x00,0x00, - 0x05,0x20,0x6f,0x33,0x6a,0x48,0x96,0xe8,0x9c,0x80,0xd2,0x3c,0x7e,0x8d,0xcd,0xf9,0x53,0x16,0xc5,0x87,0x1b,0x3b,0x92,0x97,0x99,0xd3,0xd1,0xa5,0x16,0x03,0x6d,0x24,0xf2,0x26,0x00,0x00, - 0x05,0x20,0x6f,0xf0,0xa5,0x6c,0x57,0x14,0x32,0x27,0x11,0x0f,0x77,0xcc,0x7c,0x87,0xda,0x53,0xb8,0x3f,0x06,0xf9,0x29,0x88,0xdc,0xdd,0x12,0x9d,0x4d,0xe2,0xd0,0x4b,0x20,0x6a,0x00,0x00, - 0x05,0x20,0x68,0x32,0x09,0x45,0x10,0x70,0x3d,0x07,0x5c,0x6b,0x36,0x53,0x69,0x18,0xd4,0x0d,0xd7,0xe4,0x71,0xa6,0x27,0x61,0xf7,0x33,0xed,0x42,0x41,0x04,0x6b,0x94,0x59,0xa8,0x00,0x00, - 0x05,0x20,0x68,0x86,0x94,0xcc,0xe2,0x57,0xab,0xe7,0x9f,0x3c,0x58,0x06,0x3c,0x0b,0xe0,0xf8,0xb2,0xea,0x27,0x12,0xef,0x58,0x45,0x94,0x4e,0x7c,0xea,0xbd,0x1f,0x88,0xcc,0x17,0x00,0x00, - 0x05,0x20,0x68,0xe6,0xe4,0x77,0x65,0xcf,0xc9,0xe6,0x2f,0xd5,0xf2,0x5b,0xbd,0xfb,0xfd,0x6d,0x84,0x8b,0x7d,0x94,0xeb,0x24,0xdf,0x80,0xb9,0x09,0xc8,0x17,0xc6,0x92,0x81,0xbe,0x00,0x00, - 0x05,0x20,0x68,0xe8,0xd6,0xc9,0x38,0x7f,0x97,0xcb,0x6d,0x24,0x0b,0xad,0xcc,0x9a,0x45,0x88,0xe5,0x8d,0x2e,0x20,0x7a,0x4d,0x25,0x87,0x73,0xaf,0xc6,0x6f,0x3b,0x0f,0x28,0x6d,0x00,0x00, - 0x05,0x20,0x68,0xef,0xad,0xde,0x15,0x9f,0x20,0x4c,0x93,0x28,0x3f,0x2c,0xb4,0xfd,0x90,0x9d,0x85,0xc6,0xe4,0x35,0x61,0xa4,0x48,0x78,0xa2,0xf1,0x34,0x31,0xe2,0xd1,0x62,0xad,0x00,0x00, - 0x05,0x20,0x69,0x12,0xc4,0x3d,0xe4,0x73,0xf0,0xef,0xf6,0xc3,0xd9,0x93,0x13,0x88,0x1b,0x2c,0x7a,0xc7,0x68,0xdb,0xfb,0xad,0x9b,0x0c,0x99,0xbb,0x0d,0xfa,0x1e,0xfe,0xc1,0xae,0x00,0x00, - 0x05,0x20,0x69,0x64,0x8d,0x94,0x8d,0xcc,0x72,0xe1,0x09,0x3f,0x0b,0xf3,0x4a,0xa4,0x37,0x6a,0x13,0xf1,0xb3,0x34,0x7c,0x4d,0xf4,0x03,0x86,0x25,0x1d,0x19,0xba,0x14,0x48,0x3f,0x00,0x00, - 0x05,0x20,0x69,0x9b,0xd2,0x2d,0xb5,0x0b,0x35,0xbe,0x63,0x14,0x6f,0x54,0x14,0xe2,0x3f,0xf3,0xb1,0xd6,0x9e,0x35,0xc0,0x94,0xdd,0xec,0x50,0x10,0x6f,0xae,0x9e,0xdc,0x59,0x5d,0x00,0x00, - 0x05,0x20,0x69,0xde,0x1a,0xea,0x20,0xac,0xfd,0x3e,0x94,0xf7,0xc5,0x68,0x78,0xdf,0x0c,0x06,0xff,0x67,0x9f,0xc3,0xcd,0x32,0xf1,0x8d,0x76,0xdd,0x1c,0x8a,0xe5,0x7e,0x9d,0xf8,0x00,0x00, - 0x05,0x20,0x6a,0x38,0xd9,0x6d,0xd4,0xfd,0x7d,0x93,0xf6,0x11,0x05,0xaa,0xab,0x35,0x92,0x3b,0x63,0x91,0x60,0x5d,0xcb,0x92,0xab,0x7b,0x9f,0x8c,0x5a,0x87,0xad,0x94,0x8c,0x42,0x00,0x00, - 0x05,0x20,0x6a,0x0d,0x12,0x85,0xd4,0xde,0x67,0xeb,0x5c,0x86,0x6f,0x50,0xce,0x0b,0x0c,0x43,0x52,0x24,0xb0,0x32,0x84,0x5d,0x1f,0xb6,0x62,0x8f,0x51,0xfc,0x57,0xc2,0x3d,0xab,0x00,0x00, - 0x05,0x20,0x6a,0x13,0xf7,0xe4,0x3e,0x61,0xe3,0x10,0x74,0xcb,0x0e,0xc7,0x83,0x1d,0x33,0xef,0x64,0xd3,0x5a,0x28,0x56,0x46,0xb0,0x19,0x8f,0x91,0x7e,0x96,0xe9,0xcd,0xab,0x80,0x00,0x00, - 0x05,0x20,0x6a,0x24,0x3e,0x58,0x12,0xe1,0x99,0xb7,0xaa,0xb4,0xb2,0x4f,0xb9,0x04,0x0e,0x76,0xfa,0x99,0xdd,0xcf,0xf6,0x34,0x3f,0xd0,0xdc,0x43,0x97,0xc1,0x14,0xaa,0x8a,0xbb,0x00,0x00, - 0x05,0x20,0x6a,0x31,0x9f,0xd7,0xa5,0x19,0xe1,0x09,0xae,0x3c,0xc6,0xe6,0x23,0x0d,0xc4,0xa6,0xd9,0x86,0xce,0x81,0xe4,0xe3,0x9a,0x99,0x17,0x59,0x92,0x16,0x3a,0xc2,0x11,0x92,0x00,0x00, - 0x05,0x20,0x6a,0xdd,0x0e,0xe9,0xae,0xad,0x1f,0xb1,0x02,0xc2,0x15,0x40,0x05,0x30,0x34,0x1b,0x9c,0x09,0xd9,0x56,0xf8,0xe0,0xb9,0xb6,0x3e,0x86,0xd3,0xc8,0x63,0xf1,0xf3,0x90,0x00,0x00, - 0x05,0x20,0x6b,0x7e,0xfe,0x63,0xef,0xa3,0x76,0xcd,0xce,0xe0,0x80,0x54,0x47,0xcd,0x57,0xc2,0xb3,0x68,0x97,0xfd,0x8d,0x35,0x94,0x30,0x03,0x69,0x2c,0x9f,0x9b,0x71,0xe5,0x1a,0x00,0x00, - 0x05,0x20,0x6b,0x93,0xf5,0x93,0xea,0x52,0x7b,0xca,0x31,0xde,0x60,0xcb,0x30,0x1a,0xb5,0x56,0xf5,0xf1,0x51,0x11,0xfc,0x3f,0xd0,0xb6,0xb4,0x79,0xe3,0x70,0x7d,0x49,0xa2,0x5a,0x00,0x00, - 0x05,0x20,0x6b,0xc4,0xc2,0x1d,0x47,0x3f,0x33,0xab,0x4d,0x5b,0x2f,0x79,0xaf,0x23,0x31,0xc4,0xeb,0x0a,0xe0,0xbe,0x00,0x3e,0x7c,0x5f,0xc7,0x2f,0x92,0x30,0xde,0xa4,0x82,0x18,0x00,0x00, - 0x05,0x20,0x6c,0x62,0x6e,0x3f,0xf3,0xcc,0xd6,0xbc,0xcc,0xeb,0x54,0x32,0xe6,0x41,0x1b,0x19,0x12,0x51,0x01,0x5f,0x9f,0xb6,0xdf,0xe7,0x34,0x73,0x27,0xd0,0x4f,0x39,0xeb,0x38,0x00,0x00, - 0x05,0x20,0x6c,0xf7,0x89,0x02,0x5c,0xb3,0xd2,0x65,0x16,0x7d,0x7b,0x8f,0x12,0xca,0x6c,0xd5,0x4c,0x9f,0xcf,0x55,0xbe,0xf9,0x4d,0xea,0xae,0xc7,0xe3,0x07,0x37,0xe3,0x58,0x4c,0x00,0x00, - 0x05,0x20,0x6d,0x34,0x07,0x7f,0x59,0xb0,0x31,0xa7,0xb9,0xaa,0x3c,0x4b,0xbd,0x6a,0xd8,0x2c,0x62,0xde,0x30,0x6c,0xc3,0xfe,0xde,0xc3,0xb7,0xcb,0x12,0x71,0x18,0x9d,0x70,0xd8,0x00,0x00, - 0x05,0x20,0x6d,0x0a,0xb4,0x22,0xdb,0xa0,0x2b,0xb9,0xe4,0x60,0x5a,0x27,0xad,0x73,0x07,0x09,0x5e,0x24,0xcc,0xc5,0x8b,0x3a,0x81,0x7d,0xc1,0xf2,0xf6,0xc6,0x48,0x18,0xf0,0x9e,0x00,0x00, - 0x05,0x20,0x6d,0x18,0x85,0x9f,0xe7,0x39,0xcb,0xe4,0x37,0x2a,0xcd,0x81,0x8d,0x9f,0x28,0x2f,0x14,0x88,0xba,0x12,0x9d,0xe0,0x1c,0xfc,0xf9,0xab,0xb1,0xa1,0x4c,0xcf,0x04,0x06,0x00,0x00, - 0x05,0x20,0x6d,0x2c,0xf3,0xce,0x94,0x19,0x63,0x2b,0x20,0x72,0xd6,0xa0,0x98,0x7b,0x79,0x35,0xcf,0xdb,0x53,0xe4,0x88,0x0a,0xbd,0xf9,0x38,0x6a,0x29,0x73,0xe7,0xfd,0x42,0xb1,0x00,0x00, - 0x05,0x20,0x6d,0x59,0x4a,0x01,0x27,0x05,0xbf,0xc3,0x77,0xdd,0x5e,0xc1,0xf1,0xbc,0x99,0x97,0x22,0xac,0xb3,0x5a,0xa0,0x7a,0x93,0x9f,0xcc,0x1d,0x73,0x4e,0x6d,0x3c,0x07,0x87,0x00,0x00, - 0x05,0x20,0x6e,0x78,0xb8,0x7d,0xec,0x95,0x9a,0x60,0x12,0xb5,0xd5,0x21,0x80,0x21,0xb0,0xcd,0x26,0x5b,0xad,0x40,0xad,0xcc,0x32,0x6a,0xda,0x92,0xdd,0xa7,0xf8,0x9a,0x50,0x8b,0x00,0x00, - 0x05,0x20,0x77,0x50,0x97,0xe5,0xd1,0xd9,0x1b,0xdb,0xb5,0xa3,0x66,0xdb,0x39,0xa3,0xee,0xe1,0x6f,0x5a,0xeb,0x93,0xdd,0x48,0x7e,0x1b,0xec,0x01,0xd5,0xf7,0x18,0x92,0x0f,0xbe,0x00,0x00, - 0x05,0x20,0x77,0x83,0xfe,0x7e,0x0a,0x79,0xa9,0xe3,0x56,0x44,0x67,0xd6,0x4c,0x2e,0xac,0xbc,0x80,0x08,0x07,0x1e,0xfb,0xe9,0xde,0x95,0x90,0x6f,0x74,0x33,0x03,0x34,0xa8,0x6e,0x00,0x00, - 0x05,0x20,0x77,0xa7,0xc2,0xc7,0xa0,0xc1,0x40,0x3c,0xa0,0x94,0x9c,0xa6,0x6b,0x09,0x6b,0xad,0xae,0x4a,0x65,0x2b,0xbb,0x33,0x26,0x3d,0x3b,0x3b,0xd5,0x52,0x14,0xf9,0x28,0x08,0x00,0x00, - 0x05,0x20,0x77,0xaa,0x1a,0x3c,0x6d,0x78,0xfa,0x1b,0x54,0x57,0xfa,0x2a,0x02,0x08,0xd8,0x77,0xef,0xda,0x8e,0x9d,0x23,0x39,0x50,0x78,0x4c,0xbf,0x51,0x61,0x17,0xb3,0xc0,0x04,0x00,0x00, - 0x05,0x20,0x70,0x09,0x00,0xa8,0xcf,0x22,0xb9,0x06,0xb3,0x6d,0x5e,0x3f,0xeb,0xea,0x65,0x88,0x07,0xa9,0xd1,0xba,0xb9,0x0a,0xb4,0x13,0x3f,0x06,0xe9,0x71,0x8c,0x90,0xe2,0x38,0x00,0x00, - 0x05,0x20,0x70,0x4b,0xd5,0x15,0x5d,0x6f,0x1a,0xd9,0x5b,0xe4,0xcf,0x97,0x2f,0x08,0xf0,0xa7,0x17,0x9e,0x59,0x62,0x57,0xe9,0x3b,0x55,0x89,0x6a,0xd0,0xde,0x37,0x25,0x6c,0x9f,0x00,0x00, - 0x05,0x20,0x71,0x30,0x3a,0xa9,0x2e,0x24,0x31,0xbe,0x7f,0x76,0xba,0x94,0x16,0x38,0x5e,0xce,0x7a,0xcf,0x64,0x4c,0x2f,0x9d,0x5d,0x1c,0xaa,0x12,0x3b,0xc2,0x16,0x48,0x9e,0x28,0x00,0x00, - 0x05,0x20,0x71,0x74,0x6c,0x6a,0xa1,0x59,0xe7,0xdf,0xcd,0xbe,0xc1,0x45,0x99,0x2d,0xac,0x7e,0xaf,0x80,0x8d,0x00,0xce,0x66,0x0e,0x6f,0x1a,0xe5,0xbf,0xe9,0xaf,0xd3,0xa6,0xae,0x00,0x00, - 0x05,0x20,0x71,0x8c,0xdf,0x40,0x2f,0x60,0x40,0x6d,0x6b,0x86,0xa3,0x00,0x6c,0x99,0xae,0xee,0xd8,0x67,0x64,0x3e,0xec,0xdf,0x99,0xf5,0x64,0xca,0x42,0x50,0x85,0x10,0x56,0x39,0x00,0x00, - 0x05,0x20,0x71,0x9a,0xde,0x32,0xd6,0x9b,0x26,0x90,0xc5,0xb0,0xd2,0xa9,0x1f,0xc9,0xe2,0x2b,0x8e,0x8a,0xdd,0x71,0xae,0x77,0x22,0x81,0x93,0xdc,0xf9,0xe7,0xab,0x44,0xd2,0x03,0x00,0x00, - 0x05,0x20,0x71,0xa0,0x31,0x43,0x48,0x34,0x96,0x7d,0xb7,0xa9,0x6e,0xe9,0x3c,0xea,0xaf,0x25,0x67,0x3a,0x2f,0x7e,0xf0,0x67,0xad,0x73,0xd5,0x42,0xca,0xd7,0x5a,0x98,0xab,0xaa,0x00,0x00, - 0x05,0x20,0x72,0x92,0x06,0x4b,0x03,0xe5,0xa9,0x3a,0x9c,0xa7,0x91,0x4a,0x44,0xd9,0x5e,0x43,0xa3,0x4e,0x31,0x95,0xb0,0x0c,0x59,0x49,0xd8,0xe9,0xc4,0xe1,0x1b,0x46,0x4f,0xfc,0x00,0x00, - 0x05,0x20,0x73,0x37,0xab,0x1c,0xf6,0xa8,0xa4,0x18,0x97,0x86,0xf5,0x0f,0xd3,0xd1,0xf2,0x5f,0xbe,0xe0,0x3c,0x42,0x75,0x22,0xab,0xe2,0x3f,0xa1,0x7b,0x9b,0x02,0x17,0x9d,0xc3,0x00,0x00, - 0x05,0x20,0x73,0x18,0xac,0x7e,0x04,0x9d,0x0f,0xce,0x9f,0x8b,0x56,0xe2,0x04,0x2d,0x1a,0xf9,0x5a,0x13,0xc8,0xd7,0xae,0xf3,0x41,0x21,0xae,0x06,0x18,0xdc,0x31,0xdd,0xfe,0xfb,0x00,0x00, - 0x05,0x20,0x73,0x1a,0x61,0x24,0xb6,0x9a,0x31,0x0b,0x04,0xb0,0x81,0x8d,0x90,0xaa,0x73,0x81,0x99,0xb0,0xaf,0x16,0xa7,0x36,0xa7,0xcd,0xda,0x7e,0x34,0x4e,0x19,0xff,0x29,0xe2,0x00,0x00, - 0x05,0x20,0x73,0xda,0xfa,0xe7,0xec,0xc9,0x6d,0xe6,0xe1,0xe6,0x63,0x5b,0xdc,0x9a,0x6b,0xcd,0xff,0x7a,0x0b,0x96,0xfd,0x41,0x3e,0x86,0x51,0xe3,0x07,0x37,0xff,0xea,0xcf,0xc9,0x00,0x00, - 0x05,0x20,0x74,0x22,0xbe,0xff,0x6d,0xb7,0x99,0x8d,0x3b,0xac,0xa3,0xfd,0x48,0x79,0xec,0xea,0x18,0xcb,0x6c,0xcd,0xaa,0x00,0x74,0x1b,0xa2,0x11,0x0c,0x49,0x72,0xc5,0x6e,0x0f,0x00,0x00, - 0x05,0x20,0x74,0x6b,0x23,0xc7,0x10,0x86,0xb8,0xbd,0x70,0x9c,0x1d,0x5c,0x25,0x5f,0x44,0x52,0x78,0x7a,0x73,0x4e,0x9c,0x2f,0x2a,0xe2,0xb8,0xfc,0xd9,0xf3,0x9c,0x69,0x96,0x7e,0x00,0x00, - 0x05,0x20,0x75,0x14,0x45,0x8e,0x06,0x75,0x41,0x53,0xed,0xaf,0x30,0x74,0x1c,0x7e,0xde,0x3d,0x0d,0xdf,0xf6,0x80,0x26,0xb9,0x9f,0x52,0x05,0x1a,0xfc,0x55,0x9f,0xec,0x07,0xa3,0x00,0x00, - 0x05,0x20,0x75,0x5a,0xad,0xd8,0xa1,0x8a,0xab,0x5a,0x4c,0x9e,0xaa,0x9b,0xd3,0x2c,0xe3,0x9a,0xef,0x1f,0x37,0x15,0x20,0x50,0x55,0xd6,0x3d,0x5f,0xad,0x2f,0x49,0xd1,0x78,0x35,0x00,0x00, - 0x05,0x20,0x75,0x89,0x75,0xd0,0x89,0x0e,0xc9,0x2c,0xdf,0x8f,0xd8,0x7d,0x9a,0x5f,0x06,0x34,0xaf,0x79,0xaa,0xe5,0x35,0xdd,0x85,0xa8,0x06,0x29,0x05,0x2d,0x84,0xc5,0x6b,0xd2,0x00,0x00, - 0x05,0x20,0x76,0x74,0x80,0x6c,0xab,0x7b,0x36,0x3a,0x6a,0x78,0xa4,0xa8,0xb8,0xb7,0xe7,0xf9,0x34,0x47,0x6d,0x34,0xca,0xa2,0xc6,0xef,0x81,0xab,0x62,0xb1,0x46,0x86,0xaf,0xd0,0x00,0x00, - 0x05,0x20,0x76,0x5a,0xf7,0x9c,0x68,0x91,0x6a,0xb1,0x24,0xca,0xab,0x71,0xe6,0x03,0xda,0xb6,0x3d,0xbf,0xb4,0xfc,0xac,0xdf,0x7b,0x5b,0x9f,0x41,0x5e,0xc5,0xc1,0x49,0xae,0xc2,0x00,0x00, - 0x05,0x20,0x7e,0xc1,0x4d,0x5b,0xa9,0x6a,0xa1,0x43,0x5d,0xaa,0xa2,0x93,0xc8,0xd2,0x55,0xc3,0x6b,0x9d,0xba,0xe0,0xb0,0xcb,0xc0,0x27,0x24,0xc5,0xea,0x5a,0xe3,0x27,0x61,0x27,0x00,0x00, - 0x05,0x20,0x7f,0x27,0x28,0x5a,0xa3,0x78,0x11,0x3a,0xac,0xc0,0xa2,0x4b,0x1d,0x33,0x50,0x0c,0x77,0xe8,0x22,0xd4,0x90,0x25,0xdc,0xa9,0x14,0x9f,0xed,0xab,0x24,0x4f,0xdc,0xa0,0x00,0x00, - 0x05,0x20,0x7f,0x9d,0xb9,0xe5,0x6b,0x95,0x99,0xa4,0xf2,0xc0,0x3e,0xfa,0xd4,0x47,0x1c,0x98,0x87,0x4f,0x2e,0x1d,0x0f,0xbe,0x43,0x92,0xa2,0xbf,0x3b,0x20,0x13,0xef,0x0f,0x86,0x00,0x00, - 0x05,0x20,0x7f,0xd0,0x52,0x21,0x3b,0xa9,0xc7,0x2d,0x8d,0x08,0x3d,0xfb,0x04,0x32,0x82,0xc6,0x4c,0x25,0x75,0xcc,0x2a,0xa1,0x71,0x71,0xea,0x08,0x53,0x32,0xd3,0x87,0x7f,0xad,0x00,0x00, - 0x05,0x20,0x78,0x40,0x6f,0xfa,0xfd,0xc6,0x1d,0xd1,0xee,0xd8,0x7d,0x66,0xe3,0xdd,0x86,0x0c,0xc7,0x14,0xa4,0x3b,0xea,0xd2,0xd8,0x72,0xdd,0x2b,0xdc,0x6a,0x62,0x7d,0x62,0x7d,0x00,0x00, - 0x05,0x20,0x78,0x4b,0x38,0xcc,0x73,0x38,0x53,0xd8,0x08,0x82,0x88,0x06,0x46,0xec,0xe3,0xad,0x9c,0xc8,0x44,0xd2,0x21,0x05,0xe4,0x07,0xa7,0xd7,0x1b,0xac,0x89,0x15,0x1c,0x00,0x00,0x00, - 0x05,0x20,0x78,0xb8,0x3e,0xd7,0xfc,0x9c,0x79,0x5c,0xf7,0x8f,0x0c,0x7b,0xf2,0x24,0xc0,0xff,0xba,0x47,0xfa,0xb6,0x57,0x54,0xeb,0xf7,0xa6,0x2b,0x82,0x8e,0xf7,0xfa,0x03,0xe6,0x00,0x00, - 0x05,0x20,0x78,0x85,0xe1,0x36,0x38,0xe3,0x01,0x45,0xff,0x2b,0x08,0xf7,0xa5,0x1c,0x0b,0x00,0x2a,0xa1,0x06,0xdd,0x38,0xd3,0x45,0x73,0x29,0xb3,0xdd,0x20,0x3a,0x29,0x40,0x84,0x00,0x00, - 0x05,0x20,0x78,0x86,0xb8,0x5b,0x40,0xb3,0xde,0xe3,0x85,0x14,0x20,0xf9,0x12,0x94,0xd2,0xf3,0x76,0xba,0xee,0x67,0x3b,0x9b,0xb8,0xfb,0xe9,0x65,0xf5,0xee,0xea,0x17,0xd2,0x8f,0x00,0x00, - 0x05,0x20,0x79,0x26,0x45,0x49,0xc5,0x35,0x8c,0xd1,0xc8,0x67,0xf3,0xaa,0x7d,0x60,0x6a,0x89,0x9f,0x88,0x1a,0x73,0x44,0xf9,0x49,0x52,0x52,0xe0,0x72,0xa9,0x54,0x70,0x50,0x48,0x00,0x00, - 0x05,0x20,0x79,0xc8,0xd1,0xe3,0x13,0x8c,0x07,0x1d,0x54,0xb2,0xb6,0xd4,0x85,0xfb,0x14,0x47,0x6a,0x1d,0x3f,0x95,0xed,0xe8,0x31,0x93,0x26,0xef,0xed,0x21,0xdb,0xb4,0xc4,0x29,0x00,0x00, - 0x05,0x20,0x7a,0xce,0xec,0xf7,0x77,0x3b,0xd6,0xcc,0x50,0x89,0x6c,0x8d,0xd0,0xa8,0xa4,0xd7,0x1d,0x6d,0xbc,0x2b,0x1e,0x24,0xe7,0x56,0x94,0x7d,0x3d,0x0b,0x07,0x6d,0x9c,0xc4,0x00,0x00, - 0x05,0x20,0x7b,0x38,0xda,0x2a,0x39,0x68,0xc7,0xa5,0xd4,0x7b,0x91,0xd1,0x57,0xa6,0x22,0x0a,0x56,0xe6,0xcd,0x97,0x38,0x0d,0xab,0xe4,0x65,0xef,0xf5,0x26,0xd8,0x31,0xdb,0xfc,0x00,0x00, - 0x05,0x20,0x7b,0x7a,0x2b,0xef,0x4b,0x4c,0x6b,0x94,0xfa,0xff,0x3b,0xcd,0x82,0x97,0x71,0x59,0x66,0x4b,0xce,0x0f,0x7f,0x32,0xdd,0xb5,0x45,0xa1,0x63,0x17,0xb5,0xf4,0x43,0x33,0x00,0x00, - 0x05,0x20,0x7b,0x4f,0x27,0xd3,0x71,0x5b,0x85,0x91,0x87,0x32,0xc4,0x81,0xa4,0x16,0x72,0x33,0x91,0x8d,0xe4,0xc2,0x1e,0xb4,0x97,0x0d,0x8a,0xfe,0x46,0x90,0x34,0xe8,0x23,0x16,0x00,0x00, - 0x05,0x20,0x7b,0xc9,0xa4,0x96,0x41,0xd5,0xe2,0xc3,0x5a,0x86,0x0c,0x3e,0x03,0x63,0x9c,0xa0,0x83,0xec,0x43,0x90,0x0d,0x0a,0x02,0xea,0x47,0xff,0x83,0xc5,0x59,0xe0,0xe2,0x45,0x00,0x00, - 0x05,0x20,0x7b,0xc9,0x9e,0xef,0x11,0x97,0x96,0x06,0xe2,0xb8,0xbd,0x2e,0x15,0xc2,0xe8,0xa5,0x4e,0xd8,0x56,0xb3,0x01,0x59,0x60,0x20,0x7a,0x51,0x9f,0xa1,0xdf,0x55,0xea,0x01,0x00,0x00, - 0x05,0x20,0x7c,0x1b,0x0b,0x5d,0x7f,0x4c,0xa2,0xe5,0x7e,0xa6,0x79,0x85,0x55,0xde,0xcb,0x51,0xbd,0x81,0x2a,0xfb,0xdb,0x76,0x6e,0x5c,0xbd,0x5d,0x68,0xd9,0xd9,0xbe,0xd8,0x7c,0x00,0x00, - 0x05,0x20,0x7c,0x51,0xbf,0xfa,0x3e,0xa5,0x2c,0x66,0x85,0xa4,0xaa,0x91,0xf1,0x6f,0xdb,0x3f,0x23,0x82,0xd9,0x39,0x07,0xde,0x20,0x96,0x56,0x84,0x2e,0xaf,0x1d,0xb1,0x51,0xd2,0x00,0x00, - 0x05,0x20,0x7c,0x85,0x6e,0xe3,0x20,0x4f,0x53,0x2d,0x15,0xbf,0x36,0x63,0x97,0x27,0xd3,0x23,0x9a,0xb9,0x38,0xeb,0x0b,0x6a,0x31,0x3b,0xdd,0xa0,0x46,0x42,0xbd,0xaf,0xb1,0xde,0x00,0x00, - 0x05,0x20,0x7c,0xf6,0xc8,0x32,0xaa,0xaf,0xc0,0xb2,0x24,0x1f,0xa8,0x27,0x35,0xe2,0x54,0xf5,0xfe,0x64,0xb4,0x36,0x85,0x6d,0x3a,0x72,0x4a,0xc8,0x03,0x55,0x27,0x33,0x2a,0x35,0x00,0x00, - 0x05,0x20,0x7d,0x3c,0x4d,0x07,0xa1,0xcf,0xfb,0x06,0xb1,0xfa,0x8b,0xaf,0xae,0xe8,0x0a,0x92,0xd6,0xd4,0x4e,0xba,0x34,0x5a,0xdf,0xc0,0xb8,0xca,0x54,0x54,0x3b,0xf6,0xe9,0xfc,0x00,0x00, - 0x05,0x20,0x7d,0x1b,0x25,0xbc,0xf3,0xf3,0xf1,0x26,0xae,0x64,0x3c,0xf5,0xc8,0x9a,0xb1,0x53,0x32,0x31,0xf3,0x7f,0x5b,0x5e,0x55,0xb9,0x36,0x02,0x97,0xd1,0xe3,0xcc,0x09,0x18,0x00,0x00, - 0x05,0x20,0x7d,0x7c,0x6f,0xd1,0x0d,0xf7,0x77,0x12,0x44,0x68,0x45,0x46,0x69,0xb9,0x11,0x4d,0x5c,0xa4,0xba,0xc8,0xe0,0x76,0x5b,0x02,0x72,0xc8,0xd7,0x32,0x61,0xd2,0xda,0x34,0x00,0x00, - 0x05,0x20,0x7d,0x61,0x8a,0xb7,0x4b,0x7d,0x5c,0x4c,0x1c,0xc2,0x35,0x1a,0xe8,0x4c,0x93,0x54,0x54,0xff,0xf9,0x04,0x36,0x1c,0x84,0x68,0x05,0xe0,0xa2,0xd5,0xcd,0xde,0x30,0x75,0x00,0x00, - 0x05,0x20,0x7d,0xb9,0xaf,0x77,0xca,0xd5,0x43,0x6b,0xb2,0xb1,0x16,0xa0,0x19,0x67,0x69,0x92,0xea,0x2b,0x80,0xeb,0x6f,0xe2,0x43,0xc8,0x28,0x07,0x52,0x34,0x3b,0x4a,0x69,0xf7,0x00,0x00, - 0x05,0x20,0x7d,0xc3,0x83,0xd7,0xda,0x98,0x87,0x08,0x3d,0x7e,0x78,0x5f,0xb7,0x1b,0xe0,0x4e,0x72,0x26,0x86,0xe8,0x65,0x7a,0xac,0x4f,0x67,0x40,0xf6,0x34,0x8f,0x74,0xb2,0x87,0x00,0x00, - 0x05,0x20,0x7e,0x0b,0xa1,0x49,0x17,0x4d,0x0d,0x67,0xf8,0x03,0xd8,0x55,0x1c,0x6a,0x8b,0x56,0x53,0xf4,0x34,0x5f,0xe7,0xc7,0x26,0x3d,0x5f,0x41,0x03,0x44,0x0d,0x5c,0x5e,0xe2,0x00,0x00, - 0x05,0x20,0x7e,0x1c,0xb2,0x70,0xd2,0x5c,0x58,0x46,0x94,0x4c,0x1f,0x10,0xb8,0x63,0x35,0x95,0x31,0x14,0xe0,0xa5,0x48,0x6d,0xf0,0x34,0xc4,0x6c,0xe0,0x95,0x29,0x69,0x44,0xe1,0x00,0x00, - 0x05,0x20,0x86,0xe8,0x4a,0x24,0x7b,0xde,0x95,0xd8,0x26,0xe3,0x82,0x93,0x34,0xac,0xca,0x66,0xd5,0x3a,0x8f,0x1f,0x04,0xe5,0xc1,0x69,0xc6,0x15,0x5c,0xa7,0x1b,0x96,0x66,0xeb,0x00,0x00, - 0x05,0x20,0x87,0x1d,0xf0,0x97,0x7f,0x27,0x80,0x5b,0xfc,0x95,0xb0,0xf0,0xea,0xca,0x0f,0x9a,0x6c,0xef,0x4c,0x7b,0x17,0xa1,0x34,0x9f,0x91,0x98,0xda,0x67,0xee,0x71,0xb2,0x36,0x00,0x00, - 0x05,0x20,0x87,0x7a,0x6e,0x9b,0xd2,0xe7,0xce,0x8f,0xbc,0x54,0x73,0x28,0x6d,0xd6,0x22,0x1f,0xbf,0x54,0xa3,0xf4,0x96,0x8d,0x06,0x14,0x9f,0x83,0x74,0xd5,0x43,0xb5,0xcf,0x74,0x00,0x00, - 0x05,0x20,0x87,0x97,0x99,0x13,0x34,0xe2,0x07,0x77,0x8e,0xd1,0x77,0x2f,0xe9,0x56,0xd9,0xfa,0x7c,0x7f,0x1a,0x4e,0xf1,0x1a,0x81,0x8a,0xf5,0xfa,0x4e,0x2d,0x18,0x24,0x7d,0x33,0x00,0x00, - 0x05,0x20,0x87,0x9d,0xb2,0x41,0xb8,0x37,0x39,0x4c,0xa7,0x30,0x25,0x07,0x20,0x35,0x46,0x1b,0xa9,0x85,0xc8,0xea,0x38,0xce,0xbf,0x87,0x81,0x85,0xd4,0x16,0x0d,0xac,0xe2,0x01,0x00,0x00, - 0x05,0x20,0x87,0xfc,0x6e,0x2d,0x4e,0x90,0x75,0x2b,0x91,0xa7,0xe7,0xc9,0x49,0xc0,0xd6,0xb6,0x53,0x87,0x9f,0xba,0x8a,0x22,0x2f,0x6f,0xb6,0x55,0x9b,0x79,0x11,0x31,0xc8,0xc6,0x00,0x00, - 0x05,0x20,0x87,0xdb,0x31,0xdb,0x1e,0xbd,0x09,0x8a,0x98,0xe1,0x48,0x18,0x58,0x9f,0xda,0x04,0x27,0x4a,0x6d,0x0a,0xb1,0xbd,0xad,0x11,0x9c,0xe3,0xc1,0xb1,0x65,0xcc,0x88,0xd3,0x00,0x00, - 0x05,0x20,0x80,0x3f,0xf5,0xe7,0xe3,0x5f,0xb9,0x0b,0x4d,0x3c,0x2d,0xee,0xbc,0xf9,0xd3,0x55,0x2b,0x5e,0x68,0x62,0x41,0x8c,0xd6,0x5f,0xda,0x23,0x83,0x2d,0x5e,0x08,0xdd,0x57,0x00,0x00, - 0x05,0x20,0x80,0x21,0x5b,0xb3,0x15,0x86,0x99,0xcb,0x39,0x81,0x64,0xc1,0x9d,0xba,0x91,0xdc,0x18,0xff,0x90,0x93,0xdc,0x16,0x4e,0x95,0x6d,0x8c,0xb6,0x0e,0xd8,0xc5,0x3d,0xc2,0x00,0x00, - 0x05,0x20,0x80,0x2c,0x41,0xf5,0xd4,0xed,0x43,0xcd,0x50,0xc8,0xe6,0x8c,0xeb,0xc7,0x52,0xf0,0xa1,0x97,0xe0,0xfb,0x97,0x41,0x35,0x1e,0xa5,0xae,0x0f,0x81,0x78,0x0d,0xbe,0x00,0x00,0x00, - 0x05,0x20,0x80,0xc6,0x6f,0xb3,0x18,0x5a,0x1a,0xde,0x4e,0xde,0x50,0xd2,0xc6,0x3f,0xc5,0x96,0x09,0x35,0x3a,0x4d,0x88,0x5f,0xa3,0x49,0x37,0xff,0xe6,0xc5,0x43,0x10,0xaf,0xa8,0x00,0x00, - 0x05,0x20,0x81,0x17,0x20,0x48,0x84,0xab,0x59,0x9d,0x51,0xaf,0x75,0x4f,0xc6,0x85,0xe9,0x7c,0x8e,0x93,0x73,0xa8,0xa0,0xd0,0x02,0xf7,0x21,0x69,0x88,0x05,0xda,0xd4,0xb9,0x34,0x00,0x00, - 0x05,0x20,0x81,0x43,0x43,0x1c,0xb1,0xe9,0xce,0x67,0x39,0x80,0x96,0x2a,0x8b,0x2b,0x79,0x43,0x75,0xca,0x12,0x2f,0x5f,0xa9,0x1c,0xf6,0x4c,0xcd,0xc5,0xa1,0xa2,0xbd,0x45,0xee,0x00,0x00, - 0x05,0x20,0x81,0x57,0xb4,0x73,0xa8,0x79,0xa8,0x67,0x7e,0x84,0x95,0xb1,0xbc,0x35,0xa1,0x01,0x27,0xff,0xdc,0x16,0x43,0xd7,0x56,0x33,0x6a,0x7f,0x0a,0x9f,0xea,0x15,0xc8,0xbc,0x00,0x00, - 0x05,0x20,0x81,0xe8,0xae,0xe6,0x1d,0xaf,0xcf,0xd7,0xfd,0xde,0xd1,0xa5,0x73,0x4e,0x10,0x77,0xea,0x0e,0x23,0xff,0x77,0x6a,0x44,0x7a,0xd3,0x9d,0xe0,0x23,0x02,0xdc,0xf9,0xfe,0x00,0x00, - 0x05,0x20,0x82,0x2b,0x48,0x2a,0x31,0xdb,0xeb,0xb8,0xd1,0x7c,0xb1,0xaf,0xc7,0x73,0x2e,0x6f,0x6c,0x43,0x20,0x73,0xe8,0x29,0x85,0xd7,0x61,0x39,0x02,0x5a,0x27,0xce,0x80,0x29,0x00,0x00, - 0x05,0x20,0x82,0x46,0x59,0x84,0xe2,0x01,0x8e,0x39,0x2f,0x37,0x4c,0x2f,0xb6,0xb0,0x8c,0xe6,0x7a,0xfe,0xa6,0x7f,0x27,0xdd,0x4e,0x84,0x79,0xea,0xd6,0xd8,0x2e,0xf2,0x39,0x3a,0x00,0x00, - 0x05,0x20,0x82,0xb6,0x88,0x6e,0xd1,0xf1,0x19,0x39,0x8d,0x0b,0xa8,0xe0,0x1a,0xfa,0xad,0x82,0x64,0x7a,0x67,0x3e,0x66,0x17,0x6c,0x15,0xdb,0xcf,0xaa,0xf4,0xe2,0xd5,0x69,0x44,0x00,0x00, - 0x05,0x20,0x82,0x9c,0x7c,0xba,0xe8,0x31,0x0b,0xcd,0xc5,0xdf,0x61,0x74,0x11,0xff,0xc4,0xc3,0x49,0x4a,0x27,0x55,0x2e,0x22,0x46,0x50,0xb5,0xa1,0x65,0x25,0x48,0x35,0x4e,0xd3,0x00,0x00, - 0x05,0x20,0x82,0xa5,0x33,0xa3,0x30,0x99,0x46,0x94,0xdc,0x51,0x01,0xe1,0x75,0x2f,0x61,0x25,0x7f,0xd5,0x6b,0x81,0x58,0x0d,0x15,0x3a,0x59,0xb9,0x1b,0xce,0xe4,0x8b,0x42,0x5e,0x00,0x00, - 0x05,0x20,0x82,0xce,0xa5,0xd7,0x70,0xdc,0x63,0x2c,0x86,0x2a,0xbd,0xbf,0xde,0xad,0xe3,0x0d,0x23,0x7b,0x09,0x3d,0x1a,0xaf,0x64,0x08,0x12,0xe7,0x8a,0xbc,0xcd,0x6a,0x18,0x92,0x00,0x00, - 0x05,0x20,0x83,0x26,0x6e,0xd1,0x59,0xb9,0x19,0x25,0x4e,0x57,0xb6,0x83,0x1b,0x31,0xc7,0x21,0xf0,0x43,0xd9,0x6b,0x22,0xb1,0xb5,0x53,0x24,0x86,0x71,0xc5,0x90,0x62,0x75,0x36,0x00,0x00, - 0x05,0x20,0x83,0x46,0x68,0x1d,0x3b,0x13,0xc3,0x78,0xaa,0x74,0xf4,0x7f,0x89,0x01,0xce,0x10,0xa1,0x9a,0xc8,0x8b,0xab,0x75,0x37,0x9e,0x9b,0x7a,0xef,0xac,0xf5,0xd4,0x70,0x8d,0x00,0x00, - 0x05,0x20,0x83,0x60,0xe4,0xae,0x67,0xc3,0x3f,0x9e,0x1a,0xc8,0xc8,0x82,0xb3,0xbc,0x7a,0x99,0xf1,0xfa,0xf0,0x1e,0x41,0x58,0x4e,0xfc,0x39,0xc2,0xf6,0xdb,0xe5,0x49,0xf2,0x04,0x00,0x00, - 0x05,0x20,0x83,0xa3,0x91,0xa4,0x44,0x96,0x4b,0xcd,0xe9,0xc1,0xb8,0x3f,0xb9,0xb6,0xc7,0x80,0x7e,0xb9,0xde,0x37,0x59,0x54,0xa8,0x32,0xda,0x2a,0xd8,0x54,0x9d,0xd8,0xae,0xfc,0x00,0x00, - 0x05,0x20,0x83,0xfa,0xf7,0x99,0xd9,0xc8,0x55,0x44,0x34,0xc6,0xd6,0xb2,0x60,0x30,0xbc,0x76,0x5e,0x4d,0x37,0xa7,0x4a,0xe9,0xc4,0x6b,0xb1,0xf3,0xd3,0x0b,0x69,0xa6,0x89,0xdd,0x00,0x00, - 0x05,0x20,0x83,0xc6,0x30,0x55,0xa5,0x5c,0x7b,0x31,0xb0,0x98,0x79,0x29,0xd5,0xc5,0x29,0xb4,0x8d,0x31,0x9f,0x3f,0x3d,0xba,0x46,0x5d,0x18,0x4a,0x84,0xff,0xb3,0xf7,0xc4,0x84,0x00,0x00, - 0x05,0x20,0x83,0xdd,0xba,0x77,0xdd,0x8b,0x0c,0x44,0x3a,0x34,0x96,0x40,0x30,0x8b,0x95,0x63,0xcc,0x9c,0x38,0xff,0x83,0xa3,0x5e,0x2f,0x04,0x2a,0xfe,0x62,0x12,0xd8,0xc6,0x7e,0x00,0x00, - 0x05,0x20,0x84,0x10,0x05,0x5b,0x5c,0x70,0x4b,0x6c,0xef,0xfd,0x31,0x43,0xe6,0x53,0x20,0xcf,0xe7,0x1f,0x01,0xa8,0xdb,0x87,0xe5,0x91,0xce,0xbf,0xd3,0x6c,0xc5,0x19,0xc5,0xd5,0x00,0x00, - 0x05,0x20,0x84,0x19,0x7a,0xd1,0x36,0x47,0x15,0x33,0x27,0x42,0xa4,0x19,0x6e,0x29,0x14,0x4a,0x8b,0xfa,0x2a,0x2a,0x71,0x3b,0x1c,0x63,0x81,0x48,0x7f,0x3c,0x2c,0x8f,0x5c,0x92,0x00,0x00, - 0x05,0x20,0x84,0x5f,0x9f,0x7e,0x22,0xb4,0x42,0xf1,0x38,0x4a,0x40,0xfa,0xc5,0xeb,0x83,0x98,0xce,0x73,0x91,0x53,0xc6,0xee,0x3f,0x78,0x8a,0x56,0x01,0x37,0x95,0x23,0xd5,0x94,0x00,0x00, - 0x05,0x20,0x85,0x32,0xa8,0x9b,0x21,0xeb,0xd8,0xde,0x73,0xdd,0xf7,0x3e,0xa2,0x75,0x72,0x28,0x64,0x48,0x35,0xd1,0x8f,0x96,0x9a,0x96,0x57,0x10,0x0c,0x9f,0xc7,0x2b,0xf9,0xc5,0x00,0x00, - 0x05,0x20,0x85,0x7a,0x4e,0x25,0x62,0x63,0x14,0x35,0xb0,0xfd,0x93,0xd5,0x5a,0xea,0xc6,0x4e,0xf9,0xba,0xb3,0x98,0x74,0xf1,0xa3,0xb8,0xb4,0xca,0x38,0xb7,0x45,0xad,0xd9,0xf3,0x00,0x00, - 0x05,0x20,0x85,0x8f,0x55,0xbe,0x27,0x56,0xdb,0x39,0x5a,0x3d,0xbb,0x66,0xd1,0x68,0xe7,0x33,0x2a,0x3d,0x84,0x26,0xc9,0x94,0x17,0x30,0x28,0x40,0x4f,0x19,0x27,0xea,0xf1,0xb1,0x00,0x00, - 0x05,0x20,0x86,0x14,0x0a,0xbd,0x21,0x20,0xa5,0x20,0x3c,0x9f,0xfb,0x23,0x74,0xde,0xd7,0x11,0x25,0xa3,0x05,0x23,0xf1,0xb2,0x4b,0x0f,0xd9,0xc4,0xb7,0xaa,0x1d,0x8d,0x6d,0xb6,0x00,0x00, - 0x05,0x20,0x86,0x21,0x66,0xf6,0xf2,0xd7,0x0f,0xee,0xc5,0x63,0x8a,0xc9,0xd6,0x4b,0x00,0x8b,0x20,0xe2,0xed,0x61,0xde,0xe9,0x9f,0xca,0x93,0x05,0x2c,0x33,0x76,0x08,0xa1,0xdd,0x00,0x00, - 0x05,0x20,0x8e,0x9f,0xd5,0x42,0x3f,0xba,0x5d,0xc6,0x8b,0x3f,0x5f,0x88,0xa1,0xdf,0x46,0x27,0xa5,0x4d,0x27,0x5a,0x4e,0xa6,0x39,0x3a,0xf4,0xe2,0x6d,0xba,0x7b,0xf9,0xfb,0xdc,0x00,0x00, - 0x05,0x20,0x8f,0x28,0xa1,0xa7,0xe2,0xd2,0xbb,0xdf,0xab,0xf0,0x1f,0xa4,0x80,0x50,0xe7,0x85,0x05,0x23,0xdb,0x1a,0x8c,0x54,0xcf,0x7a,0x76,0xce,0x0f,0xc4,0xa2,0x82,0x43,0x01,0x00,0x00, - 0x05,0x20,0x8f,0x47,0xd4,0x9a,0x42,0xac,0xbc,0x8b,0xf6,0xbe,0xe7,0x9c,0x7b,0x03,0xdc,0xad,0x27,0x4f,0xd1,0x85,0x22,0x9b,0x11,0x68,0xf1,0x26,0x46,0x99,0xae,0x3c,0x5b,0x3c,0x00,0x00, - 0x05,0x20,0x8f,0x87,0xc6,0x38,0x11,0x7e,0xb5,0x66,0xb6,0x4d,0x64,0xaf,0x09,0xee,0x5b,0xd1,0xb3,0x89,0x08,0x02,0x10,0x04,0xa1,0x03,0x35,0x43,0x22,0x47,0xfe,0x40,0xd7,0x98,0x00,0x00, - 0x05,0x20,0x8f,0x8e,0x3d,0xa9,0xb0,0x46,0x9f,0xe5,0x02,0xdf,0x3e,0x03,0x11,0x17,0x50,0xea,0xc4,0x08,0xd1,0x62,0x16,0x65,0xb9,0x18,0x54,0xcf,0x30,0x2d,0x48,0x09,0xd9,0xb0,0x00,0x00, - 0x05,0x20,0x8f,0xc3,0x43,0x7a,0xc1,0x39,0x2b,0x08,0x2c,0x20,0xab,0xa8,0x9d,0x98,0xcf,0x07,0xc9,0xdf,0xc8,0x23,0xdb,0x91,0x55,0x66,0x04,0xc0,0x0d,0x19,0xde,0x47,0x62,0x5e,0x00,0x00, - 0x05,0x20,0x88,0x3f,0x99,0xc3,0xee,0x87,0xd2,0x27,0x65,0xf4,0x47,0xc5,0xcc,0xd7,0xfe,0x31,0xff,0x14,0xd8,0xf0,0xe9,0x54,0xfb,0xbf,0xe3,0xad,0xbf,0x14,0x4d,0x02,0x57,0xbd,0x00,0x00, - 0x05,0x20,0x88,0x7f,0x3c,0x24,0x7e,0x32,0x3e,0x4a,0xb2,0x7d,0x66,0x6b,0x30,0xba,0x20,0x64,0x10,0xfe,0x6e,0x47,0xfe,0xb2,0x9b,0xb6,0xc7,0x4f,0x55,0xfd,0x64,0xa8,0xd9,0xbc,0x00,0x00, - 0x05,0x20,0x88,0x7f,0x7d,0x79,0x6c,0x23,0xca,0x11,0x0f,0xf6,0x9d,0xe9,0xcd,0x3c,0xbc,0x98,0xee,0x12,0x75,0xfd,0xcc,0x8b,0xb1,0x5a,0x94,0x50,0xf8,0x59,0x73,0x27,0xbc,0xc2,0x00,0x00, - 0x05,0x20,0x88,0xf4,0x2b,0x6d,0x14,0x55,0x26,0x7d,0x2e,0xc4,0xe7,0x21,0xf2,0xa1,0xe0,0xb4,0x5a,0x4d,0x21,0xde,0xc6,0xcb,0x8c,0x57,0xb7,0x25,0xbd,0x51,0xec,0xee,0x96,0xa0,0x00,0x00, - 0x05,0x20,0x89,0x0a,0xee,0x57,0xfa,0xfa,0x58,0x52,0xfb,0x0b,0x8b,0xc2,0xaa,0x8f,0xa4,0x62,0xcb,0x1d,0x1c,0x0c,0x01,0x0f,0xfc,0x9d,0xde,0x75,0x40,0xbe,0x8d,0x8d,0xb2,0xe6,0x00,0x00, - 0x05,0x20,0x89,0x0b,0x19,0xe0,0x61,0x1c,0x97,0x91,0x18,0x52,0x63,0x1e,0x7d,0xf3,0x7d,0x82,0x0d,0x80,0x24,0xfc,0x86,0x9b,0x55,0xff,0xbe,0x2f,0x70,0xe4,0xba,0x8b,0x6f,0x31,0x00,0x00, - 0x05,0x20,0x89,0x4d,0x24,0x9f,0x15,0x80,0x68,0xd2,0x17,0xa1,0xec,0x74,0x46,0x26,0x8e,0xbd,0xf4,0x8f,0xc4,0x52,0x5f,0xcc,0x09,0x9f,0x1a,0x6f,0x0d,0x64,0xe3,0x00,0x9f,0x83,0x00,0x00, - 0x05,0x20,0x89,0xbd,0xff,0xd5,0xe5,0xce,0x0f,0x21,0x2b,0x39,0x15,0x5d,0x8a,0xc0,0x61,0xb4,0xc6,0xa8,0x20,0xdf,0x5d,0xeb,0xca,0x35,0x97,0x16,0x7d,0xba,0xce,0x3e,0x99,0xb2,0x00,0x00, - 0x05,0x20,0x89,0x83,0x0d,0xfa,0x58,0x48,0x06,0xcd,0x12,0xfa,0x31,0x66,0x2f,0x5f,0x33,0x45,0x44,0xa8,0xc3,0x22,0x4c,0xb2,0xb0,0x6d,0x20,0x15,0x8a,0xee,0x9e,0x14,0x9e,0x60,0x00,0x00, - 0x05,0x20,0x8a,0x33,0x44,0x61,0xe9,0x29,0xe8,0xa9,0xec,0x30,0x69,0x26,0xf7,0xb8,0x14,0x75,0x68,0x08,0x43,0xa4,0xf2,0x72,0x61,0xfe,0x66,0xc6,0xb9,0x98,0xd8,0x1a,0xc0,0xef,0x00,0x00, - 0x05,0x20,0x8a,0x8e,0x1d,0xf3,0xdb,0x0c,0xea,0x57,0x66,0xd3,0x06,0xfe,0x89,0xad,0x53,0xdf,0xd1,0x86,0x89,0xea,0xc8,0x15,0xab,0x9d,0xc4,0xe2,0x8d,0xf9,0xc0,0x05,0x84,0x50,0x00,0x00, - 0x05,0x20,0x8a,0xf8,0x1d,0xc7,0xa7,0xed,0xdc,0x37,0x7d,0x48,0xb7,0x1b,0x85,0x0f,0x91,0x3b,0x85,0xc4,0xef,0xea,0xba,0x33,0x9c,0x07,0xd4,0x51,0x84,0xe6,0x60,0x5a,0x84,0x70,0x00,0x00, - 0x05,0x20,0x8b,0x64,0x93,0x22,0x20,0x7f,0x56,0x53,0xdd,0xe1,0xd5,0xc5,0x9a,0x02,0xc6,0x76,0x66,0x1e,0x3e,0x66,0x1d,0xa7,0xd8,0x88,0x3a,0x0e,0x7f,0xaa,0x9e,0x60,0x46,0x93,0x00,0x00, - 0x05,0x20,0x8c,0x59,0xa7,0x91,0x92,0xe6,0xba,0x1a,0x1d,0xcd,0x7c,0xdf,0xf5,0x86,0x61,0x7c,0x59,0x6b,0x24,0xe1,0x2c,0xc9,0x8e,0x51,0x35,0x56,0xba,0xd1,0x2e,0xff,0x89,0x23,0x00,0x00, - 0x05,0x20,0x8d,0x53,0x9b,0x81,0x5b,0x4d,0x6d,0x69,0xa3,0xea,0x59,0x43,0xee,0x5a,0x32,0x62,0xca,0x29,0x78,0x44,0x44,0x0f,0x90,0x85,0x89,0xc3,0x5c,0xa6,0xf6,0x79,0xd9,0x0d,0x00,0x00, - 0x05,0x20,0x8d,0x8c,0x5d,0x59,0x3a,0xbf,0xbd,0x79,0xb5,0x37,0xd8,0xcc,0x6b,0x9d,0x54,0xc7,0x8d,0x54,0x1e,0xb4,0x8f,0x35,0x30,0xa9,0xc4,0x4f,0x82,0x3f,0xa2,0x8a,0x74,0x11,0x00,0x00, - 0x05,0x20,0x8d,0xc1,0x31,0x70,0x3f,0x70,0x4c,0xe9,0x57,0x2d,0x7c,0x22,0xcc,0x45,0x7e,0x9e,0x35,0x84,0x5c,0xe8,0xfc,0x5e,0x13,0xf3,0xb2,0x73,0xe1,0x6c,0x99,0x78,0x43,0x0c,0x00,0x00, - 0x05,0x20,0x8e,0x36,0x8a,0x00,0x01,0x2f,0x48,0xaf,0xed,0xd3,0x2d,0x44,0x7b,0x46,0x11,0xc1,0x33,0xb6,0xc8,0xd0,0xef,0xc2,0xf6,0x65,0x58,0xcd,0x19,0x03,0x94,0x27,0x34,0xc1,0x00,0x00, - 0x05,0x20,0x8e,0x1f,0x2c,0x41,0xc3,0xd6,0x21,0xbc,0x80,0xc2,0xad,0x45,0xaf,0x73,0x75,0xc0,0xe7,0x5e,0x65,0x9a,0x25,0xbb,0x1d,0xdb,0xaa,0x4e,0x71,0x0d,0x49,0xb5,0xcd,0x74,0x00,0x00, - 0x05,0x20,0x96,0xfa,0x75,0xb5,0x94,0x62,0x8c,0x39,0x55,0x3a,0x31,0x1e,0xdb,0x45,0xdc,0xb3,0xb4,0x7f,0xce,0x5f,0x18,0xd2,0x73,0xa0,0xf0,0x31,0xb1,0x66,0xfe,0x02,0xc3,0x34,0x00,0x00, - 0x05,0x20,0x96,0xe2,0x12,0x75,0xbf,0x5e,0x31,0xe9,0x30,0x91,0x7a,0x8d,0x1e,0x20,0x53,0xc8,0x6a,0xa1,0x22,0x9f,0x35,0xf0,0x9f,0x66,0x16,0xdd,0xf1,0x6f,0x6a,0x2c,0x45,0x4e,0x00,0x00, - 0x05,0x20,0x97,0x37,0x6e,0x4e,0x4c,0xcb,0x06,0x3a,0xd3,0x42,0xbd,0x0c,0x7d,0x2e,0xfc,0x77,0x59,0x47,0xee,0x2a,0xaa,0x4e,0xce,0x77,0xb4,0xd4,0x20,0xf3,0x70,0x30,0x59,0xf1,0x00,0x00, - 0x05,0x20,0x97,0x20,0xb5,0xe3,0x88,0xb6,0x49,0x52,0x25,0x5c,0x25,0xfb,0x92,0xc0,0xe1,0xe4,0xfd,0xef,0x3b,0xfb,0x65,0x46,0xcc,0x70,0xcf,0xa7,0x3f,0x37,0x87,0xff,0xeb,0x52,0x00,0x00, - 0x05,0x20,0x97,0x57,0x2e,0x6a,0xb9,0x28,0x21,0x93,0x45,0x31,0xf0,0xaa,0x65,0x30,0xc8,0x29,0x11,0xa8,0xce,0xa9,0xfd,0x32,0x05,0xa5,0x4f,0x93,0x27,0xed,0x26,0xd3,0x65,0x6f,0x00,0x00, - 0x05,0x20,0x97,0xa8,0xc2,0xe6,0xc4,0xd7,0xef,0xf0,0x67,0x58,0x4c,0x8d,0x02,0xcd,0x39,0x05,0x9c,0x9e,0xae,0x22,0x89,0xae,0xb1,0xa8,0xb6,0x2c,0x35,0x0b,0x38,0x2c,0x5e,0x98,0x00,0x00, - 0x05,0x20,0x97,0xab,0x21,0x87,0x1a,0x5a,0x00,0x03,0xb7,0x45,0x3f,0xe1,0x58,0x90,0xf0,0x2d,0x25,0xf3,0x03,0x3b,0x7e,0xe9,0xb8,0xbd,0x33,0x2a,0x4e,0xce,0x00,0xf5,0xcf,0x3d,0x00,0x00, - 0x05,0x20,0x90,0x36,0xad,0x5d,0x0f,0x0d,0x2c,0xcf,0x68,0x21,0xeb,0x74,0xcb,0x02,0x18,0xc2,0x45,0x5b,0xe4,0x3d,0xda,0x99,0x94,0x35,0xce,0x49,0x9a,0x97,0xb6,0x14,0x8e,0x49,0x00,0x00, - 0x05,0x20,0x90,0x06,0xd5,0xe4,0xd4,0x00,0x38,0xaf,0x2a,0xaf,0x42,0xb1,0xaf,0xa3,0x2f,0xdf,0x89,0x1d,0xa3,0xa7,0xff,0x17,0xce,0xe9,0xee,0xa8,0x5a,0x04,0xc2,0x8b,0x5b,0xc4,0x00,0x00, - 0x05,0x20,0x90,0x13,0xda,0x08,0xe9,0xf8,0xf2,0xcb,0xa6,0xbb,0x50,0xf2,0x05,0x9a,0x61,0x86,0x6d,0xeb,0x53,0x96,0xcd,0xee,0x34,0x38,0x22,0xd6,0xd9,0xce,0xe8,0x87,0x56,0xf3,0x00,0x00, - 0x05,0x20,0x90,0x40,0xb7,0xe8,0x6e,0xbe,0x08,0x39,0xc7,0xba,0x52,0x7b,0xfa,0x83,0x51,0x60,0x51,0xd6,0xbe,0x4f,0xaf,0x07,0x15,0x72,0xb7,0x6d,0x12,0x03,0x7f,0x46,0x9b,0xd1,0x00,0x00, - 0x05,0x20,0x90,0xee,0x5c,0x84,0xd6,0xbb,0xcb,0xe3,0x85,0x0a,0xfa,0xb8,0x18,0x33,0xdb,0xb3,0x39,0x75,0x8f,0xf0,0x33,0xb6,0x74,0xac,0xea,0x6b,0x48,0x7c,0xdf,0x18,0x25,0x3a,0x00,0x00, - 0x05,0x20,0x91,0xfa,0x7b,0x5b,0x9a,0xad,0x97,0x25,0xf7,0xe2,0x1c,0x5c,0xf0,0x12,0x0c,0x65,0x9d,0x94,0x35,0xb1,0xd4,0xcd,0xeb,0x43,0x8f,0x89,0xbb,0x68,0xaa,0x92,0xad,0xd2,0x00,0x00, - 0x05,0x20,0x91,0xde,0x3d,0x89,0x05,0x12,0x5c,0x40,0xdb,0xcf,0x92,0x93,0xc7,0x95,0x91,0x67,0xd7,0x62,0x0a,0x38,0x32,0x5a,0x92,0x77,0xa7,0x23,0xa2,0x79,0x5d,0x9a,0x5b,0x63,0x00,0x00, - 0x05,0x20,0x92,0x3b,0x7d,0x95,0xcd,0xd9,0x2d,0xee,0x70,0xb1,0x42,0x06,0x2e,0xbb,0x72,0xc4,0x4b,0xda,0xf9,0x4a,0xe3,0xef,0x74,0xd4,0xe8,0x09,0x2b,0xb7,0x0e,0xea,0xfb,0x71,0x00,0x00, - 0x05,0x20,0x92,0x14,0xa6,0x46,0xf5,0xf5,0x81,0x3d,0x7b,0xb1,0x78,0x31,0xa9,0xab,0xe9,0xc5,0xb1,0x55,0xe5,0x44,0x53,0xdc,0xb6,0x5b,0x0f,0xd1,0x17,0xd3,0x7d,0x08,0x3c,0xab,0x00,0x00, - 0x05,0x20,0x92,0x5f,0x0c,0x17,0x71,0x87,0xdc,0x91,0x01,0x6b,0x1a,0xf0,0x1a,0xe3,0x07,0xea,0xe0,0x88,0x75,0x3b,0x00,0xc9,0xdb,0x7a,0x77,0x26,0xf9,0xfd,0xe0,0x27,0x56,0xe4,0x00,0x00, - 0x05,0x20,0x92,0xbe,0x04,0x55,0x44,0x1f,0x7d,0xb3,0x78,0xda,0x8a,0x35,0x20,0x18,0xcd,0x47,0xd3,0x0c,0xdd,0x94,0x15,0x20,0x0f,0x5d,0x54,0x18,0x8c,0x9a,0xbc,0x29,0x96,0x06,0x00,0x00, - 0x05,0x20,0x92,0xc2,0x19,0x22,0x1a,0x7b,0x1d,0x48,0x1e,0x7b,0x3e,0x5a,0x02,0xb5,0xd6,0x87,0xe5,0x7c,0xad,0x03,0x65,0x8c,0x72,0x88,0xff,0x42,0x21,0xee,0x47,0x23,0x3d,0xa2,0x00,0x00, - 0x05,0x20,0x92,0xc9,0xb1,0x04,0x23,0x73,0x3d,0x15,0x34,0x5b,0x1c,0x61,0x30,0x58,0x53,0x7e,0x3d,0xbe,0xa0,0x40,0xe8,0xfa,0x62,0x45,0x29,0x18,0x0e,0x5c,0x31,0x4e,0x57,0x18,0x00,0x00, - 0x05,0x20,0x92,0xda,0xca,0x4c,0x9d,0x77,0x8f,0xad,0xac,0x68,0x66,0xf9,0x68,0xbb,0x99,0x3f,0x20,0x0d,0x3c,0x47,0x6c,0x94,0xc1,0xbc,0x8a,0xd3,0x72,0x2f,0xd3,0xae,0xcf,0xd3,0x00,0x00, - 0x05,0x20,0x93,0x4a,0x86,0xc8,0x2b,0x3f,0x13,0xcb,0x4a,0xba,0x6f,0x54,0xc5,0x16,0xe1,0xac,0x32,0x22,0x23,0x51,0xc1,0x71,0x4e,0x1c,0x90,0xc7,0xa9,0xfd,0xb1,0xd2,0x23,0xfd,0x00,0x00, - 0x05,0x20,0x93,0x65,0x6d,0x92,0xc5,0xfd,0x93,0x3b,0x49,0xe8,0xa2,0x77,0xb3,0xee,0xb3,0xbb,0x70,0x15,0xae,0x91,0xc8,0xac,0xcf,0xd3,0xda,0x45,0x26,0x5e,0xbc,0xee,0x44,0xd5,0x00,0x00, - 0x05,0x20,0x93,0x9c,0xef,0x81,0x2e,0xff,0x00,0x97,0x79,0x9a,0xc3,0x98,0x21,0x79,0x22,0x71,0x46,0x65,0x0d,0xd8,0x48,0x83,0x17,0xaf,0x6d,0xc5,0x6b,0x49,0x47,0xc5,0xb7,0xe6,0x00,0x00, - 0x05,0x20,0x93,0xa2,0xe0,0xdb,0x5a,0x89,0x23,0x13,0xbe,0xfd,0x9f,0xbe,0x97,0x62,0x00,0x46,0xdd,0x4f,0x5e,0x55,0x85,0xc3,0xfb,0x0d,0xcc,0x9b,0x6c,0xd8,0x66,0x6c,0xe4,0x8c,0x00,0x00, - 0x05,0x20,0x93,0xa6,0xfa,0x8a,0x10,0xce,0x59,0x3c,0x79,0x6b,0x43,0x2c,0xba,0xa9,0xb0,0x90,0xc5,0x87,0xb7,0x96,0x93,0x6c,0xaf,0x7f,0xea,0x23,0xf2,0xcc,0x7f,0xd6,0xd1,0xa0,0x00,0x00, - 0x05,0x20,0x93,0xc2,0x1d,0xf1,0x72,0x5a,0xb5,0x35,0x8e,0xd9,0x8f,0x30,0x34,0x68,0x54,0x5a,0xbf,0x2b,0x99,0x7b,0x43,0x03,0xa3,0x1b,0xfc,0xf5,0xc3,0x78,0x40,0x49,0xfd,0x73,0x00,0x00, - 0x05,0x20,0x93,0xe8,0x00,0x6b,0x1e,0x84,0x81,0x8b,0x61,0xea,0x5e,0x7e,0x89,0x88,0x3d,0x52,0xc9,0x27,0x18,0x85,0xd5,0xfd,0xe6,0x70,0xab,0xb4,0xb5,0x1e,0xff,0x90,0x48,0xba,0x00,0x00, - 0x05,0x20,0x94,0x12,0x98,0x62,0x27,0x3f,0x3a,0x97,0x98,0xaf,0xf7,0x90,0x34,0x22,0x26,0x3f,0x44,0xaf,0x97,0x92,0xff,0x88,0x4d,0x2f,0xa1,0x5a,0x38,0xe0,0xc9,0xd3,0xa7,0xf3,0x00,0x00, - 0x05,0x20,0x94,0x12,0xe8,0xca,0x00,0x60,0x70,0x82,0x36,0x8c,0x37,0x60,0xfb,0x6c,0xae,0x2c,0xd4,0xfe,0x72,0xaf,0x90,0xf8,0xbb,0x29,0x66,0x0a,0xf8,0xb0,0x1b,0x8c,0x67,0x8d,0x00,0x00, - 0x05,0x20,0x94,0x23,0xef,0x14,0x87,0xd1,0xb6,0x5f,0x05,0x4d,0x9e,0xa6,0xd5,0xcd,0x8d,0x3c,0x06,0xac,0xba,0x1b,0x49,0xc6,0x00,0x4c,0xb4,0x94,0x8f,0x1a,0xfa,0xba,0xc9,0xd8,0x00,0x00, - 0x05,0x20,0x94,0xd7,0x30,0x49,0x85,0xe0,0x7b,0xc9,0x46,0x29,0x0e,0xd8,0x5f,0x9d,0x33,0x4d,0x59,0x5a,0xb2,0x5a,0xf0,0x67,0x70,0x28,0x42,0x1c,0xd6,0xb3,0x45,0x9a,0x86,0x4d,0x00,0x00, - 0x05,0x20,0x95,0x3e,0x3e,0x05,0x14,0x8a,0x0e,0xac,0x47,0x70,0x21,0x01,0xf6,0x01,0x4a,0xbe,0x50,0xab,0xc7,0xb9,0x47,0x32,0xda,0xc7,0x07,0xd8,0x52,0x49,0x3d,0xef,0x29,0xef,0x00,0x00, - 0x05,0x20,0x95,0x99,0x30,0x3a,0x4f,0xa8,0x28,0xff,0xb0,0x9b,0x1d,0x72,0xbb,0x76,0xee,0x23,0x8e,0x74,0xf3,0x2d,0xec,0x3c,0x03,0x22,0xa8,0x2f,0xd5,0x79,0xc8,0x96,0x24,0x51,0x00,0x00, - 0x05,0x20,0x96,0x0f,0x72,0x1e,0xab,0xf4,0x68,0x15,0xdb,0xca,0xee,0x24,0xcc,0x8a,0x50,0x8e,0x47,0x26,0x8f,0xe4,0x84,0x43,0x60,0x2c,0xaa,0xa9,0xcc,0x51,0x09,0xf4,0xd3,0xa5,0x00,0x00, - 0x05,0x20,0x96,0x14,0x9b,0x6d,0x2d,0x0f,0xdb,0xe0,0xbb,0xbf,0xe5,0x9a,0xf4,0x02,0xe7,0x7e,0x9a,0xce,0x18,0x5e,0x38,0xb8,0x93,0xf2,0xbe,0x9c,0x64,0x17,0x85,0xd8,0x93,0x9c,0x00,0x00, - 0x05,0x20,0x96,0x21,0x7c,0x2f,0xdf,0x0f,0x0e,0x37,0x76,0x9b,0x4c,0xd4,0xac,0xc8,0x01,0x10,0xab,0x34,0x80,0x91,0x7d,0x24,0x77,0x57,0xed,0x88,0xb4,0x5e,0x6a,0xfe,0xf9,0x52,0x00,0x00, - 0x05,0x20,0x9e,0x89,0xce,0xa6,0x5c,0x1b,0x78,0x22,0xcb,0x18,0x25,0x59,0xaf,0x67,0xab,0x9d,0x59,0x4f,0x2c,0xb3,0xbe,0x50,0x94,0x70,0xac,0xdd,0x79,0x5d,0x4f,0x78,0x50,0x1c,0x00,0x00, - 0x05,0x20,0x9e,0xf5,0x01,0x0b,0x53,0x0a,0x4d,0x0b,0xc7,0x03,0x8e,0xa7,0x73,0x33,0x80,0x39,0xce,0x02,0x6f,0x2a,0x53,0x92,0xc3,0x50,0x87,0xb7,0x4d,0x20,0xce,0x23,0xad,0xe4,0x00,0x00, - 0x05,0x20,0x9f,0x37,0x08,0x66,0x97,0xfa,0x15,0xf5,0x29,0x1a,0x8d,0xe6,0x85,0xac,0x46,0x0d,0xe3,0x96,0xd0,0xe9,0x00,0xbf,0x69,0xc0,0xfd,0xd4,0xa0,0xea,0xab,0xa0,0xc6,0xef,0x00,0x00, - 0x05,0x20,0x9f,0x1a,0xe9,0xad,0x03,0xe0,0x48,0x9b,0x67,0x53,0xcd,0x04,0xfa,0x90,0x6d,0x51,0x29,0x25,0x11,0xaf,0x6d,0x3b,0x28,0x08,0x23,0x39,0xf6,0xb8,0x3a,0x88,0x34,0x2e,0x00,0x00, - 0x05,0x20,0x9f,0x44,0x3f,0xc3,0x7e,0x6b,0xbc,0x37,0x5c,0x74,0xa5,0x55,0xd7,0xc8,0x77,0xe7,0xf2,0xbf,0xba,0x92,0x68,0x94,0x93,0x5b,0xe2,0xf6,0x63,0xb7,0x6d,0x44,0xf9,0x4a,0x00,0x00, - 0x05,0x20,0x9f,0xcc,0x16,0x10,0xb2,0x7b,0x70,0xd0,0x13,0x2c,0xad,0xf9,0xce,0x95,0x20,0x7b,0xf5,0xc7,0xa5,0x25,0xfd,0xaf,0xb2,0x55,0xf6,0x5b,0x1c,0xbc,0xe2,0x9b,0xb2,0x3b,0x00,0x00, - 0x05,0x20,0x98,0x1a,0xc3,0xd5,0x4e,0xc0,0xf7,0xd5,0x17,0xc0,0xd3,0x4e,0x9e,0xc5,0x81,0xb3,0xe7,0xb9,0x1c,0x5e,0x99,0xf0,0xf9,0x2c,0x9c,0xeb,0x31,0xdf,0x76,0xce,0x62,0x70,0x00,0x00, - 0x05,0x20,0x98,0x60,0x43,0xb1,0x9b,0x6d,0x28,0x5d,0x49,0xf6,0x92,0x5c,0x18,0x8b,0x87,0x37,0xa9,0x74,0xa3,0x8c,0x19,0x16,0x8a,0x9f,0x16,0xcf,0x03,0xf2,0xf5,0x75,0xf4,0x54,0x00,0x00, - 0x05,0x20,0x98,0x62,0x91,0x66,0xcb,0xff,0xab,0xf7,0x07,0xc7,0x73,0x77,0xec,0xf8,0xbb,0xeb,0xa6,0xfa,0xf4,0xdc,0xf7,0xe1,0xbd,0xbc,0xd9,0xc6,0x00,0xa7,0xf7,0x5d,0xb5,0x8b,0x00,0x00, - 0x05,0x20,0x98,0xaf,0xb2,0xce,0x43,0x5e,0xfd,0x45,0x62,0x54,0xa1,0x2d,0x81,0x81,0xe3,0xcd,0x29,0xc0,0x2c,0x96,0xc1,0xb5,0xa9,0x42,0x84,0x46,0xac,0x30,0x70,0x1f,0xe4,0xc2,0x00,0x00, - 0x05,0x20,0x99,0x26,0xe8,0x24,0x06,0x91,0x7e,0x57,0x91,0x20,0x4a,0x2c,0xce,0x45,0xd2,0x84,0x85,0x8e,0x9e,0x90,0x0e,0x7a,0x71,0x40,0xc5,0xa1,0xc1,0xd9,0x8c,0xad,0x5c,0x5b,0x00,0x00, - 0x05,0x20,0x99,0x79,0x37,0x64,0xfd,0xa3,0x64,0x6c,0x65,0xe3,0x93,0x22,0x31,0x3c,0x26,0x22,0xad,0xa0,0x1a,0x9f,0x9b,0xfa,0x9a,0xe0,0x4b,0xc8,0xa5,0xd5,0x26,0x83,0xb5,0x9e,0x00,0x00, - 0x05,0x20,0x99,0x69,0x59,0xa3,0xf8,0x73,0x5b,0xd7,0xa5,0xf3,0xce,0x6a,0xf9,0x1c,0xfa,0xdd,0xf9,0x18,0x26,0xac,0xd5,0x24,0xe5,0xc4,0x2d,0x5d,0x39,0xa5,0x81,0x3c,0x61,0xf1,0x00,0x00, - 0x05,0x20,0x99,0xbc,0x67,0x1f,0x65,0x5e,0x58,0x22,0x47,0xb5,0x71,0x67,0xa6,0x97,0x73,0xa0,0xd9,0xf4,0x2b,0x04,0xce,0xf7,0xcc,0xc7,0x1e,0xf5,0x61,0x76,0x0b,0x88,0x22,0x2e,0x00,0x00, - 0x05,0x20,0x99,0xa7,0xf8,0x8c,0xf8,0xb4,0xd7,0x67,0x07,0x9f,0x2a,0xdf,0xe1,0x0a,0x1f,0x7c,0x62,0x13,0xf1,0x0f,0x6d,0x99,0xbb,0xcb,0x34,0xc2,0xa1,0xf0,0x93,0x4f,0x54,0xb1,0x00,0x00, - 0x05,0x20,0x99,0xf6,0x34,0xf6,0x50,0xb7,0xfa,0xb3,0x03,0x73,0x69,0x4a,0x19,0x62,0xc0,0x4d,0xc0,0x5a,0xfc,0x55,0x58,0x7f,0x22,0x0f,0xd6,0xfc,0x37,0x6d,0xca,0xf4,0x83,0xbc,0x00,0x00, - 0x05,0x20,0x9a,0x75,0x47,0xb0,0x4a,0xe7,0xd0,0xa9,0x94,0xfc,0xab,0x44,0xcc,0x01,0x2d,0x50,0x41,0x38,0x19,0x70,0xce,0x38,0x27,0x40,0x85,0xfd,0x90,0xe7,0x47,0x87,0x0c,0x93,0x00,0x00, - 0x05,0x20,0x9a,0xbd,0xbb,0x87,0x34,0x37,0xc6,0x42,0xf8,0x92,0x45,0x5c,0x5b,0x43,0x47,0xd0,0xbb,0xb0,0x47,0x6e,0x9f,0xcf,0x22,0x64,0x70,0xd8,0x19,0x78,0x40,0x0e,0xc4,0x7a,0x00,0x00, - 0x05,0x20,0x9a,0xb3,0x4c,0x48,0x1c,0x5a,0x80,0x3e,0xec,0x58,0xb0,0x67,0xe9,0x19,0xe2,0x68,0xeb,0x5a,0x8d,0x49,0x20,0x26,0xf5,0x5b,0x05,0xb1,0x1d,0x1b,0xfe,0x25,0x26,0xc2,0x00,0x00, - 0x05,0x20,0x9a,0xf7,0x75,0x29,0xb4,0xa2,0xab,0x84,0x37,0x07,0xac,0xff,0x20,0x67,0x73,0xae,0x75,0xc7,0xcc,0xd8,0x84,0xf3,0x8d,0xa0,0xd8,0x36,0x0a,0x07,0x88,0xba,0x76,0xd7,0x00,0x00, - 0x05,0x20,0x9a,0xfd,0xe0,0xa8,0xae,0x85,0x3c,0x40,0x30,0x80,0x84,0xd7,0x68,0xd4,0xb3,0x9e,0x05,0xeb,0xa7,0x72,0xef,0xf2,0x0d,0x9c,0x7f,0x73,0x1a,0x56,0xa4,0xdb,0x47,0x38,0x00,0x00, - 0x05,0x20,0x9a,0xcb,0x39,0xa8,0x32,0x3c,0x44,0x8b,0xd3,0xc8,0xf4,0xb0,0xd9,0xaf,0xb7,0x4c,0x9c,0x7f,0x32,0x66,0x2b,0xd1,0x7e,0xf1,0x4d,0x01,0xf0,0x4a,0x1d,0x69,0xa7,0x0c,0x00,0x00, - 0x05,0x20,0x9b,0x18,0x96,0x0a,0x36,0x21,0x92,0xa2,0x74,0xb9,0xae,0x8e,0x70,0x6a,0xca,0x44,0xbe,0xbf,0x5c,0x60,0x07,0xca,0xa8,0x6b,0x86,0x27,0x62,0x1a,0xc1,0xf6,0xbe,0x5e,0x00,0x00, - 0x05,0x20,0x9b,0x82,0x32,0x5b,0xdd,0xef,0x05,0xff,0x24,0xf1,0xa2,0xc4,0x3d,0x4a,0x46,0xa9,0x0b,0xf1,0xc7,0x08,0x6a,0x35,0x74,0xdc,0x8c,0xd6,0x69,0x23,0x93,0x7f,0xc0,0xa8,0x00,0x00, - 0x05,0x20,0x9c,0x68,0x2a,0xac,0x16,0x7d,0x0b,0x19,0x65,0x58,0xe6,0x72,0x73,0xde,0x63,0x1b,0x4e,0x87,0x71,0x8d,0x80,0x2d,0x91,0x73,0xed,0xfa,0x90,0xaf,0x23,0x9c,0xe3,0x35,0x00,0x00, - 0x05,0x20,0x9c,0x8b,0x1f,0x66,0xa2,0x34,0x99,0x6d,0x11,0x40,0xbc,0x21,0x35,0x0e,0x2d,0x0a,0x03,0xda,0x21,0xdf,0x59,0x99,0x19,0xb2,0x42,0x8d,0x6c,0x4d,0x0f,0x9e,0x37,0xd3,0x00,0x00, - 0x05,0x20,0x9c,0xa2,0xb0,0xdc,0x18,0x3a,0x0f,0x43,0x47,0xfa,0xde,0x7d,0x15,0x60,0x05,0x32,0xda,0x71,0x63,0x28,0xd6,0x4e,0xe4,0xe6,0x58,0x28,0xd3,0x28,0x29,0x43,0xee,0xc3,0x00,0x00, - 0x05,0x20,0x9d,0x77,0x7e,0x28,0x63,0x0d,0x3f,0xdd,0xcd,0xab,0x31,0xcc,0x7d,0xce,0xee,0x33,0xf5,0xe9,0xaf,0x03,0x9f,0x3f,0x15,0xf6,0x42,0xbf,0xc8,0xeb,0x99,0xae,0x11,0x78,0x00,0x00, - 0x05,0x20,0x9d,0x43,0x49,0xc6,0xbf,0xdd,0xcf,0x68,0x06,0x6e,0x93,0x02,0xfd,0x88,0x92,0x1e,0x05,0xd0,0x86,0x72,0x58,0x31,0xc3,0x26,0x45,0xfc,0x72,0x3b,0xf3,0x33,0x36,0x41,0x00,0x00, - 0x05,0x20,0x9d,0x5d,0x3a,0xf5,0xfb,0x23,0x2f,0x76,0xcd,0x1a,0x0b,0x6b,0x41,0x04,0xb8,0xe4,0xdd,0xf3,0x5d,0xf3,0xb5,0x4f,0xc8,0x65,0xb4,0x3e,0x3d,0xa3,0x98,0xed,0x4d,0x38,0x00,0x00, - 0x05,0x20,0x9d,0xdf,0x1e,0xf9,0x35,0x09,0x76,0xb6,0x40,0xc0,0x76,0x60,0x38,0x64,0xc2,0x51,0x5f,0x43,0x67,0x03,0xe0,0xac,0xf5,0xa9,0x2e,0x74,0xea,0x5d,0x9d,0x5c,0xd2,0x03,0x00,0x00, - 0x05,0x20,0x9e,0x0a,0xa3,0xe7,0xc6,0x33,0xd1,0xa8,0xe1,0x44,0xce,0xeb,0xb4,0xf4,0xbb,0x25,0x5a,0x9b,0x95,0xc0,0xa7,0xea,0x4f,0xb3,0x47,0x20,0x28,0xa8,0x8a,0x08,0xa2,0x38,0x00,0x00, - 0x05,0x20,0x9e,0x2b,0x2a,0x43,0x1b,0xf0,0xaf,0xac,0x54,0xbf,0x49,0xda,0xa1,0xf5,0xc9,0x17,0x74,0x6f,0x56,0xeb,0xd4,0x6d,0xd8,0x48,0xf0,0xb3,0xd5,0xed,0xbe,0x6e,0xa8,0xc6,0x00,0x00, - 0x05,0x20,0x9e,0x7b,0x3b,0x8d,0x0f,0x55,0xc4,0xdc,0x0f,0x22,0x95,0x21,0x6e,0x7e,0x17,0x1d,0x5e,0xe0,0xfb,0x9c,0xa6,0xc5,0x39,0xac,0x31,0x09,0x4d,0xbc,0xbf,0xfd,0xaa,0xff,0x00,0x00, - 0x05,0x20,0x9e,0x68,0x30,0x84,0x53,0xb1,0x03,0xf8,0xbd,0xa5,0xd5,0x65,0x6a,0x5b,0x5e,0x4f,0xb7,0x89,0x43,0x33,0x90,0x67,0xf5,0x95,0xe5,0x4f,0xae,0x0a,0x4e,0x84,0x42,0x97,0x00,0x00, - 0x05,0x20,0xa6,0xa6,0xd8,0xe2,0x41,0x74,0x21,0x64,0xb7,0xfb,0x05,0x8d,0xc3,0x96,0xf3,0x2a,0x4c,0x18,0x00,0x3e,0xac,0x46,0x6c,0x53,0x9b,0x97,0xbf,0xa4,0x8c,0x40,0x69,0xc4,0x00,0x00, - 0x05,0x20,0xa7,0x51,0x7b,0x88,0x7e,0x92,0xeb,0x9b,0xba,0x89,0xee,0xf4,0xd4,0xd2,0x57,0xf9,0x05,0xcb,0x11,0x91,0x2d,0x98,0x6f,0x1a,0xcb,0x9a,0xda,0xa8,0xd2,0x81,0x47,0xb7,0x00,0x00, - 0x05,0x20,0xa7,0xb7,0xde,0x7f,0xf4,0xbc,0x25,0xfc,0xf2,0x95,0xb5,0xf5,0xae,0x53,0xce,0x4b,0x76,0x2d,0x92,0xc2,0x0f,0xbc,0x5d,0xa7,0xf0,0x58,0x73,0x0c,0x46,0x24,0xad,0xd2,0x00,0x00, - 0x05,0x20,0xa7,0xad,0x1b,0x73,0xf8,0x2a,0x47,0x95,0x78,0x1f,0x68,0xbc,0x2f,0x48,0x55,0x2b,0x95,0x6a,0x41,0x95,0xa1,0xee,0x43,0xc2,0xb8,0x64,0x6b,0xf7,0x59,0x00,0x4d,0xd0,0x00,0x00, - 0x05,0x20,0xa7,0xe8,0xa5,0xb6,0xd3,0x38,0x63,0x86,0xc7,0x79,0xd1,0x85,0xbc,0x5c,0xac,0x47,0x70,0xe2,0x32,0x54,0x32,0x42,0x1e,0x35,0x9c,0xe5,0xf5,0xe2,0xeb,0xb5,0xbb,0xfb,0x00,0x00, - 0x05,0x20,0xa7,0xf0,0x66,0xec,0xe4,0x74,0xaf,0x4f,0x2f,0x43,0x41,0x37,0xcc,0x7e,0xd3,0x21,0x2e,0x57,0xf8,0xfa,0xb7,0x53,0xb6,0x9e,0x3c,0xd7,0x30,0xe0,0xaf,0x12,0x41,0xb1,0x00,0x00, - 0x05,0x20,0xa0,0x0d,0x2f,0x1d,0x9e,0xe7,0x8b,0xa8,0x4b,0x10,0x29,0xf2,0x99,0xea,0xeb,0x6a,0x60,0x14,0x39,0xe8,0x70,0xcc,0x7c,0x59,0xd2,0x19,0xb3,0xf0,0xda,0x61,0x31,0xa6,0x00,0x00, - 0x05,0x20,0xa0,0xbb,0xa8,0xe7,0x3c,0xbd,0x3a,0x85,0x5f,0xc7,0x5f,0xa3,0xe9,0x42,0xe5,0x62,0x31,0x8b,0xc8,0xa5,0x78,0xa9,0xd2,0xc6,0x33,0x23,0xc5,0x94,0x0e,0xc9,0xb5,0x0e,0x00,0x00, - 0x05,0x20,0xa0,0xcb,0x73,0xea,0x3d,0xc1,0x69,0xdc,0xff,0x0d,0xc8,0x05,0x48,0xfd,0xfb,0x37,0xe8,0x6d,0xf5,0x45,0x06,0xf6,0x63,0x92,0x5a,0x08,0x32,0xf1,0xa2,0xb7,0x59,0xe5,0x00,0x00, - 0x05,0x20,0xa0,0xd5,0x68,0x0d,0xdd,0x70,0xcd,0xd6,0xbd,0xbd,0xd4,0x68,0x44,0x3c,0xc7,0x6f,0x5c,0xc3,0xd5,0xc9,0x99,0xf2,0x36,0x54,0x55,0xa3,0x98,0x6c,0x99,0x74,0x67,0xca,0x00,0x00, - 0x05,0x20,0xa0,0xf2,0x1b,0xf5,0x38,0xac,0x5f,0xc3,0x6d,0x14,0x4a,0xc4,0x0f,0xa5,0xab,0x00,0x00,0x0e,0xb3,0x64,0xe2,0x6b,0xc9,0x06,0x3f,0x9d,0x5f,0xe5,0x78,0x43,0x48,0xbb,0x00,0x00, - 0x05,0x20,0xa1,0x4c,0xe0,0x03,0xc6,0xff,0x3d,0x9c,0xbd,0xe7,0xa5,0x6f,0x47,0x32,0x88,0xca,0xb0,0x57,0xe7,0x9d,0x11,0xe1,0x30,0x7e,0x4a,0x8e,0x2d,0x08,0x78,0x49,0x0c,0x1a,0x00,0x00, - 0x05,0x20,0xa1,0x51,0x39,0xc5,0x71,0xe1,0x01,0x49,0xbc,0xf4,0x86,0x68,0xe9,0x8b,0xe1,0xdd,0xef,0xaf,0xb7,0x97,0x36,0x3a,0x02,0xb3,0x85,0x70,0xbc,0xd9,0x57,0xbe,0x87,0xd4,0x00,0x00, - 0x05,0x20,0xa1,0xad,0xdc,0x84,0xf2,0xd3,0xeb,0x23,0x5d,0x04,0x52,0xd8,0x2f,0x67,0x99,0xf0,0xfa,0x2a,0xe2,0x97,0xe3,0xc5,0x37,0x97,0x54,0x19,0xd2,0x6b,0xd4,0x09,0x74,0xf4,0x00,0x00, - 0x05,0x20,0xa2,0x4d,0xe0,0xf0,0x58,0xb9,0xd1,0xd7,0x97,0x8f,0xa5,0xab,0x6a,0x3e,0x91,0xda,0x06,0x36,0x6b,0x74,0x40,0x40,0xf4,0x19,0xf6,0x5f,0x03,0x29,0xd5,0x73,0xe0,0xaa,0x00,0x00, - 0x05,0x20,0xa3,0x47,0x9a,0x16,0x49,0x20,0x79,0x05,0x97,0xf8,0xea,0xd6,0x7e,0xfa,0x69,0x47,0xb2,0xb3,0xce,0x47,0x5c,0xb0,0x79,0xf3,0x09,0x1c,0x81,0xa5,0x70,0x18,0xbf,0xeb,0x00,0x00, - 0x05,0x20,0xa3,0x83,0x67,0x3c,0xed,0xcc,0x21,0xcc,0x1d,0xef,0xef,0x00,0x89,0x50,0x7d,0x72,0x4d,0x1b,0xc3,0xcf,0x04,0x99,0x0e,0x02,0x1e,0x85,0xbe,0x33,0x99,0x22,0x74,0x1e,0x00,0x00, - 0x05,0x20,0xa3,0x87,0x81,0x24,0x72,0x13,0xe9,0x15,0x90,0xce,0xd3,0x63,0x2f,0xbe,0x6e,0xc9,0x35,0xe7,0xfb,0x5b,0xf4,0xf5,0x1d,0x4c,0x17,0xed,0x02,0x33,0x23,0xc3,0xa4,0x00,0x00,0x00, - 0x05,0x20,0xa3,0x8f,0x4b,0xb5,0x23,0xd7,0xc4,0x59,0x82,0x21,0x2f,0x94,0x7e,0x0b,0x2c,0x74,0xed,0x59,0x4d,0xee,0x6e,0xa4,0x69,0x6a,0xaf,0x29,0x60,0xa3,0x30,0xdf,0x35,0x2e,0x00,0x00, - 0x05,0x20,0xa3,0xf4,0xaa,0x0e,0xd0,0x73,0x21,0x1b,0x54,0xae,0x33,0x5a,0x7c,0xe9,0x89,0xb4,0x2a,0xa3,0x3d,0x4d,0x2e,0x24,0x27,0xf2,0x84,0xea,0x1c,0x4a,0xee,0x1c,0x48,0xfb,0x00,0x00, - 0x05,0x20,0xa3,0xd8,0x4f,0x8b,0xdc,0x1d,0x92,0x60,0xcf,0xf6,0xfe,0xb0,0x5e,0xe0,0x6b,0xd8,0xf0,0xfd,0x74,0x73,0x23,0x62,0xa8,0x7b,0x3b,0x05,0xbc,0x70,0xa2,0x22,0x86,0x64,0x00,0x00, - 0x05,0x20,0xa3,0xdf,0x77,0x0c,0xbe,0x0e,0x77,0x04,0x06,0xaf,0xce,0x6b,0x32,0x0d,0x7d,0x5a,0xb6,0x7f,0x96,0x4b,0x8d,0x98,0x41,0xe8,0x4c,0x85,0x46,0xf3,0x4e,0xb0,0x55,0x75,0x00,0x00, - 0x05,0x20,0xa4,0x60,0xb8,0xec,0x44,0x47,0xde,0xfd,0x0a,0x34,0x30,0x39,0x3b,0xdd,0x8c,0xa9,0x17,0xb0,0x9f,0xed,0x90,0x61,0x98,0x65,0xe4,0xfb,0x99,0x56,0x05,0x9c,0xaf,0xfa,0x00,0x00, - 0x05,0x20,0xa4,0x8d,0x04,0x26,0x36,0x3c,0xec,0x67,0x11,0x49,0x14,0x75,0xec,0x40,0x46,0x7b,0x45,0x67,0xc8,0x92,0x14,0x63,0xb2,0x11,0x5b,0xe9,0x37,0x13,0xaa,0x33,0x7c,0xdc,0x00,0x00, - 0x05,0x20,0xa5,0x39,0xfa,0x5c,0x70,0x84,0xeb,0xa7,0xc1,0xd1,0x08,0x2e,0xd3,0x9c,0xac,0x14,0xae,0xc5,0x36,0xaf,0x89,0x00,0xc0,0xc2,0x0a,0x74,0xa3,0xce,0x87,0x9c,0x3f,0x50,0x00,0x00, - 0x05,0x20,0xa5,0x79,0xc6,0x25,0xd0,0x8a,0x76,0xcd,0x9b,0x39,0xed,0xae,0xb6,0xcb,0x33,0xeb,0xea,0x65,0x6d,0x10,0x58,0xb6,0xf6,0x40,0xa4,0xf5,0x1b,0xe3,0x5c,0x18,0x96,0x85,0x00,0x00, - 0x05,0x20,0xa6,0x24,0x76,0x79,0xae,0x50,0xd3,0x88,0x6d,0x7c,0xde,0xb5,0xc0,0x4f,0x51,0x41,0x9e,0x0e,0x65,0x88,0xc6,0x03,0x4a,0x17,0x10,0xd6,0xa7,0xc5,0xfb,0xa8,0x02,0xd9,0x00,0x00, - 0x05,0x20,0xa6,0x25,0x51,0xc8,0xfa,0x0e,0x50,0x26,0x0e,0x10,0x1a,0xfe,0x4c,0xd0,0xb3,0xb8,0xb1,0x6c,0x81,0xee,0x38,0x72,0xbe,0x81,0xfd,0x3e,0x10,0x86,0xa9,0x1b,0xef,0x19,0x00,0x00, - 0x05,0x20,0xa6,0x31,0xc1,0x84,0xb8,0xbe,0x91,0xab,0xec,0xce,0x70,0x45,0xea,0x5d,0x3c,0x68,0x7e,0xa9,0xe6,0x54,0xfe,0xb2,0xb5,0x4b,0x0f,0x49,0x51,0x23,0x28,0x1b,0xbb,0x66,0x00,0x00, - 0x05,0x20,0xa6,0x4c,0x56,0x49,0x22,0x0a,0x6e,0x89,0xcf,0xc1,0x20,0xf6,0xfd,0x99,0xe3,0xcd,0x51,0x87,0x3f,0x51,0xce,0xc5,0x78,0x62,0x9e,0xe1,0x05,0xbc,0xea,0x3d,0x43,0x20,0x00,0x00, - 0x05,0x20,0xa8,0x72,0xfe,0x49,0x2a,0x34,0x2d,0x86,0x37,0x59,0xe2,0x14,0x10,0x13,0xf1,0xae,0xc4,0xb0,0xbb,0xf5,0xaf,0x19,0x6a,0xf0,0xb3,0xfc,0xe9,0xfa,0x06,0x2c,0x09,0x0e,0x00,0x00, - 0x05,0x20,0xa8,0x95,0x26,0xe2,0x98,0xb6,0xd1,0xe3,0x96,0xa8,0x70,0x7b,0x8c,0xbb,0x0d,0x87,0xdc,0xab,0xa3,0xdf,0xf8,0x6d,0xfd,0x6b,0x9a,0xfe,0xca,0x93,0xc9,0x5a,0x51,0xa2,0x00,0x00, - 0x05,0x20,0xa8,0xde,0x57,0x00,0xf7,0x91,0x3e,0x24,0x89,0x16,0xea,0xfe,0x52,0x86,0xd9,0x17,0x89,0xcb,0x8d,0x65,0xed,0x17,0x58,0xab,0x7c,0x66,0x59,0xa3,0x63,0x8c,0x3a,0xed,0x00,0x00, - 0x05,0x20,0xa8,0xeb,0xa0,0x22,0x66,0x82,0x04,0x0e,0x4c,0x10,0x13,0x12,0x4b,0xdb,0xb7,0x28,0x62,0x50,0x9e,0xa5,0xea,0xa9,0x7b,0x54,0xa9,0x2e,0xf0,0x85,0x23,0xa0,0xe8,0x93,0x00,0x00, - 0x05,0x20,0xa9,0x27,0xe8,0x5a,0xc0,0xff,0x13,0x18,0x45,0x39,0x13,0x3f,0x85,0x95,0xf1,0xcd,0x9e,0xd9,0xec,0xeb,0xca,0x6a,0xa0,0xb4,0x0e,0x45,0x78,0xed,0x67,0x2a,0x8e,0xe5,0x00,0x00, - 0x05,0x20,0xa9,0x28,0x24,0x1d,0x83,0xff,0x1a,0xda,0x31,0x14,0x6d,0x63,0x4c,0x26,0x5e,0x53,0xd3,0x2e,0xca,0x16,0xe8,0xdf,0x15,0x8d,0x79,0x11,0x7e,0x8d,0x9f,0x88,0x32,0x86,0x00,0x00, - 0x05,0x20,0xa9,0x2c,0x38,0xa2,0x4c,0xcd,0x9a,0xbb,0xae,0xad,0x47,0xe4,0xb7,0xc3,0xfa,0xd5,0x97,0x62,0x81,0x88,0xd1,0x16,0x63,0xd0,0x6c,0xd3,0x8a,0x24,0x9d,0xe9,0x14,0xbc,0x00,0x00, - 0x05,0x20,0xa9,0x76,0xbd,0x97,0xb4,0x6a,0xed,0x12,0xb2,0x3b,0x2a,0x1e,0x77,0xb9,0x86,0x92,0xee,0x66,0x79,0x9c,0x11,0xcd,0xfd,0x22,0x65,0xe7,0x70,0x5a,0x6c,0x31,0x66,0x35,0x00,0x00, - 0x05,0x20,0xa9,0x5f,0x90,0x4a,0x32,0x8c,0x0f,0xb5,0xad,0x54,0x1b,0x01,0x2e,0x97,0x0c,0xb3,0x74,0xe3,0xca,0xd0,0x46,0xea,0x05,0x09,0x66,0x67,0x8a,0xde,0x34,0x3e,0x97,0x6f,0x00,0x00, - 0x05,0x20,0xa9,0x94,0xea,0x73,0x12,0xa5,0xea,0x75,0xde,0x36,0x2f,0x5b,0xa4,0x1d,0xbc,0x29,0x71,0x5a,0x90,0x6b,0xa5,0x1b,0xcf,0xaf,0xc3,0x70,0x51,0xdc,0x0b,0x28,0xc6,0xdb,0x00,0x00, - 0x05,0x20,0xa9,0xa9,0xe5,0xae,0x01,0xc2,0x5e,0x76,0x2f,0x5d,0xa3,0x07,0xdc,0xce,0xb8,0xbc,0x6f,0x47,0xaf,0x3a,0x37,0xf8,0x5c,0x86,0xff,0xe9,0xb6,0xa5,0x00,0x93,0x76,0x11,0x00,0x00, - 0x05,0x20,0xaa,0x7b,0xc1,0xe9,0xea,0x19,0x21,0x51,0x51,0x3d,0xc2,0x88,0x63,0x47,0xc9,0x69,0xce,0xd6,0x43,0xb0,0xf4,0x09,0xf6,0xce,0x75,0x0f,0xb0,0x92,0x4e,0xc4,0x00,0xd8,0x00,0x00, - 0x05,0x20,0xaa,0xec,0xea,0xa7,0xc5,0xbe,0x6b,0x39,0x61,0xed,0x64,0x96,0xe1,0x39,0xd3,0x63,0xce,0x4c,0xc7,0xb3,0xb8,0x1b,0x82,0xe7,0x46,0x49,0xdb,0xd5,0x81,0xb1,0x6e,0x8a,0x00,0x00, - 0x05,0x20,0xab,0x01,0x37,0x86,0x9a,0xa9,0x7a,0xff,0xf9,0x5a,0x23,0x32,0x6d,0x4d,0x38,0x82,0x3c,0xff,0x61,0x3b,0x12,0xf9,0x9d,0xe9,0xa2,0x19,0xf3,0xbf,0xd0,0x2f,0x8a,0x8e,0x00,0x00, - 0x05,0x20,0xab,0x03,0x89,0xce,0xe5,0xf4,0xad,0xe4,0x54,0x60,0x61,0x67,0x7a,0x34,0xdc,0xe3,0x15,0x38,0x07,0x95,0x79,0xd8,0xce,0x2e,0x19,0x1c,0x20,0xf1,0x31,0x52,0x99,0x23,0x00,0x00, - 0x05,0x20,0xab,0x1c,0xe3,0x0c,0x7d,0x5e,0x67,0x3e,0xd9,0xf9,0x55,0x8e,0x3f,0x7e,0x96,0x6d,0x5f,0x47,0xe0,0x9f,0xc0,0xa4,0x1c,0xf7,0xa9,0x5e,0xbb,0x2a,0x11,0xd6,0x15,0xef,0x00,0x00, - 0x05,0x20,0xab,0x7b,0x19,0x47,0x5e,0x8b,0xff,0x8b,0xc6,0x0b,0x44,0x3f,0x57,0x73,0x21,0xf0,0x1c,0x81,0x1c,0x18,0x08,0xf7,0x48,0xd4,0x5d,0x21,0x06,0x09,0x3e,0xe9,0x7e,0xd6,0x00,0x00, - 0x05,0x20,0xab,0x6e,0x96,0x65,0xc6,0x02,0x85,0xa0,0x72,0xed,0xed,0xb9,0x07,0x45,0x88,0x84,0xfa,0xa3,0xb5,0x2f,0x9b,0x5c,0x08,0xbb,0xfc,0x21,0xd0,0xd8,0xd7,0x90,0xde,0x0c,0x00,0x00, - 0x05,0x20,0xab,0x91,0xda,0x6c,0x19,0x38,0x12,0xd9,0xff,0x9f,0xf4,0xc4,0x85,0x2f,0xac,0x00,0xa7,0x71,0x56,0x72,0x0b,0x63,0x94,0x5e,0xca,0x4f,0xb5,0x03,0xbc,0x16,0xed,0x13,0x00,0x00, - 0x05,0x20,0xab,0xc9,0x5b,0xfa,0x6b,0xf3,0x01,0xe6,0x35,0x69,0xe6,0x87,0xc2,0xa8,0x9d,0xf9,0x1b,0xca,0xf6,0x3f,0xf6,0x2f,0xe8,0x89,0x87,0x9d,0x6d,0xcf,0x9a,0x8e,0xdf,0x29,0x00,0x00, - 0x05,0x20,0xab,0xd8,0xa1,0x4e,0x07,0x50,0xe0,0x65,0x11,0x53,0xfe,0xa5,0x18,0x33,0x92,0x80,0x16,0x8a,0x1b,0x7f,0xa4,0x35,0x67,0xeb,0x16,0x00,0xf1,0xb7,0xeb,0x7d,0x13,0xc1,0x00,0x00, - 0x05,0x20,0xab,0xe7,0x97,0xdc,0x20,0xfb,0xb1,0x2d,0xdb,0x47,0x9a,0x4c,0x7e,0x52,0xee,0x30,0x08,0x3a,0x46,0x43,0x3e,0xb1,0x9e,0xab,0xc4,0xfe,0x0f,0xc0,0xed,0xee,0x55,0x1a,0x00,0x00, - 0x05,0x20,0xac,0xbd,0xf9,0x27,0xa2,0x8a,0x84,0x97,0x7d,0x9f,0xe4,0xc7,0x46,0xe4,0x85,0x4f,0x80,0x73,0x44,0xce,0x3c,0xbc,0x43,0x27,0xa9,0xbb,0x1a,0x49,0x66,0xc0,0x73,0xbe,0x00,0x00, - 0x05,0x20,0xad,0x20,0xaf,0xf9,0x35,0xb9,0x55,0xde,0x85,0x4e,0xac,0x04,0xc6,0x2a,0xb8,0x13,0x1a,0x32,0x13,0xe9,0xdc,0xe9,0x5f,0x93,0x23,0x0e,0xa4,0xb8,0x95,0xe9,0xc5,0x5c,0x00,0x00, - 0x05,0x20,0xad,0xdc,0xa3,0xa9,0x03,0x24,0xd2,0xfe,0x4d,0x31,0x4f,0xd0,0x37,0x26,0xfc,0xe9,0xcd,0x43,0xb5,0x7a,0x06,0x6b,0x06,0x86,0x8b,0x75,0x0d,0x51,0xaa,0x53,0x2e,0xd8,0x00,0x00, - 0x05,0x20,0xad,0xe5,0xa2,0x4b,0xc5,0xfd,0x2d,0xaa,0x51,0xa4,0x92,0xc3,0xf4,0x3e,0xac,0x37,0x95,0x03,0xfb,0x13,0x7a,0x49,0x97,0x27,0x4f,0x9d,0xaf,0xf7,0x0f,0x89,0x83,0x2e,0x00,0x00, - 0x05,0x20,0xae,0x51,0x8d,0x08,0x31,0x0d,0x56,0x88,0x3d,0x1a,0xf9,0x48,0x05,0x68,0xe8,0x25,0x9d,0x5b,0xcd,0x6a,0x83,0xdf,0x20,0x1a,0x60,0xb9,0x10,0x1f,0x35,0x4e,0x6a,0x9b,0x00,0x00, - 0x05,0x20,0xae,0x60,0xeb,0x28,0x7c,0x03,0xb0,0x45,0x01,0xe2,0x92,0xb0,0xb5,0xa3,0xff,0x02,0x76,0x4e,0x95,0xcc,0x45,0xe4,0x9c,0x20,0x16,0x6a,0xc7,0x94,0xf8,0x5d,0x6d,0xe7,0x00,0x00, - 0x05,0x20,0xb6,0x81,0xfd,0xb1,0xdc,0x34,0x46,0x6b,0x55,0x59,0x1c,0x8f,0xe6,0xe2,0x93,0x01,0x87,0xc0,0xb3,0x16,0xc5,0x80,0x2b,0xd5,0x0e,0x1d,0xbf,0x76,0xb8,0xbf,0xd0,0x1c,0x00,0x00, - 0x05,0x20,0xb6,0x98,0x60,0x64,0x1f,0xe8,0x19,0x1a,0x95,0xc2,0x5f,0xed,0x3f,0x57,0xe4,0x43,0x1f,0x15,0x82,0x54,0x4e,0xc2,0x8e,0x5c,0x99,0x1c,0x75,0x6c,0x40,0xea,0xbe,0x6d,0x00,0x00, - 0x05,0x20,0xb6,0xb2,0x8d,0xdd,0xd2,0xe2,0x41,0x9d,0x96,0x7d,0xc0,0x81,0xab,0xf7,0x25,0xdf,0x09,0x21,0x4d,0xec,0xcc,0x17,0x07,0x8e,0x30,0x6c,0xd2,0xc4,0x69,0xdb,0x31,0x42,0x00,0x00, - 0x05,0x20,0xb6,0xcf,0x88,0x35,0x74,0x20,0x79,0x8a,0xf5,0x6a,0xca,0x77,0x65,0xb6,0x29,0x7f,0xcb,0x97,0xdd,0xa8,0x37,0xaf,0xe6,0x6e,0xdd,0x1d,0x34,0xf9,0x95,0x22,0x66,0x93,0x00,0x00, - 0x05,0x20,0xb7,0x01,0x1c,0x28,0x55,0x17,0xc8,0x25,0x66,0x90,0x8f,0xd5,0x59,0x69,0xa9,0x92,0x5e,0xa6,0xe4,0x3e,0xad,0x64,0xe1,0xbf,0x19,0x7f,0xa7,0x5a,0x6b,0xe1,0xcb,0x94,0x00,0x00, - 0x05,0x20,0xb7,0x15,0xc3,0x33,0x62,0x3a,0x31,0x25,0x17,0x32,0x3a,0x17,0x74,0x88,0xef,0x34,0xdf,0x7d,0x5d,0x82,0xf1,0x29,0x55,0x63,0x2a,0xc2,0x6b,0x9a,0x8c,0x30,0x8b,0x98,0x00,0x00, - 0x05,0x20,0xb7,0x7b,0x1e,0x61,0x59,0xa7,0xa1,0x3f,0x50,0xef,0xde,0xc9,0x78,0x06,0x0c,0x5c,0xf7,0xdf,0x8a,0x72,0xd5,0x35,0x97,0x23,0xe7,0x55,0x1e,0x78,0x32,0xbd,0x45,0x1e,0x00,0x00, - 0x05,0x20,0xb7,0x92,0xbd,0x1a,0x81,0xc4,0x84,0x37,0xd0,0x28,0xc9,0x25,0xd0,0xbf,0xd2,0xe6,0x84,0x89,0xbb,0x8a,0xd7,0xef,0x61,0x26,0xc7,0xff,0xa3,0x5a,0x21,0x5a,0x7c,0x4e,0x00,0x00, - 0x05,0x20,0xb0,0x04,0x52,0x59,0x1e,0x21,0xd8,0x5b,0xd4,0xb3,0xbc,0x19,0x10,0x08,0xa7,0xfc,0x89,0xa9,0xfd,0xd9,0x5f,0xb5,0x4e,0x1e,0x54,0xc0,0xf8,0x2e,0xdc,0xb9,0xa0,0x13,0x00,0x00, - 0x05,0x20,0xb1,0x10,0x37,0xd6,0x47,0x43,0x47,0xb1,0xb4,0x2b,0xb4,0xc3,0xcc,0xbe,0x52,0x06,0x48,0x46,0xa8,0xbf,0x07,0xb6,0x50,0x54,0x15,0x50,0xb8,0x28,0x9e,0x03,0x57,0xfc,0x00,0x00, - 0x05,0x20,0xb1,0xa2,0x13,0xc0,0x8c,0x99,0x7f,0x0a,0x70,0x5e,0x00,0x92,0x81,0x07,0xf4,0xc1,0x09,0xe8,0xad,0x0d,0x01,0x71,0x89,0x56,0xe2,0xd6,0x1c,0x28,0x72,0x7a,0x42,0xc4,0x00,0x00, - 0x05,0x20,0xb2,0x4b,0x45,0x5b,0x0e,0x3a,0xd2,0x0b,0x9a,0xbc,0xb3,0x89,0x61,0xcd,0xee,0xba,0x37,0x0f,0x1d,0xb6,0x13,0x48,0x57,0x9a,0x33,0x41,0x74,0xa8,0x16,0x37,0x92,0xdb,0x00,0x00, - 0x05,0x20,0xb2,0xc8,0xf4,0x97,0x8b,0xbc,0xb8,0x4e,0xf7,0x71,0x9b,0xdd,0x89,0x79,0x50,0x7e,0x9d,0x91,0x57,0x8f,0x82,0x6d,0x97,0x60,0x20,0xb0,0x97,0xbc,0x9e,0x23,0xae,0x74,0x00,0x00, - 0x05,0x20,0xb3,0x17,0x8f,0x0b,0x3d,0x4f,0x79,0x6d,0x1b,0x46,0x40,0x5a,0x75,0xbe,0xb4,0x39,0xf6,0x15,0x63,0x5e,0x14,0x36,0x0e,0xa7,0x1e,0x1b,0xf4,0x73,0x6c,0xe2,0xdf,0x1d,0x00,0x00, - 0x05,0x20,0xb3,0x5f,0xaf,0x37,0x0f,0x3c,0x0a,0xc8,0x6e,0x83,0x70,0x8c,0x2b,0x11,0xaf,0x91,0x8b,0x65,0x72,0x52,0xb7,0x77,0x29,0xf2,0xd5,0xb4,0xfc,0xcb,0x17,0xf6,0x66,0xfb,0x00,0x00, - 0x05,0x20,0xb3,0x80,0xd0,0x49,0x0b,0xad,0xa9,0xbc,0x16,0x91,0xa9,0xeb,0x04,0xed,0x77,0x1e,0xba,0x1c,0xa7,0x85,0xbd,0xb1,0xb2,0x17,0x70,0x48,0x64,0xed,0x89,0xd9,0xae,0x04,0x00,0x00, - 0x05,0x20,0xb3,0xda,0x4b,0x39,0x64,0xf9,0x5c,0x5a,0xda,0xb1,0xaa,0x94,0x62,0xf3,0xb2,0x30,0xaa,0x48,0xad,0xc3,0x70,0xa9,0xf2,0xca,0x6c,0xd0,0x2e,0xfe,0xa4,0xb8,0x54,0x41,0x00,0x00, - 0x05,0x20,0xb4,0x61,0x4e,0xf3,0x72,0x95,0x03,0xf5,0x22,0xd9,0x2d,0x0d,0xc7,0x7d,0x9e,0x58,0xba,0x80,0xb0,0x00,0x60,0xc5,0xb7,0x72,0x8e,0xf0,0x3e,0xd9,0xdd,0x10,0xc8,0xf9,0x00,0x00, - 0x05,0x20,0xb4,0x82,0x5e,0xcd,0xee,0xf9,0x05,0x20,0x16,0x92,0x2a,0xf1,0x86,0x7f,0x4a,0xf4,0xc3,0x81,0x2c,0xd5,0x80,0x2b,0xdf,0x40,0x05,0xae,0x05,0xc4,0xee,0x4f,0xc8,0xdd,0x00,0x00, - 0x05,0x20,0xb4,0xca,0x40,0x86,0xcc,0x95,0xdd,0x8b,0x53,0xcd,0xb7,0x44,0xeb,0x2e,0xf0,0x3c,0xdc,0xab,0xc6,0xe5,0x9d,0x49,0xac,0x90,0x9e,0x2a,0xeb,0x17,0xc0,0xdc,0x4f,0x98,0x00,0x00, - 0x05,0x20,0xb4,0xdc,0x7e,0xd7,0xf7,0x66,0xed,0x7e,0x46,0x14,0x98,0x71,0x58,0x01,0x17,0xc0,0x6c,0xb7,0xc6,0xfd,0xa0,0x35,0x84,0x57,0x46,0x00,0xb6,0xf8,0xc5,0x00,0xe9,0x19,0x00,0x00, - 0x05,0x20,0xb5,0x10,0xa2,0xd9,0x44,0xbc,0xfc,0xb0,0xaf,0xd4,0x89,0xdd,0x89,0x47,0x40,0x08,0xb0,0x52,0xf5,0x6a,0x66,0x9c,0x98,0xf9,0x85,0x23,0x61,0x0d,0x75,0xb9,0x5a,0xe9,0x00,0x00, - 0x05,0x20,0xb5,0x18,0x9b,0x3e,0x3c,0xed,0x0f,0x59,0x98,0xd0,0xf2,0x55,0x92,0x8c,0x1c,0xf9,0x38,0x88,0x2b,0x4e,0x6a,0x33,0x6f,0x55,0xbd,0x7b,0xb6,0x11,0xee,0x90,0x10,0xe9,0x00,0x00, - 0x05,0x20,0xb5,0x77,0xbe,0xd5,0x51,0xfe,0xcd,0x20,0x64,0x1c,0x9f,0x8a,0xe8,0x61,0xed,0x75,0x44,0x2a,0x06,0xb6,0x2c,0x81,0x15,0x32,0xdb,0xbc,0xc5,0xb9,0xee,0x4d,0x13,0x30,0x00,0x00, - 0x05,0x20,0xb5,0x55,0x31,0x3f,0xe7,0xc7,0x17,0xe4,0x31,0x87,0x47,0x45,0x7c,0x67,0x43,0x5c,0x82,0x73,0xd6,0x62,0x64,0x94,0x92,0x32,0x2d,0x81,0x0e,0x01,0x35,0xc0,0x7e,0xb7,0x00,0x00, - 0x05,0x20,0xb5,0x82,0xe4,0xe2,0xcd,0x88,0x8b,0xa6,0x09,0x1f,0x2e,0xf2,0x60,0xb9,0x91,0xa2,0x84,0xce,0x0f,0x6d,0xaf,0x9f,0x39,0x87,0x63,0x71,0xd2,0xf3,0x13,0x52,0xce,0xbe,0x00,0x00, - 0x05,0x20,0xb5,0x83,0x6f,0xb6,0x11,0xd8,0x0e,0xa8,0x57,0xda,0x15,0x20,0x5b,0x1a,0x6d,0x21,0x15,0x5a,0xbd,0xb4,0x17,0x11,0xc2,0xfb,0x0e,0xfc,0xde,0xe8,0x26,0x56,0xa8,0xac,0x00,0x00, - 0x05,0x20,0xb5,0xcb,0x2d,0x08,0x40,0x8f,0x25,0x91,0xfb,0xc3,0x5b,0x16,0x84,0x9f,0x68,0xdc,0x78,0xca,0x10,0xf0,0x4d,0xd2,0xc0,0x06,0xc1,0x0f,0x3c,0x28,0x6c,0xcf,0x0c,0x9c,0x00,0x00, - 0x05,0x20,0xb6,0x35,0x41,0xa9,0x66,0xc0,0xcf,0xf4,0x29,0xad,0x29,0x43,0x9a,0xac,0x6e,0x45,0xa4,0x29,0xf8,0x78,0xdb,0xbe,0x54,0x8a,0x49,0x10,0xd2,0xe8,0x70,0x3e,0xed,0x4e,0x00,0x00, - 0x05,0x20,0xb6,0x68,0x8f,0x48,0x5f,0xf7,0xbf,0x6f,0x80,0x01,0x97,0x90,0x40,0xa0,0x97,0xe7,0xdd,0xf1,0x62,0x57,0x7c,0x70,0x51,0x81,0x73,0x02,0x97,0x6d,0x67,0x57,0x34,0xe9,0x00,0x00, - 0x05,0x20,0xb6,0x6a,0xa4,0x77,0x5b,0xe1,0x4b,0x03,0xc5,0x1a,0xf1,0x60,0xeb,0xba,0x50,0x86,0xee,0x46,0x99,0x7a,0xd9,0x1c,0x89,0xaa,0xa8,0x7f,0x18,0xff,0x81,0x0f,0x76,0xd7,0x00,0x00, - 0x05,0x20,0xbf,0x04,0x49,0xd0,0x11,0x0d,0x91,0x07,0x9c,0x81,0x44,0xea,0x6a,0xf2,0xfc,0x56,0x4f,0xec,0x1f,0x18,0xad,0x3a,0x2e,0x61,0x2b,0x67,0x13,0x2c,0x2f,0x81,0xac,0xbb,0x00,0x00, - 0x05,0x20,0xbf,0x61,0x33,0x63,0x39,0x32,0x9d,0x57,0x29,0xde,0xd2,0xfc,0xde,0xf1,0xfd,0xed,0xd8,0x0e,0xbc,0x32,0x98,0x5f,0xe9,0xfa,0xe2,0xf1,0xc3,0x43,0x5f,0x3d,0x12,0xb4,0x00,0x00, - 0x05,0x20,0xb8,0x24,0x4b,0x3d,0x10,0x7e,0x4f,0x83,0x1a,0xf6,0x90,0x12,0xc6,0xaa,0x2f,0x7a,0x34,0xec,0xb0,0x0f,0x85,0x7d,0xef,0xef,0x34,0xa6,0x18,0xea,0x12,0x1e,0xfc,0xd6,0x00,0x00, - 0x05,0x20,0xb8,0x49,0x3c,0x06,0x5b,0x6e,0x09,0x85,0x49,0x40,0x93,0x96,0xf0,0x4d,0x3c,0x84,0x4a,0xd4,0x1b,0x3f,0x06,0x83,0x7f,0xd8,0x52,0xc4,0x5a,0x88,0x0f,0x74,0x93,0x41,0x00,0x00, - 0x05,0x20,0xb8,0xf4,0x1c,0x1e,0x3a,0xd4,0x60,0xa0,0x59,0xc2,0x03,0xc3,0x72,0x0d,0xd5,0x62,0x0b,0x85,0x7f,0xf0,0x89,0xfc,0x18,0xf0,0x53,0xbf,0xdb,0x8d,0x78,0xef,0x65,0x25,0x00,0x00, - 0x05,0x20,0xb8,0xdc,0xe6,0xbe,0xcd,0xb9,0xe3,0xf9,0x25,0xd8,0x10,0x36,0xb5,0x42,0x40,0x7b,0x08,0x51,0xe9,0xf4,0xc0,0x23,0xad,0x66,0x6e,0x13,0x87,0xc1,0xc5,0x29,0xa7,0x8b,0x00,0x00, - 0x05,0x20,0xb8,0xe1,0xa3,0x72,0x6a,0x05,0x15,0x91,0x53,0xcc,0x6d,0x47,0x45,0x08,0xe8,0x6b,0x01,0xf5,0x39,0x1e,0x16,0xda,0xe2,0xad,0xe9,0x00,0x63,0x94,0xc4,0xc4,0xa3,0x0a,0x00,0x00, - 0x05,0x20,0xb9,0x0c,0x27,0x1c,0xb1,0x6b,0x5b,0x4c,0xec,0xe3,0x60,0x7f,0x1e,0x13,0xcf,0xcd,0xc2,0xc9,0x9b,0x9e,0xf3,0x7c,0xc9,0xe3,0x4e,0xce,0xe6,0x27,0x42,0x93,0xba,0x7f,0x00,0x00, - 0x05,0x20,0xb9,0x71,0x92,0xd0,0xce,0xdc,0x26,0x57,0xc3,0x72,0xee,0x44,0x20,0x86,0x11,0xb9,0x54,0x6c,0x6e,0x73,0x5c,0x0f,0x9f,0x4f,0xce,0xab,0x26,0x68,0xca,0x98,0x11,0x3f,0x00,0x00, - 0x05,0x20,0xb9,0x83,0x9e,0xd5,0xe4,0x57,0xaa,0x02,0x11,0x3a,0xc9,0x13,0x78,0xa5,0x6e,0x81,0xb5,0x28,0x07,0xdf,0x32,0x19,0xfd,0x42,0x0f,0x70,0xe0,0x58,0x7b,0x51,0x2a,0xeb,0x00,0x00, - 0x05,0x20,0xb9,0xa1,0x9b,0xd0,0x6a,0xa9,0x83,0x0b,0x3a,0x40,0x38,0x3f,0x90,0xeb,0xc9,0x36,0x41,0xdb,0x07,0xec,0xf7,0xbf,0xaf,0xc5,0x5c,0xae,0xb2,0x9f,0xea,0xe6,0x36,0x90,0x00,0x00, - 0x05,0x20,0xb9,0xa4,0xad,0x1e,0x90,0x31,0xd0,0x59,0xe3,0x2d,0x8f,0x96,0xb8,0xfb,0x33,0x23,0xdd,0xdd,0x6c,0xe8,0xb4,0x24,0x2b,0xa5,0xe0,0xb0,0x82,0xc2,0x7e,0xf3,0x4c,0x66,0x00,0x00, - 0x05,0x20,0xba,0x48,0x1c,0x20,0x18,0x1c,0x82,0x1f,0xf8,0xd0,0xc9,0x27,0x26,0x08,0x46,0x3f,0xbe,0xe2,0x02,0xf3,0xd8,0xb8,0xc5,0x59,0x93,0xf9,0x92,0xb2,0xe1,0x9a,0xf7,0x88,0x00,0x00, - 0x05,0x20,0xba,0xcb,0x7a,0x48,0xcd,0xcb,0xd8,0x09,0xd2,0x60,0x89,0x06,0x2a,0xdf,0x5f,0xcb,0x90,0x41,0x35,0xdc,0x9b,0xee,0xce,0xe9,0x28,0x10,0xea,0xde,0x4a,0x3d,0x1e,0x30,0x00,0x00, - 0x05,0x20,0xbb,0x3b,0xdb,0x34,0xa7,0x33,0x25,0x8e,0x5b,0x3a,0xe4,0xac,0x99,0x6b,0x28,0x35,0x0e,0x4a,0x4f,0xd8,0xfe,0x94,0x79,0xf3,0x13,0xb6,0x0a,0x36,0x26,0x57,0x92,0xdb,0x00,0x00, - 0x05,0x20,0xbb,0x43,0xb7,0xde,0x6c,0x02,0x3c,0xe2,0x84,0x11,0xc0,0x84,0xbb,0x5a,0x84,0x00,0x22,0xde,0x47,0x79,0x9e,0xf2,0x65,0x10,0x8f,0x77,0x1e,0x66,0x4a,0xd0,0xa9,0x45,0x00,0x00, - 0x05,0x20,0xbb,0x6b,0x23,0x05,0xcd,0x5a,0x41,0xf1,0x30,0x8e,0x54,0x74,0xc9,0x54,0x64,0x5c,0x16,0x09,0x05,0x56,0x34,0x1a,0x38,0x1b,0xe4,0x02,0xad,0xcd,0xcf,0x6c,0xe7,0xbb,0x00,0x00, - 0x05,0x20,0xbb,0xe1,0x40,0xcb,0x85,0x9d,0x3f,0x86,0x72,0xf6,0x8a,0x22,0xbc,0xe8,0x9b,0xf1,0xab,0x84,0xa9,0x0b,0xd8,0x8f,0x58,0x7f,0x81,0x4f,0x16,0x5f,0x8d,0x22,0x8d,0xb9,0x00,0x00, - 0x05,0x20,0xbc,0x63,0x7d,0x44,0x4f,0x4e,0xf2,0x42,0xc8,0xf3,0x9f,0xd4,0x06,0x67,0x74,0x2a,0xdb,0x62,0x05,0xf5,0xd1,0x94,0x61,0xfa,0xab,0x88,0xc1,0x9b,0x99,0x6d,0xef,0xcd,0x00,0x00, - 0x05,0x20,0xbc,0x6d,0x48,0x61,0x62,0x32,0xa3,0xa7,0x56,0x45,0xe3,0xf2,0x87,0x48,0x7a,0xfe,0x2c,0x3f,0xbc,0xa0,0x71,0xdb,0x12,0x3b,0x19,0x67,0xf5,0x05,0xb6,0xae,0x54,0xe3,0x00,0x00, - 0x05,0x20,0xbc,0xee,0x7e,0x5a,0x6c,0x0a,0x57,0x2f,0xfa,0xd7,0x69,0x0e,0x4e,0xfc,0x93,0xa0,0x69,0x0a,0xc8,0x68,0xa3,0x6c,0x6a,0x93,0xca,0xb2,0x67,0xc0,0x0a,0xd2,0xb3,0x53,0x00,0x00, - 0x05,0x20,0xbd,0x07,0xc2,0x99,0x84,0x87,0x0e,0xbe,0x08,0xd2,0x0a,0x5b,0xba,0x07,0x3a,0x46,0x12,0x6a,0x38,0xd2,0x53,0x7f,0x68,0x90,0x92,0xab,0xe4,0xcd,0xa0,0x3a,0xfa,0x9e,0x00,0x00, - 0x05,0x20,0xbd,0x11,0x5a,0xb5,0xe2,0x4e,0xa2,0x79,0x5d,0x8a,0xc6,0x13,0x96,0x62,0x1e,0x07,0xcd,0x63,0x52,0x4d,0x85,0x86,0xa5,0x99,0x0c,0x03,0x2a,0xac,0xd3,0xf1,0x6b,0x59,0x00,0x00, - 0x05,0x20,0xbd,0x5f,0x90,0x40,0xb3,0x59,0x6f,0xa2,0x4e,0x18,0x97,0xf7,0xb6,0x34,0x6c,0xfa,0x63,0xb5,0xe9,0x3b,0x41,0x77,0x69,0x28,0xab,0x4e,0x40,0xeb,0x76,0x5c,0x8c,0x4b,0x00,0x00, - 0x05,0x20,0xbd,0x67,0x56,0x00,0x8b,0x27,0xdb,0x2f,0xeb,0xac,0x48,0x1d,0x69,0x01,0x2f,0xbf,0x02,0x62,0x90,0x41,0xa4,0x70,0x7f,0x3e,0x0c,0x1b,0x5b,0xbf,0x8a,0x1f,0x14,0xb5,0x00,0x00, - 0x05,0x20,0xbd,0xbc,0x15,0x93,0x9a,0x4d,0x2c,0xa2,0xc5,0x24,0x98,0x76,0x76,0x2b,0x44,0x7f,0x92,0xdc,0x50,0xa7,0xa4,0xdc,0x46,0xe2,0x2e,0xa7,0x90,0x47,0x41,0x0e,0x65,0xb9,0x00,0x00, - 0x05,0x20,0xbd,0x96,0xa7,0xd0,0x2a,0xac,0x87,0x2c,0x00,0x98,0x5c,0x0a,0xcb,0x95,0x5c,0xda,0x68,0xaf,0x4b,0x3b,0x3d,0xda,0xcb,0x13,0x99,0x23,0x44,0x98,0x7f,0xe0,0xcb,0x48,0x00,0x00, - 0x05,0x20,0xbe,0x07,0x98,0x46,0xc6,0x34,0x94,0x30,0xb0,0x90,0x89,0xcd,0x3f,0x01,0x71,0x71,0x97,0x90,0xa8,0x40,0x8e,0x46,0xb3,0x80,0x2c,0xac,0x65,0x96,0x76,0x9e,0x11,0x69,0x00,0x00, - 0x05,0x20,0xbe,0x0e,0xb2,0x32,0x0c,0x71,0x29,0x28,0x04,0x39,0x8f,0x1d,0x07,0x9f,0xca,0x33,0x2a,0xcd,0x83,0x6b,0x88,0x68,0x06,0xdd,0x4c,0xc1,0x27,0x67,0x1e,0xee,0xc3,0x5a,0x00,0x00, - 0x05,0x20,0xc6,0xfd,0xd5,0x97,0x75,0x59,0xfd,0x53,0x72,0x32,0xf4,0xe2,0xd4,0x8b,0x88,0x06,0xaf,0x07,0xac,0x07,0x56,0xbd,0x8d,0xcf,0x10,0x4a,0xf1,0xa8,0x6a,0xaf,0x2b,0x60,0x00,0x00, - 0x05,0x20,0xc6,0xc9,0x0a,0x6a,0x62,0xf6,0x65,0x78,0x4d,0xa3,0xa1,0xa4,0x5c,0xba,0x73,0xa1,0x1a,0x53,0x5d,0xab,0xf9,0x20,0x60,0x0d,0x8d,0xca,0x54,0xe4,0x1a,0xf5,0x91,0x14,0x00,0x00, - 0x05,0x20,0xc6,0xdc,0x21,0x2f,0xb1,0x80,0xb4,0xcc,0xfb,0x84,0x95,0x3a,0xc8,0x65,0xd8,0x2e,0x56,0x1b,0xb9,0xff,0x9c,0xe6,0x5d,0x07,0x66,0xc5,0xd3,0x49,0x4f,0xbf,0x9d,0xcb,0x00,0x00, - 0x05,0x20,0xc7,0x3b,0x73,0xc1,0x41,0xe6,0xda,0x27,0x28,0xb6,0x3c,0x99,0x1e,0x67,0xc5,0xb6,0x15,0x44,0x4f,0xce,0xdb,0xf4,0xa0,0xc9,0xdb,0x23,0x2b,0xf9,0x4d,0xe8,0xb5,0x9d,0x00,0x00, - 0x05,0x20,0xc7,0x1a,0x96,0x78,0xb3,0x1b,0x7b,0xed,0x43,0xb3,0x3e,0x47,0xb2,0xd4,0x3a,0x2f,0x58,0x14,0x78,0x26,0x5b,0x31,0x47,0xd1,0x42,0x60,0x9f,0x3d,0x4e,0x8e,0xf4,0x97,0x00,0x00, - 0x05,0x20,0xc7,0x6d,0x1d,0x06,0xdb,0x8c,0xf9,0x1a,0xdb,0xe7,0x84,0x13,0xf8,0x4d,0x65,0xfd,0x46,0x39,0x7b,0x2a,0xf0,0xa5,0xb6,0x53,0x6c,0xc6,0x07,0x40,0x49,0x04,0x83,0x94,0x00,0x00, - 0x05,0x20,0xc0,0x52,0x6c,0x2d,0xa7,0xaa,0xb6,0x5c,0xe0,0x02,0xbd,0x70,0x7f,0x0e,0xd5,0x89,0xfe,0xb5,0x6b,0xfb,0x81,0xfb,0x0b,0x4b,0xf4,0x85,0x2b,0x13,0x9e,0xd1,0xf4,0x54,0x00,0x00, - 0x05,0x20,0xc0,0xb9,0x7b,0x21,0xbd,0xa2,0x48,0xda,0x8a,0x3e,0xc3,0x6c,0xac,0xfd,0x6d,0x63,0x21,0xb6,0xb3,0x37,0xa9,0x4d,0x42,0x2c,0x9e,0x75,0x61,0x07,0xdc,0xc9,0xab,0x9b,0x00,0x00, - 0x05,0x20,0xc1,0x19,0x15,0x62,0x0c,0x4e,0x6d,0x66,0xeb,0x00,0x94,0xf4,0x60,0x78,0x62,0x6c,0x9d,0x56,0xde,0xc8,0x7e,0xa2,0x97,0xa0,0x7d,0xf1,0xa2,0x33,0x7d,0x13,0xa1,0x9e,0x00,0x00, - 0x05,0x20,0xc1,0x5e,0xb4,0xfb,0xf7,0xb0,0x82,0xb0,0xa2,0x9c,0x76,0x46,0x36,0x65,0x6c,0x4a,0xf8,0x82,0x83,0xe1,0x3a,0xb3,0x9a,0x78,0xb4,0xf2,0x54,0xec,0x42,0x88,0xf5,0x7d,0x00,0x00, - 0x05,0x20,0xc1,0xa6,0x2e,0xb3,0x8c,0x3e,0xe0,0x74,0x7e,0x62,0x9f,0x38,0x6b,0xc0,0x24,0x69,0xd4,0x09,0x3f,0x58,0xe6,0x06,0x96,0xf6,0x14,0x07,0x17,0xda,0x9f,0x7d,0x74,0x87,0x00,0x00, - 0x05,0x20,0xc2,0x77,0x5d,0xb8,0x46,0x58,0xda,0x01,0x2a,0xef,0x9c,0x92,0xcb,0x02,0x40,0xe5,0xf3,0x74,0xed,0x13,0xf4,0x67,0x43,0xb1,0x6f,0xbd,0x6c,0xb8,0x75,0x4c,0xc6,0x27,0x00,0x00, - 0x05,0x20,0xc2,0xb5,0x28,0xa8,0x6b,0x0b,0x3e,0xa2,0x06,0xbd,0xd8,0xef,0xce,0xca,0x5f,0x86,0x8a,0x91,0x63,0xbe,0x66,0xcd,0x8b,0x42,0xb6,0xf7,0x49,0x80,0x7c,0x4e,0xf9,0xcd,0x00,0x00, - 0x05,0x20,0xc2,0x9e,0xf4,0xb2,0xd4,0x6e,0x61,0x9a,0x52,0x02,0xf4,0x21,0x24,0x25,0xcc,0x2e,0x46,0x64,0x10,0x90,0xd3,0x14,0x81,0x81,0xe2,0xe0,0x2d,0x1b,0x5b,0x4d,0x43,0x43,0x00,0x00, - 0x05,0x20,0xc2,0xab,0xed,0x45,0x15,0x5d,0xe9,0x18,0x6a,0xca,0x20,0x80,0x6c,0xcb,0xfe,0x9d,0x16,0x57,0x47,0xfe,0xe8,0xb5,0xbf,0x86,0x49,0x6f,0xd3,0x3e,0x73,0x7e,0x53,0x75,0x00,0x00, - 0x05,0x20,0xc2,0xd7,0x58,0x2b,0x54,0x9a,0x19,0x74,0xcd,0xd8,0xca,0xbe,0xbd,0x72,0x5c,0x6f,0x65,0x07,0xf4,0x61,0x6f,0x6b,0x69,0x06,0x7b,0x36,0xc6,0x3f,0x1f,0x83,0xbc,0x89,0x00,0x00, - 0x05,0x20,0xc2,0xdf,0x82,0x8a,0x5a,0xe2,0x13,0xef,0x8d,0x4b,0xfa,0x0c,0x7c,0x3a,0x9c,0xce,0x8c,0xf2,0x9d,0x2b,0x9e,0x90,0x45,0xad,0x3a,0x00,0xf8,0x31,0xc6,0xe2,0x47,0xb6,0x00,0x00, - 0x05,0x20,0xc3,0x1d,0xa1,0x35,0x63,0x64,0xa7,0x98,0x2e,0x43,0x3d,0xfe,0xaa,0x45,0x08,0xf8,0x00,0x52,0xc4,0xef,0x30,0x0b,0x75,0xad,0x1b,0x97,0x3e,0xfc,0x84,0xa4,0xe9,0x2b,0x00,0x00, - 0x05,0x20,0xc3,0x71,0xec,0xc2,0x61,0xfc,0x2a,0x4f,0xda,0xc5,0x14,0xe4,0xec,0x9f,0x27,0x0c,0x38,0x7c,0x22,0x6b,0x80,0x9d,0xca,0x1c,0x5d,0x86,0xe3,0x54,0x92,0xff,0xfb,0x81,0x00,0x00, - 0x05,0x20,0xc3,0x72,0x73,0xdd,0x68,0x22,0x0d,0x36,0x27,0xcb,0xf9,0x74,0x38,0x77,0x98,0x7b,0x64,0x02,0xff,0x5b,0x05,0x3e,0xed,0xd0,0xed,0x44,0x98,0xb3,0x35,0x4c,0x14,0x13,0x00,0x00, - 0x05,0x20,0xc3,0x8b,0xcc,0x56,0xbc,0x01,0xac,0x72,0xb1,0x02,0x4f,0x69,0xa1,0xc4,0x8c,0xe7,0xdb,0x52,0xa9,0x07,0x6b,0xfc,0x14,0x2f,0xee,0x11,0xbd,0xd3,0x60,0x78,0xce,0x45,0x00,0x00, - 0x05,0x20,0xc3,0x93,0x4c,0x47,0x10,0xf5,0x4a,0xec,0x69,0x85,0x9c,0x46,0xcc,0x05,0x90,0xd1,0xd2,0x42,0xd3,0x31,0xb3,0x1f,0x08,0x16,0xaa,0xd2,0x87,0xd3,0xbe,0x66,0x8e,0xe0,0x00,0x00, - 0x05,0x20,0xc3,0xc3,0x0e,0x81,0x64,0x74,0x20,0xeb,0xcd,0xdc,0x9a,0xae,0xb6,0x2e,0xe7,0xd1,0xe3,0x29,0xa6,0xf9,0x79,0x9c,0xd4,0xed,0x6a,0xf8,0xf3,0x62,0x00,0xf2,0xd9,0xcf,0x00,0x00, - 0x05,0x20,0xc4,0x17,0xa5,0x73,0x29,0x5f,0xb8,0x39,0xe0,0x34,0x15,0x16,0x93,0x1b,0x95,0xe5,0x3d,0x24,0x93,0x92,0x63,0x70,0x0c,0x6e,0xb2,0x5d,0x7e,0x88,0xc5,0x06,0xcd,0xd4,0x00,0x00, - 0x05,0x20,0xc4,0xb7,0xe8,0xce,0x84,0x19,0xb9,0xc9,0x00,0xe4,0x58,0x71,0x28,0x23,0x4c,0x08,0xb4,0xbd,0xc4,0x45,0x1e,0x37,0xbc,0x8e,0xa7,0xa9,0x55,0x7e,0xd1,0xc2,0x00,0x82,0x00,0x00, - 0x05,0x20,0xc4,0xbe,0xd7,0xed,0xec,0x29,0xd1,0x88,0x6f,0x3a,0x88,0x9c,0x4c,0x2c,0x3f,0x01,0x8a,0x1c,0x16,0x87,0x3b,0xfe,0xac,0x6a,0x99,0xad,0x69,0x99,0x58,0x03,0xf0,0x90,0x00,0x00, - 0x05,0x20,0xc5,0x20,0x1e,0xf4,0x71,0xcc,0x4f,0x72,0xb6,0xae,0x0e,0x05,0x78,0x02,0x9c,0xfa,0x90,0x10,0x00,0xbc,0xab,0x80,0xc5,0x6d,0x57,0x5f,0xff,0x70,0x87,0x9a,0xba,0xa0,0x00,0x00, - 0x05,0x20,0xc5,0x8a,0x0a,0x02,0x80,0x22,0x83,0x1b,0x9a,0xc0,0x01,0xc4,0x9c,0xa0,0xa4,0x66,0x47,0x0d,0x7a,0xf2,0x91,0xed,0xde,0x48,0xdc,0x0b,0xe3,0xdc,0xff,0x92,0x15,0x91,0x00,0x00, - 0x05,0x20,0xc5,0x9f,0x23,0x53,0xcd,0x5b,0x4b,0xa5,0xf2,0x58,0xe7,0x26,0x89,0xe8,0x15,0xf9,0xcb,0x9b,0x5a,0x73,0x0a,0x6b,0x60,0xce,0x41,0x9c,0x29,0x1d,0x82,0xc8,0x05,0xf4,0x00,0x00, - 0x05,0x20,0xce,0xf8,0xfb,0x76,0x6b,0x75,0xac,0x8d,0x99,0xe9,0xde,0x04,0x1d,0x0d,0xf3,0x36,0x29,0x0f,0x74,0x2f,0x4f,0xed,0xbf,0x5c,0x07,0x92,0xcc,0x85,0x18,0xce,0xe9,0x00,0x00,0x00, - 0x05,0x20,0xce,0xd3,0xab,0xc8,0xeb,0xe4,0xde,0x1b,0x83,0x01,0x13,0xe2,0x7c,0xc3,0xe2,0xa6,0x7d,0x48,0x85,0xd0,0x75,0xeb,0x57,0xb4,0xb1,0x45,0x78,0xdd,0x2e,0x1f,0xd2,0x65,0x00,0x00, - 0x05,0x20,0xce,0xde,0x6c,0x15,0x16,0x2e,0x44,0x3d,0x1b,0xf5,0xe4,0x65,0xe2,0x2f,0xb3,0xa8,0xbb,0xdc,0x7c,0x1b,0x98,0x11,0xc3,0x08,0x2f,0x93,0xbc,0x55,0x80,0x89,0x12,0x88,0x00,0x00, - 0x05,0x20,0xcf,0x98,0xbc,0x46,0xe2,0x48,0xc6,0xf1,0x01,0xd4,0x65,0xdb,0x6e,0xbc,0x94,0x5b,0x55,0x54,0xf7,0xc7,0x35,0xa0,0xc6,0x8b,0xa0,0x1b,0xa9,0x37,0xfd,0xe8,0xa2,0x40,0x00,0x00, - 0x05,0x20,0xcf,0xaf,0x29,0x4f,0x10,0xe6,0x70,0xdc,0xd4,0x06,0xb5,0x77,0x68,0xfc,0xf3,0xcf,0x2b,0x79,0xce,0x2e,0x9e,0x43,0xd4,0x64,0x85,0x74,0xd7,0x68,0x33,0xea,0x4c,0xe8,0x00,0x00, - 0x05,0x20,0xcf,0xc4,0x9b,0xbf,0x1c,0x98,0x28,0x8d,0x28,0x1b,0x22,0x8b,0x09,0xba,0x8c,0x90,0x7e,0xf3,0x6a,0x4e,0x56,0xec,0x52,0x63,0x6c,0xd4,0x5c,0x4a,0x3d,0xe2,0x8e,0x4f,0x00,0x00, - 0x05,0x20,0xcf,0xc4,0x9c,0x95,0x95,0xf5,0x80,0x34,0x9a,0x99,0x00,0x2b,0x4f,0xbc,0xb2,0x81,0xe8,0x90,0x8b,0x32,0x78,0x4b,0xd9,0x5e,0xf1,0x83,0x46,0x47,0x56,0x9b,0x5c,0xf6,0x00,0x00, - 0x05,0x20,0xcf,0xcc,0xa2,0x48,0x2a,0x0a,0xf5,0xf5,0xbc,0x4f,0x0b,0x4e,0x62,0xb8,0xa9,0xcf,0x4a,0x76,0xd5,0x69,0xc9,0x6b,0x8c,0x0e,0x9f,0x56,0x36,0xe1,0xe4,0x70,0x97,0x17,0x00,0x00, - 0x05,0x20,0xc8,0x0a,0x3e,0x74,0x5a,0x3e,0x47,0xcb,0x6a,0x7a,0xe4,0x26,0x98,0x40,0x30,0x66,0xf3,0xc3,0x83,0x01,0xf5,0x40,0x34,0xfa,0x43,0xeb,0xa8,0xa4,0xe1,0x09,0xd0,0x22,0x00,0x00, - 0x05,0x20,0xc8,0x55,0x01,0x42,0x68,0x45,0xb8,0xdb,0x48,0x72,0xeb,0xd2,0x45,0xf8,0x0b,0x8f,0x51,0xc3,0x99,0x18,0x81,0x7a,0x64,0x5a,0x91,0x1e,0x0c,0x5c,0x48,0x02,0x8d,0x34,0x00,0x00, - 0x05,0x20,0xc8,0x73,0xfd,0x68,0x67,0xfc,0x6b,0x4f,0x50,0xc3,0xc0,0xd8,0xb6,0x4c,0xc5,0xc0,0xbf,0x16,0xbc,0x92,0x58,0x09,0xdd,0x74,0x5f,0x61,0xe3,0xf8,0x9a,0x44,0x52,0x42,0x00,0x00, - 0x05,0x20,0xc8,0xac,0x68,0x5b,0xe7,0x5d,0xbf,0xcd,0xfc,0x1f,0x05,0x3c,0xdf,0x38,0x2b,0x48,0xc3,0xc0,0x45,0xb2,0x3b,0x90,0x11,0xc1,0xde,0xab,0xa2,0x42,0x72,0xe8,0xcb,0x5d,0x00,0x00, - 0x05,0x20,0xc8,0xf8,0xd9,0x73,0x22,0xc5,0x4c,0xfb,0x29,0x0e,0x2c,0xd0,0x82,0xcc,0xc9,0xff,0x1b,0xe6,0x17,0x8c,0xe2,0x09,0x0f,0x00,0x83,0x80,0x32,0xd6,0x0d,0x1e,0x89,0xc7,0x00,0x00, - 0x05,0x20,0xc9,0xad,0x22,0x12,0x37,0xb4,0x1a,0x81,0xef,0x27,0x15,0x17,0x9a,0x40,0x2a,0x39,0x8f,0x33,0xc8,0x35,0x90,0x5b,0x07,0x5a,0x24,0x1b,0xa5,0x32,0xc1,0x75,0x05,0xa5,0x00,0x00, - 0x05,0x20,0xca,0x08,0x7a,0x5c,0x6f,0xc1,0xba,0x3a,0xd5,0xb9,0x20,0xd8,0x28,0x5e,0x59,0x18,0x8a,0xb9,0x46,0xfe,0x2c,0x18,0x6c,0x87,0xee,0x19,0x0b,0x0b,0x40,0x17,0x8c,0xbf,0x00,0x00, - 0x05,0x20,0xca,0xb5,0x1f,0xab,0x39,0x41,0xb3,0x4e,0xab,0x3e,0xfd,0xdb,0x10,0x93,0xbe,0xa7,0x6c,0x05,0xb4,0xd8,0x58,0xa4,0xaf,0xf7,0xc1,0x53,0x27,0xef,0x09,0x84,0x26,0x07,0x00,0x00, - 0x05,0x20,0xca,0x82,0x93,0x15,0xfc,0x75,0x1c,0x25,0x3e,0x4c,0x78,0x47,0x85,0xa3,0x88,0x5b,0xbe,0x5d,0xac,0x25,0x4c,0x82,0xe0,0x63,0x6d,0x2f,0x3f,0x86,0x22,0x3a,0x58,0xe3,0x00,0x00, - 0x05,0x20,0xca,0x91,0xe3,0x81,0x64,0x95,0x14,0x72,0x91,0x7f,0xf3,0xf2,0x8a,0x4c,0xc8,0x10,0x39,0x98,0xbf,0xb0,0x98,0x58,0xb6,0x1b,0x10,0x2f,0x86,0xd6,0xb9,0x8a,0xf9,0xd2,0x00,0x00, - 0x05,0x20,0xca,0x90,0x9e,0x7f,0x60,0xa3,0x18,0xff,0x46,0xb6,0xaa,0x3f,0x60,0xc7,0xa8,0x43,0xbd,0x7a,0x6a,0x87,0xe4,0x5c,0xf3,0x84,0xf8,0x74,0xf7,0xfa,0x5c,0xf1,0xc1,0x91,0x00,0x00, - 0x05,0x20,0xcb,0xeb,0x08,0x0e,0x22,0x68,0x0c,0x01,0xf4,0x18,0xa4,0xcb,0xf3,0xa9,0xfe,0x7c,0x67,0x58,0x85,0x8a,0x69,0xe0,0x3a,0x2f,0x70,0xb1,0x0b,0x3f,0xb8,0x1d,0x42,0xb3,0x00,0x00, - 0x05,0x20,0xcc,0x0b,0x3f,0x8b,0xd1,0x45,0x7e,0x0a,0x5f,0xda,0x85,0x89,0xdb,0x96,0x0a,0x46,0xc6,0x20,0xf2,0x91,0xa8,0x4b,0x8f,0x33,0x96,0xcf,0xcb,0xcf,0x27,0x54,0x96,0xd6,0x00,0x00, - 0x05,0x20,0xcc,0x0e,0xe8,0x18,0xbb,0x23,0x53,0xa7,0xd7,0xfc,0x92,0x5d,0x5f,0x0e,0x67,0x7c,0x7c,0x98,0x00,0xb6,0xec,0x21,0x9c,0xca,0xad,0x28,0xe1,0x9c,0x0b,0x02,0x3d,0xdf,0x00,0x00, - 0x05,0x20,0xcc,0x62,0xa4,0x77,0x8c,0x6f,0x7c,0x5c,0x4d,0x19,0x51,0x58,0x7b,0xfc,0x94,0x09,0x01,0xbf,0xbc,0x03,0xb8,0x37,0x95,0xa2,0xd0,0xf1,0xa6,0xa6,0xc6,0x57,0xae,0x80,0x00,0x00, - 0x05,0x20,0xcc,0x8a,0xf1,0x34,0x2a,0xe1,0xb4,0x1b,0x5d,0x7f,0xc6,0x3a,0x40,0xc4,0x55,0x5d,0xc7,0xd3,0x3c,0x57,0x04,0xc9,0x61,0xc4,0xcf,0x41,0x89,0xf7,0x43,0x0a,0xa3,0x6d,0x00,0x00, - 0x05,0x20,0xcc,0xb3,0x0f,0x91,0xa0,0xb8,0x73,0xd7,0xec,0xbb,0x40,0xce,0x55,0x28,0x7a,0xa6,0xb0,0x67,0x92,0x16,0x4e,0xdd,0xe3,0xa9,0xc5,0x29,0x44,0xc5,0xad,0xb8,0x65,0xa0,0x00,0x00, - 0x05,0x20,0xcc,0xe3,0xb1,0x7e,0x19,0xf5,0x78,0x78,0xb4,0x86,0x62,0xb2,0x99,0x47,0xba,0xb6,0x11,0xca,0x78,0x91,0xc7,0x19,0xfe,0x49,0x5b,0x67,0xfe,0xea,0x3f,0x56,0x97,0x14,0x00,0x00, - 0x05,0x20,0xcc,0xf1,0x70,0xa4,0x04,0xfd,0x04,0x5c,0x51,0xf7,0x7e,0x3f,0xd4,0xd9,0xf9,0x1a,0xa6,0x6e,0x18,0x35,0x3a,0xf9,0xb6,0x9f,0x42,0x8d,0xa1,0x1b,0xea,0x87,0xa9,0x06,0x00,0x00, - 0x05,0x20,0xcd,0x00,0xc4,0xfb,0x60,0x1f,0xf6,0x96,0x36,0xdf,0xbb,0x6f,0x16,0x26,0x41,0x49,0xbf,0x53,0x6b,0x69,0xe7,0xad,0xb6,0x3c,0x5a,0xa0,0xde,0x23,0x24,0xaa,0x14,0x05,0x00,0x00, - 0x05,0x20,0xcd,0x44,0x75,0xc5,0x34,0xcc,0x06,0xbb,0xef,0xe5,0x3a,0x02,0x76,0xe1,0x9c,0xc7,0x9f,0xdf,0x56,0x6b,0xc3,0x28,0x94,0xd3,0x27,0x3e,0x84,0xfd,0xf3,0x10,0x2c,0x67,0x00,0x00, - 0x05,0x20,0xcd,0xe4,0x3d,0x96,0x02,0xc9,0xfc,0x31,0x98,0x89,0x16,0xb8,0xd6,0xb0,0x3b,0xb5,0xbe,0xd0,0x2d,0x04,0x86,0xc1,0xf1,0x4b,0x4c,0x82,0x31,0xe9,0xb0,0xa5,0xdd,0x90,0x00,0x00, - 0x05,0x20,0xce,0x35,0x8b,0x57,0x10,0x1c,0xba,0x13,0x0d,0xce,0xe4,0xcc,0x1a,0x6c,0x36,0x4b,0xf7,0x83,0x61,0xbb,0xc9,0x68,0x1c,0x73,0x89,0x23,0x05,0xeb,0x83,0xc5,0x0d,0xa6,0x00,0x00, - 0x05,0x20,0xce,0x62,0x4e,0x72,0xa7,0xff,0xbc,0x93,0x15,0xd1,0x1d,0xb4,0x43,0xd3,0x51,0xf3,0xf9,0xc4,0xeb,0x74,0xc3,0xaa,0x6a,0xb3,0xe8,0xb5,0x0e,0xfd,0x9b,0xa8,0xcf,0x04,0x00,0x00, - 0x04,0x20,0xc0,0x87,0x6d,0x13,0x94,0x29,0x8b,0x63,0x8a,0x0d,0x07,0x0d,0xb6,0x6a,0x12,0xa8,0x17,0x8d,0x6d,0xd9,0x01,0x2e,0x0b,0x09,0x3b,0xbf,0x0d,0x33,0x08,0x87,0x35,0xa8,0x20,0x8d, - 0x04,0x20,0xc0,0x8b,0x52,0x0e,0x8b,0x53,0xe2,0x3e,0x85,0x88,0xac,0x08,0x9a,0x47,0xa0,0x7c,0xc5,0x2e,0x7c,0x60,0x84,0xc5,0x5c,0xba,0x6d,0x69,0xcb,0x5b,0x53,0x6e,0xf1,0x84,0x20,0x8d, - 0x04,0x20,0xc0,0x95,0xe5,0xf4,0xa5,0xb7,0x9d,0x2c,0x9a,0x6e,0x17,0xc9,0x3e,0x17,0x13,0xab,0xf7,0x28,0x0c,0xbd,0x05,0xb0,0xac,0x72,0x6b,0x79,0x88,0xcd,0x37,0x98,0xf2,0x05,0x20,0x8d, - 0x04,0x20,0xc0,0x9a,0x47,0xb7,0x2a,0x9a,0x8e,0x5c,0x4a,0x08,0x4a,0xcc,0x14,0xab,0xa0,0xb2,0x2a,0xb9,0x6c,0x88,0x80,0x7a,0xa4,0xd0,0x6e,0x9a,0x6a,0xda,0xac,0x24,0xf0,0x0f,0x20,0x8d, - 0x04,0x20,0xc0,0xad,0x18,0x80,0x2e,0x63,0x91,0x75,0x5c,0xc6,0x55,0xd6,0x3c,0x5d,0x50,0x70,0xbf,0x08,0x63,0x53,0xed,0xae,0x29,0x5d,0x26,0x70,0xd7,0x5a,0x60,0x76,0x11,0xfc,0x20,0x8d, - 0x04,0x20,0xc0,0xad,0x68,0xd9,0x50,0x40,0x6a,0xa2,0xcd,0xe2,0xea,0xb1,0x09,0x79,0xa5,0xf9,0xe3,0x92,0x4e,0x2c,0x81,0xac,0xee,0x60,0x04,0xf8,0x61,0xd7,0x4e,0xb4,0x0a,0x8b,0x20,0x8d, - 0x04,0x20,0xc0,0xae,0x91,0x9f,0x89,0x8f,0x2b,0x46,0xf3,0x9f,0x10,0xe5,0x91,0x38,0xc4,0xd7,0x9e,0x11,0xb6,0x01,0x59,0x51,0xa7,0x49,0x8a,0xe9,0x39,0x48,0x32,0x28,0x35,0xbf,0x20,0x8d, - 0x04,0x20,0xc0,0xf4,0x06,0x23,0x71,0x23,0x36,0x8d,0x72,0x1a,0x0f,0xfc,0xbe,0x51,0x38,0x86,0xf9,0xbc,0x0a,0x2e,0xb4,0x66,0x7b,0x43,0x02,0xab,0xc5,0x27,0x14,0xcf,0xb2,0xef,0x20,0x8d, - 0x04,0x20,0xc0,0xf8,0xdc,0x52,0x50,0x52,0x1a,0x6f,0x4d,0x42,0xb3,0x18,0xe7,0xe5,0xab,0xb9,0xf0,0x53,0xab,0x66,0x95,0xb5,0xee,0x81,0x79,0xfd,0x5e,0xef,0x4d,0xd0,0x36,0xd5,0x20,0x8d, - 0x04,0x20,0xc0,0xfc,0x1d,0xda,0x6c,0xa7,0x83,0x9e,0xa9,0x9f,0x3d,0xbd,0xce,0xb9,0x98,0xaf,0xba,0xe6,0x93,0xda,0xfd,0xc8,0x23,0xfc,0xbb,0xab,0x57,0x65,0x05,0x72,0xac,0x07,0x20,0x8d, - 0x04,0x20,0xc0,0xca,0xe8,0x86,0xfd,0xe3,0x1b,0x9f,0x9b,0xb4,0xd3,0x29,0xaa,0x2d,0x4e,0x65,0x40,0xa1,0x86,0xd7,0x70,0x07,0xe0,0x44,0x0a,0x6a,0x12,0x1d,0x23,0x9f,0x32,0x8a,0x20,0x8d, - 0x04,0x20,0xc0,0xd1,0x02,0x2a,0x0f,0x11,0x7b,0xbf,0x5b,0xb4,0xb4,0x86,0x25,0xdb,0xaf,0x9f,0x1b,0xa2,0xab,0x3d,0xd1,0x5d,0xca,0xd8,0x63,0xa0,0x85,0xd9,0xf5,0x7c,0x31,0xe0,0x20,0x8d, - 0x04,0x20,0xc0,0xd7,0xd5,0x42,0x3a,0x05,0x2a,0x82,0x75,0x93,0x4a,0x99,0xbf,0x9f,0x2a,0x81,0xf9,0xb7,0xb8,0x28,0x0c,0xf1,0xc6,0x48,0xb9,0x50,0x69,0xc4,0xd1,0xaf,0x37,0x4c,0x20,0x8d, - 0x04,0x20,0xc0,0xdc,0x9a,0x31,0x15,0x4b,0xd0,0xd9,0x69,0x76,0x34,0x17,0xdb,0x83,0x16,0x0b,0x4d,0x16,0x5b,0xbe,0x6d,0x59,0x30,0x2e,0xa5,0x46,0x3f,0x28,0xf3,0x4a,0x95,0x63,0x20,0x8d, - 0x04,0x20,0xc0,0xea,0x1b,0x8f,0x32,0xf5,0xbb,0x62,0x15,0x05,0x44,0x25,0x06,0xcd,0xe1,0x1f,0xe6,0xb4,0x38,0xa4,0x6c,0x10,0x7e,0x9d,0x6d,0xce,0xf9,0xde,0x78,0xb5,0xc7,0x00,0x20,0x8d, - 0x04,0x20,0xc1,0x01,0x3f,0x10,0x1c,0x24,0xaa,0x3e,0x35,0x0c,0x39,0xb5,0x11,0x07,0x66,0x3b,0xe9,0x27,0x43,0x29,0x0f,0x38,0x05,0x87,0x67,0x38,0xd3,0xc1,0xe9,0xa8,0x63,0x75,0x20,0x8d, - 0x04,0x20,0xc1,0x0a,0x81,0x64,0xd4,0x2f,0x39,0xb9,0x39,0x29,0x18,0x98,0x7f,0xaf,0x2a,0xfa,0xfd,0x8e,0x6c,0x1e,0xae,0x92,0x1c,0x2b,0x77,0xd5,0xb8,0xdf,0xdd,0xca,0x4c,0xb8,0x20,0x8d, - 0x04,0x20,0xc1,0x0a,0x90,0x61,0x6e,0xab,0xc6,0x70,0x87,0xa1,0xe8,0x4e,0x9b,0xef,0xe3,0x41,0xa7,0xda,0x7b,0x4b,0x66,0x70,0x2e,0xf3,0x06,0x98,0x03,0x61,0xbc,0xec,0xde,0x6c,0x20,0x8d, - 0x04,0x20,0xc1,0x0c,0x77,0x8a,0x91,0xc0,0x06,0xb0,0xdf,0x2a,0xf3,0xb7,0x44,0x90,0x2c,0x2d,0x28,0xc5,0x3d,0xc8,0xde,0x87,0x1d,0x0a,0x65,0x64,0x17,0xea,0xc1,0xbd,0xb2,0x50,0x20,0x8d, - 0x04,0x20,0xc1,0x1b,0x6d,0x78,0xbb,0x47,0x94,0x5e,0xd3,0x4d,0x00,0xfd,0x75,0xa0,0xd7,0x57,0x51,0x84,0x65,0x35,0x5f,0xd9,0x2b,0xed,0xf9,0x48,0x81,0x34,0x12,0x4e,0x30,0xc8,0x20,0x8d, - 0x04,0x20,0xc1,0x1c,0x01,0xd0,0x8e,0xdd,0x14,0x5f,0x4b,0x65,0x24,0xf1,0x69,0x86,0xa6,0x63,0xeb,0x19,0xa9,0x20,0xec,0x56,0xff,0xd8,0x4f,0xe0,0x10,0x23,0xfa,0x65,0x39,0xf7,0x20,0x8d, - 0x04,0x20,0xc1,0x20,0x98,0xb5,0xb4,0x2f,0x0a,0x13,0x65,0x0a,0xff,0x20,0x53,0xc5,0xc7,0x16,0x18,0x9f,0x88,0x41,0xc9,0x3c,0xd1,0xab,0x1c,0x79,0x3d,0xfd,0x88,0xe5,0x92,0x44,0x20,0x8d, - 0x04,0x20,0xc1,0x22,0xd6,0x14,0xd1,0xa7,0x3c,0x6e,0x6e,0xb2,0x42,0x53,0x5e,0x71,0xbf,0x66,0xfb,0x37,0xbb,0x2d,0x6a,0x87,0xa7,0xea,0xcb,0xdd,0x21,0x95,0x20,0x93,0xa2,0xaf,0x20,0x8d, - 0x04,0x20,0xc1,0x27,0x32,0xe5,0xfa,0xa8,0x1a,0xc5,0x10,0xf6,0xb9,0x01,0x43,0x3a,0x70,0x14,0x8d,0xbb,0x49,0xcc,0x10,0x22,0x6a,0x92,0x6a,0xe3,0x4f,0x66,0x90,0x31,0x7c,0x3e,0x20,0x8d, + 0x02,0x10,0x2a,0x11,0xd5,0x40,0x05,0x31,0xb0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, + 0x02,0x10,0x2c,0x0f,0xfb,0x18,0x04,0x02,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x20,0x8d, + 0x04,0x20,0xd6,0x9f,0x9d,0x19,0x10,0x32,0xe2,0x90,0x1d,0xa4,0x08,0x48,0x41,0xa7,0x05,0x3b,0x31,0xaf,0x59,0x05,0x87,0xc7,0xeb,0x35,0x0e,0x43,0xa1,0x5d,0xa8,0x22,0x98,0xc7,0x20,0x8d, + 0x04,0x20,0xd7,0x38,0x5e,0x38,0x72,0xd2,0x70,0x7b,0xa4,0x39,0x62,0x5c,0xef,0xf0,0xf5,0x19,0xb3,0x75,0x28,0xbc,0xbe,0x24,0xdb,0x2d,0x0d,0xe0,0x7d,0xec,0x80,0x53,0x95,0x49,0x20,0x8d, + 0x04,0x20,0xd7,0x57,0xed,0x23,0x12,0x64,0x29,0x98,0xaf,0x57,0x33,0x85,0x54,0x3e,0x41,0xd4,0x0f,0x6b,0xa3,0x20,0x39,0x8a,0xee,0xf6,0x52,0x4e,0x87,0x41,0x00,0xe6,0x3b,0x05,0x20,0x8d, + 0x04,0x20,0xd7,0x5b,0x68,0x32,0x61,0x82,0x05,0x08,0xbe,0x32,0x2d,0x7f,0xd9,0x98,0xe6,0xe6,0xf4,0x2e,0x55,0x10,0x5b,0xe5,0xf7,0x57,0xba,0x78,0x75,0x44,0xea,0x9a,0xb7,0x08,0x20,0x8d, + 0x04,0x20,0xd7,0x72,0xc2,0x82,0x00,0x52,0x36,0x5d,0xf1,0xf6,0x88,0x35,0xcc,0x2f,0xc4,0x81,0xa5,0x13,0xb0,0x57,0xb0,0x35,0x54,0x84,0xb7,0xc8,0xc6,0x60,0x2c,0x86,0x21,0x3c,0x20,0x8d, + 0x04,0x20,0xd7,0x92,0x50,0xde,0x23,0x6c,0x83,0x75,0x81,0x1f,0x83,0x9b,0x10,0x21,0x2f,0xdc,0x81,0xa9,0x60,0x28,0xcb,0x2f,0xfe,0xc7,0x1e,0x1e,0x23,0xb9,0x6c,0x60,0x63,0xd9,0x20,0x8d, + 0x04,0x20,0xd7,0xda,0x30,0x73,0x66,0x86,0xe0,0x82,0x71,0x96,0xd1,0xa4,0x29,0x66,0xf6,0xe7,0x44,0xa9,0xad,0x59,0x0e,0x87,0x22,0x1c,0x0d,0xb4,0x23,0x5d,0xa1,0x7c,0xe8,0x45,0x20,0x8d, + 0x04,0x20,0xd0,0x7a,0xcc,0x52,0x83,0x8e,0x34,0x51,0x74,0x01,0xb5,0x23,0xef,0xe2,0xe4,0x6c,0x14,0x90,0xbf,0x66,0xb6,0x39,0x75,0x5d,0x78,0xf1,0x17,0x48,0xde,0xcf,0x87,0x99,0x20,0x8d, + 0x04,0x20,0xd0,0x69,0xf0,0x08,0x1d,0x1c,0x97,0x7e,0xed,0xca,0x20,0xc9,0x35,0x3a,0xa8,0xac,0x8b,0x93,0x25,0x54,0xea,0xa3,0x76,0xde,0xbe,0x48,0xac,0xf7,0x56,0x30,0x11,0x30,0x20,0x8d, + 0x04,0x20,0xd1,0x62,0xdc,0x41,0xd8,0x67,0x4d,0x0b,0x3b,0xef,0xbf,0x82,0xb8,0xa3,0x4f,0xf0,0xa1,0x77,0xc2,0xc9,0xcf,0x8b,0x79,0xc6,0x96,0x0b,0xbc,0x71,0x14,0x34,0x3f,0xe3,0x20,0x8d, + 0x04,0x20,0xd1,0xbe,0x5e,0x0e,0x53,0xe1,0x81,0xa6,0x5a,0x60,0xaa,0x77,0x43,0xa2,0xe7,0xb4,0xd5,0x30,0x4b,0xbb,0x8d,0x27,0x93,0x97,0x63,0x5f,0x16,0xa2,0x07,0x77,0xf2,0x3e,0x20,0x8d, + 0x04,0x20,0xd1,0xf0,0xed,0x35,0xe7,0x48,0xce,0xaf,0xca,0x2d,0x52,0x7f,0xad,0x3d,0xb8,0x68,0x66,0x3e,0x40,0x54,0xd2,0x81,0x08,0x4a,0x05,0x83,0x78,0x3a,0x6e,0x08,0xe7,0x70,0x20,0x8d, + 0x04,0x20,0xd1,0xf1,0x76,0x2c,0x0a,0x44,0x66,0xf3,0x06,0xec,0xc3,0xb0,0xb9,0x2a,0xcc,0xdc,0x36,0xfe,0x76,0x32,0x24,0x33,0xc0,0x93,0x2f,0xb3,0x85,0x7e,0xe5,0x5a,0x8e,0x4c,0x20,0x8d, + 0x04,0x20,0xd2,0x5a,0x3a,0x01,0xe6,0x6c,0xb3,0x3b,0xc1,0x76,0xf8,0x1b,0xaf,0x6d,0x89,0x4c,0x47,0xa3,0x9f,0x4e,0x51,0x9e,0x6f,0x4b,0x8f,0xba,0xe6,0xab,0x48,0x16,0xc1,0x62,0x20,0x8d, + 0x04,0x20,0xd3,0x42,0x52,0x53,0x19,0xc4,0xa0,0x7b,0x68,0x00,0xb2,0x09,0x5a,0x24,0x62,0xfc,0xb6,0xfa,0xc5,0x1b,0x36,0x0d,0x42,0xba,0xcd,0x17,0xf6,0xf0,0x86,0x1f,0x7d,0x9c,0x20,0x8d, + 0x04,0x20,0xd3,0x84,0xa3,0x27,0xd8,0xba,0xb1,0x32,0xa2,0x8f,0xdc,0x57,0x49,0xab,0xe9,0xf6,0xa7,0x36,0xd5,0xa3,0x45,0x63,0x28,0x43,0x9a,0xd9,0x91,0xfd,0x04,0xdd,0x7d,0x21,0x20,0x8d, + 0x04,0x20,0xd3,0xb1,0x9f,0xe5,0x4f,0xa2,0x8e,0xb7,0x0f,0x3c,0x38,0x87,0x22,0xa8,0x3f,0x2e,0xe6,0x37,0x3f,0x0a,0xd1,0xfd,0xd6,0xda,0x60,0x45,0x51,0x4b,0x0a,0xbc,0x5a,0xa9,0x20,0x8d, + 0x04,0x20,0xd4,0x18,0x53,0xe8,0x18,0xf6,0x6a,0xfa,0xd6,0x42,0xd1,0x4d,0x51,0x02,0x36,0x47,0x9b,0x8f,0xd5,0xc7,0x9e,0xfd,0x4b,0x43,0x27,0xd4,0xb4,0xb1,0x29,0x53,0xb8,0xc9,0x20,0x8d, + 0x04,0x20,0xd4,0x5f,0x04,0x6b,0xc9,0x5c,0xdf,0x0b,0x98,0xeb,0x72,0xd2,0xa2,0xd5,0xf8,0xb4,0x30,0x8c,0xcd,0x4b,0xac,0x09,0xa4,0xf8,0xdd,0xdf,0x45,0x3e,0x40,0x5d,0x11,0x51,0x20,0x8d, + 0x04,0x20,0xd4,0x5f,0x71,0x44,0xb7,0x8c,0xc6,0x29,0x7c,0xbf,0x50,0xc2,0x0f,0x27,0xf1,0xd9,0x13,0xe5,0x6a,0xe8,0xb0,0xa2,0x10,0xb4,0x55,0xa6,0x1d,0xb1,0xb2,0x5b,0x44,0x24,0x20,0x8d, + 0x04,0x20,0xd8,0x73,0x8e,0x55,0x90,0x75,0x4e,0x86,0x51,0xa3,0xdf,0x44,0xb0,0x0b,0x93,0xbe,0xd1,0x2c,0x70,0xb9,0x7b,0x61,0x0f,0x88,0xf9,0x43,0x95,0x38,0xf5,0x0d,0xe0,0x35,0x20,0x8d, + 0x04,0x20,0xd8,0xf7,0xf9,0xaa,0x2e,0x0c,0x16,0xcf,0xf0,0x92,0x98,0x5d,0x6a,0xef,0x95,0x21,0x9b,0x37,0x87,0x1c,0x76,0xfa,0x5e,0x09,0xfc,0x00,0xdc,0xf5,0x4a,0x27,0xac,0x1e,0x20,0x8d, + 0x04,0x20,0xd8,0xef,0x0e,0xe7,0x71,0x61,0xf2,0x78,0xf5,0x20,0x02,0x2d,0x96,0xef,0x83,0x5d,0xd2,0x09,0x1e,0xc3,0x2e,0x09,0x97,0xed,0xf7,0x46,0x82,0xe5,0x17,0xcb,0x4a,0xe3,0x20,0x8d, + 0x04,0x20,0xd9,0x79,0xc1,0x8d,0xf8,0xd0,0xbd,0x6c,0x4e,0x1b,0xf8,0xff,0xb8,0xbb,0xe9,0xd9,0xd7,0xae,0x35,0x26,0x62,0x8e,0xa6,0xdf,0x04,0x50,0xf6,0xd2,0xa3,0xc5,0x47,0xb4,0x20,0x8d, + 0x04,0x20,0xd9,0x7d,0x7d,0x80,0x42,0x4e,0x5d,0xfd,0x4c,0x57,0x2e,0xcb,0x6c,0xba,0x76,0x9e,0xac,0x8e,0x17,0xc9,0x82,0x19,0x47,0x0c,0x7d,0x98,0xf7,0x35,0x2c,0x1f,0x9d,0x65,0x20,0x8d, + 0x04,0x20,0xda,0xba,0xfb,0x57,0xac,0x82,0x5d,0xc1,0x18,0x8a,0xc6,0x34,0xd1,0x57,0xc8,0x76,0x07,0x48,0x50,0x6a,0xf1,0x92,0xef,0x46,0x1b,0x76,0x47,0x00,0x4c,0xc3,0x60,0x3a,0x20,0x8d, + 0x04,0x20,0xda,0xe9,0x14,0x31,0x06,0xef,0x1d,0x97,0xbe,0x95,0x80,0x4f,0xd5,0xba,0x37,0x13,0x39,0x9f,0x75,0x7e,0xc0,0x71,0x19,0x4f,0x6a,0x90,0xd2,0x54,0x3b,0x08,0x17,0x9a,0x20,0x8d, + 0x04,0x20,0xdb,0x38,0xef,0x94,0x42,0x72,0x32,0x68,0x13,0x68,0xc0,0x6c,0x49,0x86,0x13,0x66,0xeb,0x20,0xfc,0x6f,0x73,0x86,0x61,0xf4,0xd3,0x03,0x71,0x7c,0xfc,0xdb,0xa4,0x8d,0x20,0x8d, + 0x04,0x20,0xdc,0x0c,0x6b,0x85,0xfa,0x09,0x8d,0x52,0x6a,0xfa,0x25,0x45,0x2f,0x37,0x0d,0x70,0x2f,0x1c,0x50,0x96,0xeb,0x05,0x1e,0x2d,0x72,0x53,0x45,0x92,0x59,0x1b,0x70,0x85,0x20,0x8d, + 0x04,0x20,0xdc,0x80,0xfe,0x55,0xdd,0xaf,0x35,0x92,0xfa,0x95,0x09,0x1d,0x73,0x27,0x53,0x64,0x2c,0x5b,0xb6,0x4c,0xf2,0xd7,0x38,0x88,0x97,0x39,0x07,0xfc,0x85,0x1e,0xfc,0x6a,0x20,0x8d, + 0x04,0x20,0xdc,0xdc,0x53,0x83,0x96,0xf8,0x7f,0x8e,0x81,0x86,0xb1,0xd3,0xb3,0xca,0x49,0x8f,0xf3,0xb8,0xe6,0x2f,0x9a,0xde,0xcf,0x58,0xd9,0x32,0xa3,0x1a,0x42,0xdc,0x4e,0x34,0x20,0x8d, + 0x04,0x20,0xdc,0xde,0x12,0x4c,0x84,0x63,0xa9,0xdd,0xe0,0xb9,0x41,0x72,0x10,0xb0,0xe6,0x87,0xc1,0x55,0xc6,0x8c,0x98,0x05,0x29,0xab,0xda,0x3a,0xe8,0xab,0x72,0xa6,0x9f,0xd0,0x20,0x8d, + 0x04,0x20,0xdd,0x96,0x36,0x3e,0x5d,0x3b,0xae,0x2f,0xfa,0x05,0x2e,0x9c,0x5d,0x80,0x6f,0xf1,0x60,0x30,0x6e,0xae,0x08,0x88,0xd7,0x0d,0xd0,0xb5,0x9b,0xa3,0x45,0x66,0x93,0x69,0x20,0x8d, + 0x04,0x20,0xe6,0xa0,0x53,0xc1,0xd8,0x20,0x54,0xf1,0x8c,0x92,0xba,0x3f,0x90,0xb3,0x74,0x48,0x8b,0x96,0x02,0x73,0x12,0xc0,0xd6,0xd5,0x43,0x7f,0x8d,0xdf,0x99,0x41,0x37,0x57,0x20,0x8d, + 0x04,0x20,0xe6,0xa8,0xa1,0xa3,0xd9,0x91,0xa1,0xd3,0x88,0xbd,0x1f,0x03,0xeb,0xdc,0x69,0xff,0xca,0x54,0x49,0x87,0xce,0xa4,0xcf,0x98,0x95,0x40,0x44,0xdb,0x1f,0x25,0x35,0x1a,0x20,0x8d, + 0x04,0x20,0xe7,0xe9,0xc5,0x85,0x3f,0x83,0x30,0xb5,0xaa,0xe9,0xda,0x43,0x92,0xa5,0xc0,0x37,0x33,0xdc,0x22,0x8e,0xc3,0xe5,0x87,0xf3,0x7d,0xe0,0x1f,0x17,0x49,0x94,0x6a,0x81,0x20,0x8d, + 0x04,0x20,0xe2,0xf4,0xa0,0xd7,0xc3,0xc0,0x0c,0x74,0x42,0x39,0x15,0x30,0xbc,0xd0,0xf6,0x48,0x80,0x6d,0xd4,0x34,0x4c,0x78,0x28,0x93,0x45,0xd1,0x76,0x0e,0x98,0x25,0xfc,0xb5,0x20,0x8d, + 0x04,0x20,0xe3,0x65,0xf2,0x53,0x6b,0xb8,0x36,0x1e,0xe6,0x15,0x02,0x6b,0x98,0xa0,0xce,0xd7,0x17,0x30,0xa5,0x84,0x44,0x19,0xa7,0x82,0x27,0x22,0x0e,0x09,0x8f,0x8d,0xf3,0x20,0x20,0x8d, + 0x04,0x20,0xe3,0xd9,0xa0,0x94,0x3b,0x01,0x14,0xbd,0xad,0x4f,0x2f,0x22,0x74,0xa4,0x23,0x69,0x44,0xdd,0x5c,0x4d,0x82,0x95,0xc1,0x93,0x6f,0xcf,0x88,0xaa,0x9c,0xbd,0xc3,0x37,0x20,0x8d, + 0x04,0x20,0xe4,0x3d,0x75,0x4e,0x71,0xd5,0x6b,0x81,0x37,0xc4,0xe5,0x2d,0xde,0x94,0x85,0x5c,0xa1,0xb7,0x62,0x2c,0x06,0x5b,0xf9,0x97,0x3c,0xee,0x2e,0xd4,0x7f,0x78,0x3a,0x53,0x20,0x8d, + 0x04,0x20,0xe4,0x4b,0xbf,0x49,0x3f,0xfe,0xca,0x7b,0x5c,0x30,0xd4,0x99,0x8b,0x3f,0x97,0x53,0xc7,0x7a,0xa3,0x1e,0x06,0x62,0xee,0x11,0xe2,0x5f,0x6b,0x34,0x97,0xe5,0x92,0x5b,0x20,0x8d, + 0x04,0x20,0xe5,0x7a,0xcc,0x5a,0x97,0x0b,0xc7,0x0c,0x16,0xd6,0x77,0x03,0x5c,0x18,0x30,0xc5,0x5a,0x4d,0x7c,0x8a,0x35,0x01,0x58,0x6b,0xde,0x03,0xfc,0xef,0xf5,0x21,0x12,0x56,0x20,0x8d, + 0x04,0x20,0xe5,0x5f,0xa7,0xc9,0x1f,0xdc,0x0b,0x27,0x8b,0xcd,0x23,0x86,0xfb,0xba,0xe4,0xe1,0xc9,0x77,0x9c,0xb9,0x87,0x56,0xb7,0x4a,0x20,0x3f,0x4c,0xae,0x35,0x36,0x3b,0x7e,0x20,0x8d, + 0x04,0x20,0xee,0x98,0x54,0xba,0x87,0xb5,0xcb,0xb7,0xd2,0x9a,0x01,0x78,0x39,0x39,0x52,0x49,0x4e,0xda,0xd0,0xbc,0x61,0x9e,0xa1,0x05,0x76,0xf1,0x86,0xc9,0x24,0xd1,0x0b,0xe3,0x20,0x8d, + 0x04,0x20,0xee,0xc2,0xf3,0x48,0xb8,0x5a,0x73,0x7e,0xd3,0x33,0x87,0x73,0x4d,0x60,0x2c,0xd3,0xa0,0x94,0x04,0x1a,0x20,0x98,0xc1,0x59,0x30,0xcf,0x78,0x59,0x2e,0xf1,0xd2,0x7d,0x20,0x8d, + 0x04,0x20,0xef,0x8a,0x5f,0xe5,0x67,0x8e,0xe4,0xb3,0x83,0x63,0xd1,0x7d,0xa4,0x12,0xf7,0xf9,0x9b,0xb4,0xde,0x29,0xaa,0x83,0xb2,0x7d,0xb7,0xfd,0x34,0x99,0xb6,0x82,0xd4,0xbf,0x20,0x8d, + 0x04,0x20,0xe8,0x6e,0xf7,0x3a,0x31,0x36,0x0f,0x21,0x77,0xfc,0xf4,0x4d,0xc0,0x0e,0xb3,0x4b,0x2e,0xa7,0x96,0xce,0xe5,0x4e,0xe5,0x64,0x9f,0xbd,0x7f,0x51,0x00,0x1b,0x03,0x49,0x20,0x8d, + 0x04,0x20,0xe9,0x90,0xa1,0x51,0x46,0xef,0xaf,0xf9,0xe0,0xd6,0x9a,0x5e,0x4b,0xd4,0x7f,0x10,0x36,0xc4,0x1d,0x2f,0x9e,0x4b,0x11,0x5c,0x31,0x59,0xf7,0xaa,0x93,0x16,0x77,0x17,0x20,0x8d, + 0x04,0x20,0xea,0x8c,0x60,0x11,0x69,0xa1,0xb3,0x6e,0xee,0x7f,0x62,0x23,0x7d,0x1e,0x0c,0x90,0xa8,0x2e,0x94,0x01,0xd6,0xde,0x53,0x77,0xec,0x45,0x62,0x1b,0x5b,0x6f,0x27,0x44,0x20,0x8d, + 0x04,0x20,0xeb,0x4c,0x2b,0xc6,0x2f,0x50,0x84,0x82,0x57,0xd4,0x01,0xa9,0x36,0x7b,0x29,0x72,0x3e,0x3f,0x2f,0x6d,0x59,0xd0,0xa9,0xa1,0x1b,0xce,0xd8,0x7c,0xbc,0x41,0xec,0x14,0x20,0x8d, + 0x04,0x20,0xeb,0xd0,0x0e,0x3d,0xdf,0x0c,0x4c,0x20,0x04,0x87,0x4e,0x1e,0x86,0x98,0x94,0x2d,0xec,0x0c,0x39,0x3c,0x62,0x1b,0xe4,0x98,0x1d,0x86,0x32,0x01,0x37,0xab,0x7f,0x05,0x20,0x8d, + 0x04,0x20,0xeb,0xd9,0x1d,0x41,0x74,0x00,0x0a,0x46,0x2d,0x05,0x64,0xa2,0x3d,0x8e,0x77,0x39,0xa7,0x95,0x1c,0x5a,0xa7,0xd4,0xf9,0x66,0x15,0x5f,0x4f,0xb5,0xd8,0x3d,0xe2,0x58,0x20,0x8d, + 0x04,0x20,0xec,0x97,0xe2,0x95,0x29,0xdb,0x08,0x26,0xc9,0x47,0x97,0x97,0x37,0x9f,0x30,0xfe,0x79,0x5b,0x8c,0xe5,0x93,0x3c,0x5f,0xde,0xbc,0x2b,0x31,0x04,0xce,0x0b,0x0e,0x73,0x20,0x8d, + 0x04,0x20,0xec,0xd9,0xea,0x05,0x12,0xd0,0x26,0xf4,0xa0,0x86,0x33,0xe6,0x54,0x4f,0xb9,0x57,0x06,0xd6,0x38,0x96,0x10,0x96,0x9d,0x98,0x29,0x28,0x9e,0xd7,0x4b,0x16,0xa9,0x3e,0x20,0x8d, + 0x04,0x20,0xed,0x50,0xa3,0xfe,0xd9,0x66,0x15,0x31,0x85,0x3c,0x74,0xda,0x8c,0xda,0x4e,0x24,0xdf,0x0f,0xcf,0x72,0xb0,0x0d,0xdd,0x79,0x75,0xae,0x33,0x6e,0xd9,0x2c,0x72,0x13,0x20,0x8d, + 0x04,0x20,0xed,0x56,0xb6,0xa5,0xcf,0xce,0x0e,0xc5,0x95,0xf2,0x02,0x83,0xea,0xe6,0x11,0xe1,0x5e,0x60,0xc0,0x88,0x58,0xa9,0x1b,0xb1,0x1d,0x54,0xc0,0xc9,0xd5,0x47,0x80,0xe8,0x20,0x8d, + 0x04,0x20,0xed,0x5e,0x16,0xd9,0x8a,0x82,0x58,0x47,0x4b,0x90,0x2c,0xc1,0xd7,0x7f,0xcd,0x95,0x11,0xc4,0x22,0x52,0x01,0x4d,0x95,0xee,0x03,0x54,0xd9,0x2c,0xb7,0x21,0x26,0xf6,0x20,0x8d, + 0x04,0x20,0xed,0x84,0x64,0x53,0xe4,0x33,0xd5,0x07,0xb7,0xde,0xae,0x3c,0x3c,0xf3,0x7d,0x8f,0xdd,0x58,0x49,0xfa,0xc7,0xc8,0x57,0xa7,0x1e,0x68,0x02,0x1e,0x84,0xf3,0x6a,0x0d,0x20,0x8d, + 0x04,0x20,0xee,0x08,0xd0,0x45,0xf9,0x41,0xcf,0x6c,0xff,0xab,0x08,0xa3,0x3d,0x6a,0xc9,0xd4,0x27,0x05,0xf3,0x8a,0xeb,0xf2,0x1d,0x4f,0x04,0xaf,0x8b,0x75,0x85,0xf9,0x63,0xfd,0x20,0x8d, + 0x04,0x20,0xee,0x51,0xc1,0x50,0x47,0x66,0x69,0x66,0xa8,0xde,0x5a,0x3e,0x89,0x9f,0x6f,0x24,0x64,0x86,0xe2,0xae,0x60,0xa8,0x23,0xf4,0xac,0xbe,0x29,0x99,0xf8,0x8d,0x2e,0x85,0x20,0x8d, + 0x04,0x20,0xf6,0xa7,0x6f,0xc8,0x5d,0xee,0xbd,0xdb,0x6a,0x50,0x39,0xd4,0x16,0x89,0xd4,0x61,0xae,0x14,0x5e,0xf3,0x50,0x14,0x8a,0x38,0xdf,0xc8,0xa1,0x8a,0x1b,0xe8,0x20,0x43,0x20,0x8d, + 0x04,0x20,0xf6,0xc5,0x0a,0x43,0x44,0xd9,0x9e,0x23,0x16,0x68,0xeb,0xc9,0x39,0xdf,0x92,0x09,0xbb,0x33,0x7a,0xf2,0x4a,0xfe,0xd2,0x49,0x4b,0xd5,0xbd,0x66,0xc0,0xc8,0x57,0x95,0x20,0x8d, + 0x04,0x20,0xf7,0x52,0x80,0x5e,0xe4,0x3b,0x00,0xa6,0xfb,0x8d,0x96,0x08,0x0b,0xea,0xea,0xd8,0xe0,0xa2,0x19,0xc7,0xa6,0xf6,0x54,0x7f,0xe6,0x49,0xe8,0xac,0xdb,0xe3,0x67,0x69,0x20,0x8d, + 0x04,0x20,0xf0,0x73,0x3d,0x30,0x64,0x77,0x80,0x53,0x95,0x65,0xbb,0x10,0xb6,0x9d,0xca,0x55,0x6d,0xe2,0x0e,0xf4,0x27,0x16,0x61,0x0e,0xa9,0x40,0x7c,0x56,0xf4,0x6c,0xc7,0xcf,0x20,0x8d, + 0x04,0x20,0xf1,0xdc,0x1a,0x12,0x46,0x6e,0xca,0xae,0x07,0xd7,0x52,0x8c,0x94,0xf3,0x00,0x0b,0x79,0x11,0xaa,0x17,0x3b,0xa3,0xac,0x1b,0xb2,0x19,0x56,0xf8,0xb2,0x69,0x4d,0x1d,0x20,0x8d, + 0x04,0x20,0xf2,0x22,0x14,0x59,0xde,0x66,0xeb,0x87,0x3a,0xe8,0x07,0x8d,0x2c,0x5e,0xb7,0xe8,0xaf,0x42,0x8d,0xf5,0x68,0x76,0xfa,0xf6,0xd6,0xc7,0x08,0xe5,0xb9,0xdd,0x1b,0x00,0x20,0x8d, + 0x04,0x20,0xf2,0x70,0x0f,0xf7,0x6c,0x86,0x62,0xa6,0x19,0x4e,0x7e,0x9b,0x8b,0xfb,0xa2,0xbc,0x0a,0xea,0x3f,0x5a,0x60,0xc0,0xf4,0xf6,0x6a,0x57,0x8d,0x0b,0x1f,0xec,0xf6,0x48,0x20,0x8d, + 0x04,0x20,0xf3,0x3b,0xef,0x7d,0x4b,0x85,0x43,0x80,0x7a,0x90,0x6b,0x05,0x09,0x3d,0xdf,0x01,0x1d,0x12,0x3b,0x22,0x43,0xf3,0x90,0xf4,0xba,0xd6,0xaa,0xb8,0xa4,0xe7,0x70,0xe2,0x20,0x8d, + 0x04,0x20,0xf3,0xaa,0xbd,0x6c,0x41,0xb1,0xc5,0xa1,0xbd,0x9d,0x89,0xb9,0x19,0x6a,0xf1,0x81,0xbf,0x1f,0x57,0x43,0xe0,0x67,0x2a,0xcb,0xd3,0x21,0xf6,0x9d,0x96,0xc8,0xee,0x3e,0x20,0x8d, + 0x04,0x20,0xf4,0x35,0x0b,0x15,0xaf,0x3e,0x1d,0x5f,0x6f,0xb2,0x87,0x13,0xe3,0xa1,0x18,0xef,0x6c,0x8e,0x38,0x64,0xea,0x42,0x21,0xfa,0xce,0x12,0x29,0xc9,0xf4,0x4d,0xfb,0x19,0x20,0x8d, + 0x04,0x20,0xf4,0x15,0xe0,0xcc,0x5a,0xdd,0x67,0x45,0x8e,0x6d,0x6b,0x15,0x58,0xc2,0xac,0xc8,0x92,0xf7,0x51,0x6b,0x2d,0x86,0xc6,0xb4,0x53,0xaa,0xea,0x45,0x5c,0xea,0x1a,0x57,0x20,0x8d, + 0x04,0x20,0xf5,0x5c,0x4a,0xe0,0x5e,0x2f,0xda,0x6d,0x02,0xef,0x36,0x6d,0xb4,0x45,0x94,0xf7,0xfe,0xe9,0x6c,0x3e,0x5f,0xba,0xb4,0x9e,0x8e,0xc9,0x7e,0x72,0xa8,0x11,0xd1,0x5e,0x20,0x8d, + 0x04,0x20,0xf5,0xb1,0x0d,0x23,0x86,0x92,0x6a,0x81,0xd7,0x3f,0xa3,0x24,0x36,0xda,0x26,0xbd,0x55,0x24,0xcb,0xf6,0x85,0x6b,0x42,0xf3,0x23,0x4d,0xe4,0x92,0xa6,0xc6,0xfd,0x90,0x20,0x8d, + 0x04,0x20,0xf6,0x5b,0x41,0x3e,0xb7,0xfa,0xbd,0x90,0x48,0xc7,0xc5,0x34,0x38,0x15,0xfd,0x99,0xe5,0x18,0xfc,0x1d,0xf0,0x86,0x70,0xef,0x10,0x70,0x0d,0x12,0x6e,0x95,0xee,0x9c,0x20,0x8d, + 0x04,0x20,0xff,0x1c,0x9e,0x48,0x7c,0x27,0x72,0x5f,0xb2,0x81,0xef,0x5e,0x46,0x71,0x49,0x14,0x1d,0xea,0x0e,0x86,0x77,0x77,0xb6,0x2d,0xa0,0x3d,0xd9,0x7f,0x29,0x68,0xb3,0x0f,0x20,0x8d, + 0x04,0x20,0xff,0xb0,0x84,0x86,0xa2,0x27,0x24,0x15,0xd8,0xd1,0xde,0xa1,0xa9,0x13,0x47,0x02,0x84,0x1b,0x92,0x42,0x13,0x72,0x96,0x2d,0xee,0x7c,0xd9,0xa1,0xea,0x77,0x64,0x88,0x20,0x8d, + 0x04,0x20,0xff,0xef,0x45,0xc2,0x5e,0x33,0x80,0x0b,0x31,0x9e,0xd7,0x54,0xe8,0x69,0x2c,0xdd,0x0e,0xd1,0xf4,0x62,0x14,0x7a,0x29,0x9c,0xc8,0x6c,0xb6,0x97,0xd3,0x16,0x68,0xa1,0x20,0x8d, + 0x04,0x20,0xf8,0x41,0x44,0x73,0xc3,0xac,0x0b,0xbf,0xf1,0x4f,0x47,0xc0,0x02,0x94,0x1f,0xbb,0x4f,0xbf,0x5d,0xa3,0x17,0x58,0x96,0x40,0xbc,0x56,0x43,0x71,0x52,0x97,0x07,0x5c,0x20,0x8d, + 0x04,0x20,0xf8,0x53,0x61,0xb6,0xfd,0xa3,0x08,0x5d,0x84,0x47,0x9b,0x78,0x27,0x67,0x90,0x05,0xaf,0xa9,0x4f,0x9f,0xee,0x84,0xa8,0xb2,0xd0,0x8e,0xbf,0x42,0x1b,0x9d,0xb7,0x98,0x20,0x8d, + 0x04,0x20,0xf8,0xfe,0xa2,0x8b,0x16,0x2f,0x76,0xe0,0xcc,0xd4,0x84,0x8f,0x2d,0xf3,0x8b,0x34,0xce,0x90,0x0b,0x5e,0x3b,0x46,0x34,0x4e,0xae,0x1c,0x16,0x7e,0xc5,0xc2,0xc6,0xc4,0x20,0x8d, + 0x04,0x20,0xf8,0xd2,0x4d,0x3d,0x09,0x65,0x80,0xd7,0x27,0xb3,0x3c,0x4d,0xfb,0xb0,0x5e,0x39,0x64,0xb1,0xea,0x66,0x8c,0x54,0xd9,0x50,0x8c,0xd8,0xcb,0x7d,0x2f,0xce,0xe1,0x74,0x20,0x8d, + 0x04,0x20,0xf9,0x37,0x1b,0xf1,0xee,0x98,0xb5,0x19,0xef,0x9d,0xc1,0x01,0x33,0x84,0x86,0xbb,0x47,0xd7,0xa9,0xa9,0xa7,0xd1,0x6d,0x2e,0xc8,0xd0,0xb3,0xb0,0x3f,0xae,0x6b,0x55,0x20,0x8d, + 0x04,0x20,0xf9,0xbd,0x57,0xe4,0xb0,0x66,0x43,0x7f,0x08,0x30,0xa6,0xbe,0x4a,0x00,0xfa,0xc3,0x45,0xa1,0xef,0xb6,0x29,0x0c,0x0e,0xd0,0x4e,0xfd,0xe1,0xfc,0x5a,0x2a,0x1c,0x93,0x20,0x8d, + 0x04,0x20,0xf9,0xc8,0x53,0x1a,0xd6,0x50,0x5f,0x8b,0xca,0x1c,0xd2,0x06,0xe3,0x56,0xef,0x28,0x46,0x0c,0x03,0x05,0xe5,0x4c,0x89,0x91,0xc6,0xe9,0x15,0x33,0x90,0xcc,0xc6,0xc6,0x20,0x8d, + 0x04,0x20,0xfb,0x17,0x3f,0x49,0x3b,0x30,0x92,0xe7,0x75,0x2f,0x2e,0x85,0x31,0x75,0xd9,0xaa,0xd2,0x8c,0xd3,0xd5,0xb6,0x85,0x2d,0x0e,0xdb,0x76,0x32,0xe6,0x10,0x0e,0x45,0xb7,0x20,0x8d, + 0x04,0x20,0xfb,0x5a,0xfc,0xbf,0x05,0x0c,0x21,0x97,0xb1,0x85,0x23,0x7d,0x6f,0x63,0xe6,0x8e,0xb4,0x32,0x63,0x5d,0xcd,0x62,0x0a,0xed,0x02,0x2b,0x17,0x80,0xe9,0xa5,0xb5,0xe6,0x20,0x8d, + 0x04,0x20,0xfb,0xf1,0x17,0xd6,0x03,0x3b,0x01,0x8b,0x98,0xcf,0x16,0x20,0xde,0xaf,0x6c,0xed,0x60,0xab,0x6e,0x14,0x0b,0x58,0x6b,0x2d,0xf8,0x06,0x98,0x37,0x7a,0xff,0x7a,0x0f,0x20,0x8d, + 0x04,0x20,0xfc,0x2c,0xaa,0xad,0xe8,0x5a,0xba,0x52,0x2f,0x41,0x42,0x0b,0xc6,0xca,0x6e,0xa0,0x6e,0x32,0x0e,0xe8,0x8d,0x61,0x44,0x8b,0x0f,0x9d,0xcd,0x8f,0x04,0xbe,0x1e,0x64,0x20,0x8d, + 0x04,0x20,0xfc,0x77,0xed,0x48,0x93,0x65,0x0d,0x98,0x99,0xf3,0x7a,0x73,0xa1,0x1b,0x2c,0xfc,0x2b,0xc6,0x9e,0xfb,0x8f,0x86,0x70,0x80,0x2a,0x47,0xef,0x2a,0xf2,0x10,0xb5,0x19,0x20,0x8d, + 0x04,0x20,0xfc,0x7b,0xa8,0xd7,0xa4,0x7e,0x1d,0x0e,0x35,0x1c,0x81,0xe1,0x79,0x3d,0xa5,0xc0,0x13,0x73,0x95,0x7e,0x8e,0x1b,0x6f,0x0b,0x80,0xd3,0xf5,0xf8,0xf2,0xad,0x87,0xb8,0x20,0x8d, + 0x04,0x20,0xfc,0x5f,0x9e,0xfb,0x72,0x34,0xcb,0x90,0x6a,0x0c,0x02,0x7e,0xb9,0x81,0x92,0xb5,0x0a,0xd6,0x0e,0xf5,0xfe,0xaa,0x28,0x2d,0xd7,0x2a,0xa4,0xc2,0xc7,0xe5,0xa0,0xd3,0x20,0x8d, + 0x04,0x20,0xfc,0x99,0xcd,0x29,0x50,0x95,0xac,0xff,0x02,0xe3,0x7e,0x7b,0xb9,0x48,0x85,0x0b,0x0d,0x10,0x1b,0xe4,0xbd,0x90,0x89,0x69,0x05,0x19,0xbf,0x62,0xa1,0xde,0x0d,0xdb,0x20,0x8d, + 0x04,0x20,0xfc,0xed,0x9c,0x1f,0x7a,0xdb,0xa7,0x3f,0xb1,0xe1,0x77,0xb1,0xd8,0x2b,0x0a,0xd9,0x28,0x6b,0x22,0x6d,0x91,0xac,0xab,0x90,0xd0,0x29,0xb9,0xda,0x6c,0x51,0xbb,0x81,0x20,0x8d, + 0x04,0x20,0xfd,0x80,0xa7,0xf2,0xe9,0xba,0xa4,0x68,0x90,0x8a,0xb2,0x48,0xe6,0xd1,0x7a,0x32,0x78,0xe6,0x09,0xbe,0xf9,0xb5,0x05,0x20,0x19,0x2c,0x39,0xc3,0x9a,0x08,0x9f,0x33,0x20,0x8d, + 0x04,0x20,0xfe,0x4c,0x57,0x10,0xc4,0x20,0xfc,0x97,0x4c,0xcc,0xa1,0x75,0x65,0x3a,0x61,0x0e,0x87,0x11,0xaa,0x8a,0xd6,0xb7,0x5d,0xb1,0xce,0x60,0xb8,0x05,0x22,0x98,0xde,0x10,0x20,0x8d, + 0x04,0x20,0xfe,0x56,0xa6,0xe1,0xd7,0x06,0x37,0x10,0x8c,0x3c,0x0a,0x75,0x91,0xc9,0xa0,0x32,0xc6,0xfc,0xa5,0x79,0xca,0xe2,0xcb,0x20,0xef,0x0f,0xb1,0x49,0xa9,0x79,0x82,0x8e,0x20,0x8d, + 0x04,0x20,0x07,0x06,0xac,0xf7,0xa7,0x90,0x48,0x5d,0x79,0x20,0xf8,0x73,0xa9,0x96,0x55,0x59,0x92,0x83,0x1b,0xbd,0x70,0x9a,0x7c,0x0a,0xf0,0xdf,0x08,0x5b,0x3e,0x99,0x34,0xcc,0x20,0x8d, + 0x04,0x20,0x01,0x05,0xc2,0x89,0x38,0x2c,0x7a,0x6e,0x12,0x12,0x22,0x59,0x51,0x7e,0x7b,0x22,0x27,0xe6,0x85,0xb5,0xe5,0x5d,0x76,0xe1,0x4c,0xb6,0x9d,0x16,0xea,0x4c,0x3a,0x2e,0x20,0x8d, + 0x04,0x20,0x01,0x77,0x4a,0xf1,0x91,0xbc,0x60,0x46,0xd3,0xc0,0xda,0x82,0x52,0x3a,0xa0,0x7b,0xfc,0xae,0x57,0x4f,0xd6,0x19,0x7a,0xf3,0x89,0xb6,0xd1,0xf9,0x64,0x06,0x13,0x2e,0x20,0x8d, + 0x04,0x20,0x01,0x5b,0xa8,0xaf,0x56,0x1b,0xe2,0x89,0x12,0xb8,0x3d,0xc8,0x0e,0xb6,0x21,0x2a,0xe7,0xba,0xd8,0x67,0xe8,0xa2,0x6e,0x1e,0x01,0xd0,0xb8,0x8a,0x28,0x17,0x1d,0xb7,0x20,0x8d, + 0x04,0x20,0x01,0x64,0x48,0x16,0x7c,0x4d,0xde,0xac,0x11,0x19,0xe0,0xbd,0x5e,0xfd,0xb7,0xb4,0xe7,0x69,0x93,0xf1,0xe5,0xc1,0x2e,0x2d,0xaa,0xa5,0xc4,0xa2,0xb7,0x8e,0x3b,0xf0,0x20,0x8d, + 0x04,0x20,0x01,0xec,0xa0,0x5a,0x97,0xc3,0xad,0x82,0x49,0xd5,0x9d,0x62,0x80,0x18,0xf0,0x1d,0x68,0x3f,0xaa,0x58,0xda,0xa7,0xe8,0xa4,0xea,0x10,0x07,0x22,0x97,0xb1,0x5a,0xde,0x20,0x8d, + 0x04,0x20,0x02,0x6d,0x2d,0xdf,0xf7,0x20,0xb8,0xa1,0xb9,0xf1,0x8a,0xd3,0x21,0xc9,0xb5,0xd1,0xa3,0x98,0x34,0xdf,0xc0,0x74,0xfd,0x31,0xfc,0x33,0x3f,0xbe,0x9d,0x78,0xd4,0x46,0x20,0x8d, + 0x04,0x20,0x02,0xb5,0xaf,0x5b,0x78,0xac,0xcf,0xc9,0x70,0xb2,0xe2,0x01,0xc8,0x88,0x6a,0x3a,0xb2,0xec,0x45,0x49,0x56,0xba,0xa5,0x6f,0x90,0x35,0xc8,0xe3,0x2e,0xb4,0x3b,0xbe,0x20,0x8d, + 0x04,0x20,0x02,0xcf,0x62,0xf4,0xf4,0x97,0x4c,0x55,0x12,0x1e,0x6c,0xa1,0x73,0xc6,0xeb,0x86,0xdb,0x73,0x92,0x34,0x2e,0x04,0x06,0x00,0xbf,0xbb,0x53,0x67,0xb4,0x97,0xa1,0x74,0x20,0x8d, + 0x04,0x20,0x02,0xe4,0xdc,0x08,0x18,0x82,0x0d,0x33,0xec,0x3d,0xac,0x53,0x32,0xcd,0x6e,0xb5,0xc6,0xd5,0x34,0x9c,0x83,0x1b,0x00,0x59,0x36,0xdc,0x18,0x71,0xb9,0x06,0xe4,0x9f,0x20,0x8d, + 0x04,0x20,0x04,0xf0,0x66,0xf9,0x74,0x12,0xc1,0xf9,0xf8,0x4e,0xc1,0x82,0x51,0xfb,0x4d,0xee,0xf6,0xa0,0x48,0xe7,0xb0,0x2b,0x40,0xa9,0x16,0xcf,0x60,0x64,0xb2,0x7d,0x6a,0x95,0x20,0x8d, + 0x04,0x20,0x05,0xb2,0xd0,0xac,0x42,0xe6,0x2a,0x57,0x08,0x47,0x67,0xf6,0x6b,0x1a,0x68,0x37,0xdc,0x7b,0xde,0x59,0x65,0xaf,0xd2,0xcf,0xb1,0x78,0x48,0xd7,0x69,0x1e,0x2d,0x96,0x20,0x8d, + 0x04,0x20,0x06,0x4b,0xbc,0xc7,0x8b,0x1c,0x7f,0xc6,0x91,0x93,0xee,0x77,0xcd,0x30,0x8b,0x8d,0x62,0x52,0xb3,0xb0,0xb7,0x21,0x7e,0x3f,0x9f,0xc9,0x5c,0xab,0x42,0x8f,0xb6,0xcd,0x20,0x8d, + 0x04,0x20,0x06,0x6a,0x84,0xf6,0x9e,0x01,0x88,0x4d,0x0d,0x7a,0x57,0xc8,0x7d,0x11,0x68,0x85,0x36,0x5d,0x8f,0xa6,0x58,0xf3,0x77,0x0d,0xce,0xfc,0x26,0x92,0xa1,0x58,0xf1,0x2d,0x20,0x8d, + 0x04,0x20,0x0e,0xd2,0x68,0x95,0xe8,0x14,0x1f,0x86,0x3b,0xda,0x90,0xcc,0x56,0x54,0xca,0xf7,0x4d,0x6e,0x7e,0x27,0x8e,0x91,0x8b,0x46,0x92,0x4e,0xa2,0x59,0x6d,0xe8,0xb5,0x8f,0x20,0x8d, + 0x04,0x20,0x0f,0x8a,0xb4,0x90,0x9c,0x4c,0x41,0x18,0x6b,0x77,0xe3,0xde,0xdb,0x51,0x6b,0x1c,0xe5,0x89,0x42,0xa8,0x53,0x5e,0x69,0x8e,0x9d,0x02,0x32,0xf5,0x5d,0xcc,0x51,0xab,0x20,0x8d, + 0x04,0x20,0x08,0x05,0x62,0x54,0xf9,0x34,0xf2,0x6b,0xd4,0x6a,0x55,0xb1,0x55,0x02,0xf2,0xbd,0x8e,0xa3,0xc2,0xc0,0xf1,0xc3,0xb1,0x56,0x88,0xca,0x64,0x83,0xd9,0x4b,0x81,0xe4,0x20,0x8d, + 0x04,0x20,0x08,0x06,0x92,0x85,0x28,0x18,0xd2,0xf6,0xc6,0x9f,0x69,0x18,0xc9,0x09,0x93,0x91,0xf0,0x81,0x0e,0xcc,0x62,0x79,0x31,0x13,0x5b,0xae,0xd0,0x83,0xa4,0xfd,0x9c,0xa9,0x20,0x8d, + 0x04,0x20,0x08,0x1f,0xd4,0x73,0x94,0xb8,0x9c,0xe6,0x01,0x4c,0xb0,0x92,0xb9,0x72,0x4f,0xb1,0xf7,0x44,0x3d,0x68,0x44,0xcb,0x2f,0x30,0xaa,0x88,0xb2,0x36,0xcb,0x02,0xd7,0xcd,0x20,0x8d, + 0x04,0x20,0x08,0x78,0xdd,0xdf,0x74,0x00,0x8a,0x31,0xf1,0xdf,0x6f,0xae,0xb3,0x39,0x8d,0x74,0xe7,0xdd,0xed,0x49,0x48,0xe2,0x96,0xbd,0xde,0x7c,0xc2,0x83,0x3c,0x9d,0x3e,0xbc,0x20,0x8d, + 0x04,0x20,0x08,0x4b,0xf9,0xc2,0x01,0x33,0x55,0xd5,0x02,0x7e,0x5c,0xee,0x95,0x82,0xe4,0x8d,0x20,0x4c,0x61,0xd5,0x0d,0xe4,0x2d,0x84,0x14,0x12,0x41,0x1f,0x80,0x91,0x5c,0x3c,0x20,0x8d, + 0x04,0x20,0x08,0xe2,0xce,0xc2,0xf4,0x75,0xfe,0xa9,0x50,0x2d,0x65,0x88,0xe7,0x4e,0x97,0x38,0x79,0x5d,0xc1,0xf5,0x7f,0xca,0xa5,0x58,0x03,0x05,0x73,0x0a,0x9b,0x0f,0xa4,0xf0,0x20,0x8d, + 0x04,0x20,0x09,0x90,0xcc,0xf3,0xf1,0x84,0x3c,0xd8,0xff,0x19,0x48,0x28,0x28,0xdf,0x8b,0x59,0x43,0x38,0xe2,0x6e,0x75,0xd4,0xfc,0x77,0xee,0x52,0x4f,0x40,0xe7,0xca,0x15,0xd6,0x20,0x8d, + 0x04,0x20,0x0a,0x1f,0x23,0xba,0xdc,0x6e,0xa8,0x73,0x14,0x3f,0x66,0x3a,0x31,0xb0,0x90,0x6e,0xf1,0x2b,0x9a,0x72,0x2d,0x97,0x97,0xeb,0x07,0x81,0xbc,0x4b,0xff,0x3f,0x35,0x32,0x20,0x8d, + 0x04,0x20,0x0a,0xca,0xf8,0x55,0x82,0x41,0x15,0x39,0x43,0x38,0xe7,0x83,0x22,0x71,0x99,0xc5,0xdf,0x20,0xec,0x79,0xe6,0x7f,0x67,0xba,0x85,0x4c,0x78,0x3d,0xce,0xb9,0x41,0xa6,0x20,0x8d, + 0x04,0x20,0x0b,0xa7,0x72,0x57,0xd5,0x27,0xe9,0x23,0x8e,0xc3,0x50,0x4d,0x24,0x64,0x3d,0x57,0x68,0x67,0x64,0xb2,0x9f,0x2f,0xd7,0xce,0x40,0x9e,0xd9,0x46,0xc7,0xa4,0xc4,0x2f,0x20,0x8d, + 0x04,0x20,0x0c,0x56,0x04,0xd0,0x44,0xf9,0x48,0x73,0x03,0x78,0xd1,0x61,0xfe,0xc6,0xcc,0xf6,0xc8,0x2a,0xb7,0x07,0xd9,0x2b,0x2c,0x0f,0x00,0x3f,0xb4,0x3e,0xdf,0xec,0xce,0x59,0x20,0x8d, + 0x04,0x20,0x0c,0xb3,0x86,0xc8,0xc4,0xc9,0x3e,0xce,0xad,0x4d,0x40,0x4c,0x46,0xe7,0xb1,0x5f,0x32,0x22,0x91,0x7f,0x5b,0x93,0x72,0x79,0x3c,0xc7,0x80,0x41,0x16,0x73,0x2c,0xdd,0x20,0x8d, + 0x04,0x20,0x0d,0x34,0x17,0x93,0x74,0x16,0x2d,0x2f,0x14,0x39,0x22,0x80,0x36,0x84,0xa3,0xba,0x61,0xcc,0xee,0x70,0xbc,0x8c,0xf6,0xd5,0x9b,0xf3,0x4b,0xd9,0x92,0x5b,0xa6,0xfe,0x20,0x8d, + 0x04,0x20,0x0d,0x37,0x73,0x31,0x21,0x9a,0x8a,0xa5,0x75,0x30,0xc6,0xc4,0xa1,0xa2,0xb6,0x29,0xa8,0x52,0x15,0xe2,0xe6,0xf0,0x2c,0xcb,0x2f,0x8a,0x0c,0x66,0xaa,0x41,0x20,0x1f,0x20,0x8d, + 0x04,0x20,0x0d,0xfd,0x9f,0x1d,0x4a,0xa7,0x55,0x28,0x43,0xde,0x2d,0x21,0x13,0x1c,0x20,0xcf,0x02,0xab,0x6a,0x14,0xe5,0x11,0x5e,0x42,0xe0,0x49,0x59,0x06,0xc4,0xa4,0x4c,0xd8,0x20,0x8d, + 0x04,0x20,0x0e,0x43,0xfe,0x51,0xb2,0x35,0xe9,0x5d,0xda,0x2a,0x4e,0x48,0x4e,0x36,0xe4,0xfa,0x9a,0xc2,0xf3,0x80,0xdc,0xc3,0x69,0x17,0xab,0x4d,0x4a,0x24,0x7c,0xe9,0x40,0xd8,0x20,0x8d, + 0x04,0x20,0x0e,0x5b,0x60,0x33,0x7f,0xa1,0xde,0x4a,0x38,0x62,0x9e,0x9e,0xfb,0xa9,0xc4,0xe1,0xfd,0x79,0x6f,0xf5,0x48,0x7d,0xc1,0x3c,0x3a,0xd0,0x10,0x02,0x9f,0xfd,0xa8,0x03,0x20,0x8d, + 0x04,0x20,0x17,0xb9,0x71,0x0a,0x62,0xbf,0xc0,0x45,0xa7,0xb8,0xc6,0xa5,0x70,0x7d,0x28,0x6b,0xd1,0xfb,0x64,0xf9,0xcd,0x47,0x81,0xc7,0xa0,0x82,0xd7,0x9a,0x68,0xb9,0x35,0x0a,0x20,0x8d, + 0x04,0x20,0x17,0x8a,0xe5,0x69,0xa6,0xee,0x76,0x9a,0xab,0x61,0x0d,0x12,0xd7,0xc6,0x5a,0x12,0xf4,0x79,0xac,0xaf,0x3c,0xfa,0x71,0x92,0x67,0x6a,0x94,0x5c,0x14,0xe6,0xf5,0x91,0x20,0x8d, + 0x04,0x20,0x17,0x95,0xb4,0x73,0x5c,0xee,0x3c,0x77,0x36,0x32,0xb9,0x44,0xcd,0x2f,0xa6,0x13,0x5b,0xd8,0xac,0x40,0x9d,0xf3,0x8c,0x50,0x25,0xda,0xa8,0x13,0xe4,0x75,0x35,0xdc,0x20,0x8d, + 0x04,0x20,0x10,0x4c,0xf1,0xdd,0xd1,0x21,0x34,0x43,0x73,0x77,0x60,0xf9,0x2c,0xb8,0x00,0xb4,0xa6,0x1b,0xc2,0xae,0xea,0x83,0xad,0xab,0x1d,0x09,0x33,0xa7,0xc3,0xfd,0x57,0xea,0x20,0x8d, + 0x04,0x20,0x10,0x5b,0x4b,0xd1,0xf0,0x82,0xf9,0xab,0x10,0xb9,0x93,0xd2,0x4e,0xda,0x0a,0x00,0x28,0xad,0x31,0x5e,0x7c,0xe0,0x1f,0x28,0xeb,0x27,0x39,0xb0,0x4e,0x72,0x03,0x5b,0x20,0x8d, + 0x04,0x20,0x10,0xac,0x79,0x2d,0x92,0x34,0x96,0x09,0x8f,0x1b,0xfc,0xe5,0x06,0xff,0xae,0x4d,0xe7,0x62,0x1b,0x60,0xf7,0x9e,0x75,0xdd,0x9c,0x77,0xe5,0xb3,0x78,0x38,0x4f,0x2f,0x20,0x8d, + 0x04,0x20,0x10,0xad,0x47,0xb2,0x8f,0xff,0xa1,0x04,0xb2,0x79,0xa2,0x2b,0xb3,0xbd,0x1b,0xa7,0xc0,0xa8,0x4c,0x9b,0x1f,0xad,0x9a,0x54,0x84,0xec,0x9e,0x4e,0x2c,0x43,0xc9,0x16,0x20,0x8d, + 0x04,0x20,0x11,0x4c,0xe2,0x7b,0x43,0xff,0x9a,0xde,0x78,0xfa,0x1b,0xff,0x49,0xf1,0xc8,0x30,0x77,0xd5,0x29,0xe7,0x47,0x4c,0x7c,0xb7,0xe7,0x64,0xae,0xbc,0x76,0x05,0x42,0x56,0x20,0x8d, + 0x04,0x20,0x14,0x43,0x0a,0x6d,0xb2,0xa0,0x0d,0xfc,0x6c,0xb3,0xc6,0xa5,0xa7,0x79,0x47,0x35,0xd7,0xc5,0x76,0xc5,0x0b,0x7c,0xc3,0x53,0x1a,0x55,0x46,0x1c,0x06,0xb3,0x0c,0x32,0x20,0x8d, + 0x04,0x20,0x14,0x60,0x4e,0x8d,0x1d,0x7d,0x15,0xa2,0x1d,0x28,0xb6,0xa3,0x4a,0x40,0x10,0x61,0x0a,0x2f,0x1e,0xd1,0xc3,0xba,0x27,0xa0,0x58,0xc0,0xd5,0x72,0x28,0x61,0xcb,0x5d,0x20,0x8d, + 0x04,0x20,0x14,0xf4,0x89,0x7f,0xe6,0xc4,0x08,0x25,0x3e,0x14,0xda,0x8e,0x3a,0xe6,0xb0,0xe8,0x59,0xb1,0x3a,0xc8,0xba,0x2e,0x35,0x98,0x03,0x01,0x55,0x51,0xe4,0x95,0x45,0xb1,0x20,0x8d, + 0x04,0x20,0x14,0xe6,0xef,0xed,0x0e,0x15,0x4c,0x95,0x46,0x9e,0x45,0xbd,0xa0,0x78,0xf1,0x27,0x17,0x40,0xc3,0x4a,0x5d,0x28,0xfc,0x13,0x43,0x6b,0xf9,0x10,0x5e,0x3a,0xa4,0x4d,0x20,0x8d, + 0x04,0x20,0x16,0x39,0x49,0xe0,0x6c,0x0d,0x64,0xfc,0x94,0x39,0xd5,0x46,0xbc,0xd2,0x97,0x56,0x31,0x93,0xa6,0x94,0x64,0x41,0xf5,0x2d,0x5e,0x72,0x50,0xf9,0xd7,0xf8,0xf0,0xa8,0x20,0x8d, + 0x04,0x20,0x1e,0x98,0xb3,0xb9,0x89,0x0c,0x13,0x7a,0xf9,0x8d,0xf5,0xef,0xbb,0xa2,0x3d,0xbf,0x7a,0x98,0xb2,0xfb,0xfb,0xf3,0xa9,0x59,0x9d,0x66,0xc1,0x11,0x4d,0xf3,0xfb,0x75,0x20,0x8d, + 0x04,0x20,0x1f,0x00,0x23,0x5d,0xd2,0xce,0x19,0x64,0xc5,0x29,0x16,0x04,0xb3,0xcf,0x59,0xcc,0x39,0xf7,0xb9,0x87,0x05,0x64,0x02,0xdd,0x04,0x8d,0x48,0x98,0x63,0x28,0x78,0xfb,0x20,0x8d, + 0x04,0x20,0x1f,0x04,0xb1,0x3f,0x2b,0xf7,0x9d,0x66,0x7e,0x7b,0x7b,0x3e,0x2c,0x87,0xf9,0xc9,0xa5,0x02,0x15,0xe3,0x3f,0x5e,0xb8,0xb4,0xb8,0x78,0x41,0xf2,0xe9,0x88,0x51,0x6b,0x20,0x8d, + 0x04,0x20,0x1f,0x12,0xd4,0x33,0xce,0x97,0xc3,0x23,0xc5,0x26,0x79,0x48,0x29,0x1b,0x88,0xd1,0xb7,0x59,0xf0,0x19,0xc0,0xa5,0x2a,0x40,0x07,0x45,0x1f,0x21,0xfc,0xf6,0x9a,0x5e,0x20,0x8d, + 0x04,0x20,0x1f,0x64,0x3f,0x61,0x14,0xb4,0xfb,0x19,0xcb,0xd7,0x31,0xf1,0x64,0x1c,0xd7,0x78,0x4a,0x83,0xfe,0x22,0x8d,0x75,0x40,0xcf,0xa6,0x3f,0x9a,0x5f,0x7c,0x65,0xbc,0x3a,0x20,0x8d, + 0x04,0x20,0x1f,0xdb,0x25,0xc0,0x99,0xd2,0xb9,0x13,0xd6,0xe1,0x36,0x95,0x72,0x0d,0x79,0xc3,0xb1,0x3d,0x1b,0x6d,0xa9,0x16,0x26,0xa3,0x06,0xfd,0xe8,0x2d,0x15,0x03,0x99,0xa5,0x20,0x8d, + 0x04,0x20,0x18,0x18,0x43,0x64,0x4e,0x30,0xdf,0xd5,0xd7,0x0f,0x46,0x3a,0xfe,0x95,0xde,0x59,0x5c,0xce,0xcb,0x85,0xad,0x2c,0x0d,0x59,0x2b,0x66,0x84,0xc9,0x34,0xe7,0x78,0x80,0x20,0x8d, + 0x04,0x20,0x18,0x7a,0x09,0xcb,0x17,0xdb,0x7d,0xb1,0xe0,0x5d,0xa3,0xe8,0x9a,0x32,0x4f,0xd0,0x7a,0x94,0x1c,0x05,0xbb,0xed,0xc9,0xbf,0x8a,0xe3,0xda,0xb6,0x04,0x07,0x42,0xd0,0x20,0x8d, + 0x04,0x20,0x19,0x89,0x98,0x9f,0x6a,0x28,0x9a,0x69,0x56,0x85,0xbf,0x57,0x17,0xf9,0xae,0x18,0xa4,0x7c,0x68,0xb2,0xdd,0xb8,0xb9,0x81,0x76,0x9e,0x89,0x38,0xf2,0x15,0xae,0x17,0x20,0x8d, + 0x04,0x20,0x19,0xd0,0xf5,0x70,0xfd,0xbc,0x80,0xdd,0x25,0x29,0x28,0x91,0xa7,0xad,0x2d,0xc6,0x36,0x87,0xef,0x93,0x65,0x33,0x89,0xea,0x27,0xfe,0x56,0xc2,0x67,0x23,0x14,0x09,0x20,0x8d, + 0x04,0x20,0x1a,0x49,0xb6,0xba,0xab,0x76,0x59,0xd1,0x11,0x58,0xf3,0x5e,0x19,0xfe,0x09,0x69,0x78,0x46,0x51,0x1e,0x2f,0x30,0x6b,0x14,0xe7,0xc7,0x7e,0x31,0xa8,0x12,0xae,0x3f,0x20,0x8d, + 0x04,0x20,0x1b,0x51,0xa8,0xa6,0xb0,0x27,0x76,0x67,0xb0,0x71,0xde,0x14,0x76,0xca,0x88,0x90,0x93,0x8f,0x77,0xa9,0xf2,0x23,0xde,0xd0,0x86,0x19,0x90,0xe3,0x2a,0xd9,0xf8,0x86,0x20,0x8d, + 0x04,0x20,0x1b,0x71,0x5c,0x1a,0x1a,0x1b,0x2a,0x4a,0xe7,0xc0,0x48,0x8b,0xb0,0x48,0x7b,0x1f,0x45,0x06,0x3c,0x95,0x77,0x39,0x0c,0x4f,0x6a,0x67,0x7e,0xdc,0x4b,0x13,0xff,0x62,0x20,0x8d, + 0x04,0x20,0x1c,0x00,0x4c,0x1c,0xbd,0xaf,0x39,0xfd,0x0f,0x06,0x00,0x62,0x01,0x2f,0x2d,0x29,0xe7,0x8c,0x4e,0xd8,0xe1,0xc7,0x58,0xa6,0x00,0x8d,0x90,0x9f,0xc2,0x9b,0xff,0x64,0x20,0x8d, + 0x04,0x20,0x1d,0x12,0x22,0x94,0x19,0x1c,0xe6,0x4b,0x4b,0xe1,0x24,0x5b,0x4a,0xfe,0xc4,0x75,0xf6,0x09,0x29,0x6d,0xb5,0x33,0x09,0x0d,0xd8,0xcc,0x2f,0x8d,0xad,0xc6,0x2d,0x1f,0x20,0x8d, + 0x04,0x20,0x1d,0x78,0x39,0xe7,0xb9,0xa6,0xe6,0x4d,0x9b,0x42,0x14,0x73,0xb6,0xc4,0xc2,0x2e,0x5d,0x98,0x12,0x46,0x61,0xa6,0x1e,0x81,0xd9,0x3a,0x8c,0xe6,0xc2,0xc6,0xd8,0xd0,0x20,0x8d, + 0x04,0x20,0x1d,0x73,0x6c,0x06,0x2a,0x16,0x1b,0x92,0xa4,0xdc,0x4b,0xc4,0xa9,0xf5,0x54,0x69,0x87,0xc6,0xca,0x01,0xb6,0x17,0x23,0x85,0x64,0x95,0x2d,0x92,0xae,0xae,0x13,0x39,0x20,0x8d, + 0x04,0x20,0x1d,0xd4,0xac,0x4e,0x01,0xaa,0xf8,0x73,0xd8,0xfd,0x47,0xa9,0xff,0xc6,0xfa,0x8a,0x90,0x20,0x53,0xc3,0xc6,0x0d,0x3f,0x5c,0x96,0x36,0x36,0x07,0x85,0xcb,0xb7,0xad,0x20,0x8d, + 0x04,0x20,0x1e,0x4e,0x78,0x3c,0x93,0xae,0x21,0xd3,0x7a,0xe7,0x36,0x3e,0x65,0x52,0xc4,0xc6,0xb6,0x39,0x3b,0xd2,0x17,0xd2,0x1e,0xa2,0x2b,0x11,0x65,0xf1,0x04,0xa0,0x20,0xb6,0x20,0x8d, + 0x04,0x20,0x26,0xbc,0x0e,0x05,0xf7,0x42,0x68,0x7e,0x35,0x84,0x83,0x3a,0x6f,0x0f,0x48,0x8f,0x8f,0xa1,0x5b,0x16,0xfa,0x3e,0xd8,0xba,0xf8,0xfc,0xb9,0x87,0x68,0x8e,0x37,0x2b,0x20,0x8d, + 0x04,0x20,0x27,0x0e,0x30,0x39,0x8c,0x63,0x39,0x8f,0x43,0xda,0x37,0x53,0x53,0xf9,0x93,0x13,0xa7,0xba,0x9e,0x09,0xe6,0xac,0xc7,0x3d,0x9b,0xd0,0x69,0xb2,0x4e,0x23,0x77,0x6a,0x20,0x8d, + 0x04,0x20,0x27,0x59,0x90,0xe4,0x75,0x7b,0x4d,0x74,0xa8,0x25,0x87,0xfc,0x71,0xbc,0xb3,0x46,0xec,0x88,0xda,0x04,0xcd,0x0d,0x00,0x2a,0x4f,0x88,0xc5,0x30,0xed,0xfb,0xa3,0x6d,0x20,0x8d, + 0x04,0x20,0x20,0x21,0x7c,0x51,0x38,0x64,0x33,0x60,0x33,0x05,0xec,0x26,0x10,0xb6,0xb2,0x9d,0x39,0x23,0x6c,0x35,0xed,0x18,0xf5,0x66,0xe9,0x0c,0x81,0x70,0x33,0x25,0xa7,0xae,0x20,0x8d, + 0x04,0x20,0x20,0xaf,0xc7,0x97,0xe6,0xb0,0xde,0xb5,0x80,0xbb,0x96,0x7c,0xd9,0x10,0x3c,0xd3,0x92,0x67,0xec,0x53,0x77,0x6e,0xee,0xa7,0xd5,0x6f,0xc0,0x5a,0x72,0x4f,0x10,0xa8,0x20,0x8d, + 0x04,0x20,0x20,0xf8,0x86,0x43,0x9c,0xe2,0x17,0xd7,0xbf,0xa6,0x54,0xb7,0x84,0x30,0xc7,0xda,0x7f,0x5d,0xd4,0xff,0x86,0x07,0x9c,0x65,0x52,0xad,0x75,0xad,0x10,0x34,0x1b,0xb1,0x20,0x8d, + 0x04,0x20,0x21,0xc9,0x06,0x3a,0x42,0xce,0x93,0x00,0x7b,0x61,0xe7,0xf5,0xde,0xbd,0x4a,0x6a,0xfd,0xde,0xdd,0x49,0x09,0xac,0x77,0x92,0x88,0x8e,0x0b,0x14,0xf8,0xea,0x2f,0x2b,0x20,0x8d, + 0x04,0x20,0x22,0x31,0x6a,0x5c,0xfa,0x3d,0x8e,0xad,0x40,0x0b,0x2d,0x61,0x32,0xd5,0x3c,0x5a,0x68,0x4c,0xed,0xda,0x1f,0x06,0x48,0x31,0xd6,0x00,0x44,0x8e,0x3b,0x64,0xab,0x0c,0x20,0x8d, + 0x04,0x20,0x22,0x4c,0x42,0x2d,0x8c,0xf6,0xb0,0x64,0x7a,0x34,0xc3,0x55,0x99,0xf6,0x71,0x3f,0xf1,0x2d,0x0a,0x46,0xaa,0xaf,0x91,0x4f,0x90,0x7c,0xd7,0x68,0x08,0x6d,0x7c,0x11,0x20,0x8d, + 0x04,0x20,0x22,0x63,0x85,0x60,0x89,0x55,0x3a,0x35,0xb2,0x99,0xf3,0x9b,0xa7,0xa3,0xf8,0x92,0x4d,0xe1,0x75,0xf4,0xa3,0xac,0xd0,0xe2,0x76,0x64,0x3e,0xca,0xdb,0xd7,0xc4,0x03,0x20,0x8d, + 0x04,0x20,0x23,0x45,0xc8,0x5d,0xd8,0x70,0x1f,0xd6,0x8e,0x3f,0x1d,0x09,0x56,0x24,0xf5,0xd6,0x44,0xf7,0x47,0x62,0xdf,0x3f,0xdd,0x6f,0x00,0x2b,0xbc,0x29,0xf2,0x79,0x4f,0x3b,0x20,0x8d, + 0x04,0x20,0x24,0xf4,0x92,0xf9,0xa4,0x51,0x19,0xbb,0xf7,0x73,0xc6,0x44,0x72,0x41,0xdf,0x04,0x7f,0xbb,0x1b,0x81,0xc6,0xe8,0x2a,0xe7,0x09,0x2a,0xd1,0x45,0xff,0x7d,0xf8,0x88,0x20,0x8d, + 0x04,0x20,0x24,0xc1,0xdf,0x81,0x6a,0x9b,0x39,0x93,0xd4,0xfb,0x05,0x5d,0x1d,0x27,0xa7,0x09,0xc6,0x02,0x2c,0x3b,0x8f,0xd3,0x8d,0x1d,0x0f,0x88,0x0a,0x59,0x61,0xfe,0x0e,0x5d,0x20,0x8d, + 0x04,0x20,0x24,0xc4,0x00,0xe1,0x96,0xa3,0x54,0xaa,0xb6,0xfc,0x2d,0x8c,0x71,0x73,0xf0,0x2e,0xa0,0x5e,0x22,0xfb,0x4c,0xf2,0x53,0xbf,0x86,0x71,0xf0,0x71,0x0d,0x01,0x37,0xa4,0x20,0x8d, + 0x04,0x20,0x24,0xd3,0xab,0x6f,0x21,0xc7,0xce,0x50,0x2c,0x78,0xdf,0x07,0x2a,0x4e,0x75,0x4c,0xd0,0xcc,0x58,0xf5,0x82,0x51,0x35,0x6e,0xdf,0xed,0x0a,0xf8,0xca,0x04,0xe7,0xeb,0x20,0x8d, + 0x04,0x20,0x28,0x69,0x50,0xb3,0x8a,0x22,0x83,0xbb,0x64,0x9e,0xbb,0x84,0x80,0xa5,0x57,0x6a,0xb0,0x9d,0x77,0xee,0x9f,0x87,0xdd,0x6f,0x9a,0x0e,0x6b,0x59,0x72,0x99,0x56,0xb0,0x20,0x8d, + 0x04,0x20,0x2a,0x0d,0xf9,0xdd,0xcb,0x2e,0xe6,0x78,0xb8,0x93,0x54,0x65,0xac,0x84,0xe4,0xaf,0x3d,0x18,0x6a,0x03,0xff,0x73,0x1f,0xbc,0x6d,0x61,0x2c,0x66,0x99,0x82,0x91,0x29,0x20,0x8d, + 0x04,0x20,0x2a,0xcc,0x41,0xe0,0xec,0x74,0x58,0x3c,0x46,0xf0,0x98,0x31,0x9f,0x75,0x4f,0x61,0xad,0xc0,0xb0,0xcf,0x8f,0xa5,0x32,0x1b,0x91,0xf9,0xd2,0x8b,0xb5,0x2e,0xb0,0xc0,0x20,0x8d, + 0x04,0x20,0x2a,0xd0,0xe7,0x67,0xea,0x87,0x96,0x9f,0x12,0x5c,0xea,0x4d,0xbd,0x37,0xde,0x4c,0x3c,0xcc,0x2d,0x10,0x0b,0x72,0x6d,0x23,0x14,0x95,0x1b,0xd1,0xcf,0xb3,0xc5,0xcd,0x20,0x8d, + 0x04,0x20,0x2d,0xb0,0xa1,0x7d,0xd6,0xf2,0x38,0xed,0x33,0xf5,0xc1,0x98,0x62,0x8d,0x44,0xae,0x21,0x5b,0x68,0xd2,0x78,0xcb,0xe5,0xde,0x25,0x38,0xc8,0xc0,0x2c,0x3b,0xe0,0xc2,0x20,0x8d, + 0x04,0x20,0x36,0xe3,0x9a,0x1a,0x7c,0x0f,0x23,0x5d,0x62,0x1a,0xf7,0x92,0x40,0x61,0x55,0x0d,0x7f,0xe6,0xb6,0x08,0xf7,0xf7,0xd6,0x98,0xee,0xa8,0xa4,0xda,0xe2,0x16,0x61,0x5d,0x20,0x8d, + 0x04,0x20,0x37,0x1c,0x98,0x83,0x68,0x6b,0x38,0xbd,0x75,0xff,0xca,0xf5,0xed,0xd7,0x3a,0x5e,0x75,0x0a,0x16,0xd3,0x4d,0x96,0x43,0xdb,0x25,0x2a,0x37,0x52,0xc6,0x84,0x2e,0x94,0x20,0x8d, + 0x04,0x20,0x37,0x43,0x20,0x60,0x5b,0xbe,0xb6,0x55,0x2a,0x52,0x7c,0xd8,0xb5,0xd3,0x50,0x6f,0x14,0x6f,0xa5,0x4f,0x12,0xf8,0x5b,0xf4,0x83,0x48,0x48,0x27,0x27,0x0c,0x45,0x14,0x20,0x8d, + 0x04,0x20,0x37,0x63,0xaa,0x0c,0x1e,0xb1,0xe4,0x69,0x7b,0xb8,0x2f,0xeb,0xfc,0x3a,0x0c,0x83,0x94,0x15,0x41,0x16,0xa9,0xac,0x94,0x18,0x89,0xf7,0x31,0x25,0x2b,0x72,0x52,0xc9,0x20,0x8d, + 0x04,0x20,0x37,0x69,0x4a,0xa0,0x66,0x55,0x46,0x5d,0x09,0x8e,0x22,0x8c,0x6c,0x85,0x05,0xc8,0x5c,0x93,0xfc,0x6d,0xff,0x49,0xfe,0xe3,0xf5,0xd2,0x0d,0xd4,0x95,0x6a,0xc2,0x99,0x20,0x8d, + 0x04,0x20,0x37,0xec,0xd7,0x65,0xa3,0x8a,0x24,0x1a,0x53,0xde,0xe5,0xf2,0x1b,0x5b,0x34,0xa2,0x3e,0x1e,0xdd,0x54,0xc9,0x49,0x6d,0xdd,0x85,0x62,0xc7,0xdc,0x5b,0xd8,0x7c,0xad,0x20,0x8d, + 0x04,0x20,0x31,0x7d,0x5c,0x40,0x99,0x74,0xb5,0x2e,0xe9,0x57,0xb6,0x76,0x89,0xbd,0x80,0xed,0x9a,0x1f,0x6d,0xcb,0xfc,0x0d,0xb5,0x52,0xd7,0x37,0x77,0xf9,0x11,0x33,0xa7,0x52,0x20,0x8d, + 0x04,0x20,0x31,0x5d,0x02,0xb7,0x95,0x5b,0x72,0xae,0x38,0x51,0xb1,0x0d,0x08,0x99,0x99,0x61,0x62,0x8b,0x47,0x26,0x6d,0xfe,0x91,0xbd,0x0d,0x82,0xb0,0x14,0x0e,0x78,0x9f,0xd4,0x20,0x8d, + 0x04,0x20,0x32,0x8d,0x41,0xec,0x0b,0x85,0xbf,0x58,0x62,0xd3,0x05,0xa5,0x29,0x3a,0xac,0xaa,0x8f,0x25,0xc2,0x3c,0xb9,0x1b,0x16,0x44,0xde,0x73,0x3c,0x85,0xa6,0x81,0xeb,0xb4,0x20,0x8d, + 0x04,0x20,0x32,0xaa,0x63,0x18,0xbd,0x35,0x20,0x2c,0x1b,0x16,0x59,0x1a,0xc2,0x75,0x8b,0xf8,0xcd,0x35,0x3d,0x2c,0x0c,0xc8,0xc9,0x05,0x76,0x19,0x2f,0xe4,0xd7,0xaa,0xab,0xc5,0x20,0x8d, + 0x04,0x20,0x32,0xdf,0xdc,0xef,0xc9,0xa6,0x79,0x92,0x9f,0xf3,0x75,0x13,0xd9,0x84,0x47,0x7c,0x44,0x50,0x8d,0xf3,0x19,0xc4,0x8f,0xc8,0xf8,0xc2,0x18,0x3f,0x04,0x29,0x58,0x90,0x20,0x8d, + 0x04,0x20,0x33,0xa6,0x95,0x65,0x35,0xa3,0x78,0xfd,0x92,0x60,0x2e,0xf6,0xfd,0x7a,0xab,0xb4,0xd8,0xb1,0x13,0x13,0xc6,0x1b,0x20,0x99,0x0a,0x68,0x79,0x38,0x83,0x72,0x6a,0xf5,0x20,0x8d, + 0x04,0x20,0x33,0xe6,0x2c,0x65,0x2a,0x86,0x67,0xdf,0x47,0x80,0xe6,0xc9,0x13,0x22,0xe8,0x5a,0x4e,0x40,0xe3,0xbb,0x9f,0x6f,0x30,0xfc,0x62,0x85,0xfc,0x72,0xa9,0xf3,0xe9,0x7d,0x20,0x8d, + 0x04,0x20,0x33,0xf3,0x67,0xe5,0x06,0x2c,0x4e,0xac,0x1c,0x5b,0x5f,0x64,0xb5,0xbb,0x5c,0x1d,0x2e,0x0f,0x3a,0x92,0x6a,0xba,0xe8,0xf3,0x89,0x94,0x66,0x34,0xeb,0x83,0x94,0xdc,0x20,0x8d, + 0x04,0x20,0x34,0x05,0x09,0x3f,0xca,0x98,0x18,0xad,0x58,0x03,0xfc,0xb1,0xa8,0x53,0x12,0xba,0x2a,0x6a,0x6c,0xc9,0xba,0x27,0x7f,0xaa,0x2f,0xb1,0xa4,0x7d,0xfc,0x52,0x5a,0xef,0x20,0x8d, + 0x04,0x20,0x34,0x55,0x1a,0x64,0x20,0xe7,0x22,0xce,0xb3,0x86,0x56,0x08,0x94,0xb7,0x7d,0xb5,0xc2,0xbb,0xba,0x5c,0x08,0x35,0x59,0x23,0xe3,0x1e,0x53,0x40,0xf3,0x78,0x1b,0x62,0x20,0x8d, + 0x04,0x20,0x35,0xf6,0x79,0x62,0xe5,0xd2,0x72,0xd4,0x1c,0xcf,0x8c,0xd4,0x03,0x41,0x2d,0x7d,0x84,0xfe,0x1d,0x7c,0x57,0x54,0x32,0x77,0xa6,0x76,0xab,0x32,0x8b,0x27,0xd4,0xf5,0x20,0x8d, + 0x04,0x20,0x36,0x66,0x4d,0x9f,0xf7,0xec,0x13,0x91,0x87,0x08,0x0c,0x5f,0x12,0x97,0x25,0xd3,0x32,0xc3,0xb1,0x47,0xce,0x19,0x0f,0xe6,0x5c,0x54,0x8d,0x69,0x4c,0x77,0x98,0xdf,0x20,0x8d, + 0x04,0x20,0x3f,0xd4,0x58,0x1b,0xcb,0x2f,0xeb,0xd1,0xe2,0xd2,0xb0,0xf2,0xa0,0x68,0x84,0x78,0xf0,0x88,0x22,0x20,0xf3,0x00,0xc4,0xf9,0x7f,0x88,0x33,0x4b,0x91,0x2b,0x93,0xdc,0x20,0x8d, + 0x04,0x20,0x3f,0xe2,0xe8,0xcb,0xb9,0x41,0xce,0x63,0x8b,0x13,0x8f,0x96,0x7f,0xd8,0xcc,0x43,0x80,0x79,0xe8,0x34,0x0c,0x97,0x25,0x23,0x8e,0xdb,0x41,0x2e,0x2d,0xb0,0xb4,0x38,0x20,0x8d, + 0x04,0x20,0x38,0x0c,0xa1,0xe8,0xd0,0xdd,0x7c,0x0e,0x69,0x71,0x02,0xc2,0xf6,0x1d,0xe2,0x4a,0x56,0x62,0xc3,0xcb,0x20,0xc8,0x62,0x6c,0x01,0x2b,0xed,0x54,0xf5,0x6d,0xfe,0x07,0x20,0x8d, + 0x04,0x20,0x38,0x15,0x46,0x7f,0x14,0xc7,0x20,0xf4,0xe6,0x9f,0x16,0x70,0xbe,0xa7,0x4d,0x6a,0xd1,0xd6,0x5b,0x65,0xbe,0x8b,0x74,0x8a,0xc5,0x4c,0xb6,0x68,0xf6,0xaa,0x32,0xe2,0x20,0x8d, + 0x04,0x20,0x38,0x94,0x67,0xfc,0x12,0xd2,0x88,0xf3,0xb9,0xd2,0x74,0x09,0xcd,0x57,0x48,0x0c,0xfa,0xed,0xa8,0xc9,0x26,0x22,0x61,0x05,0x0f,0x42,0xee,0xda,0x1e,0x11,0x3d,0xd8,0x20,0x8d, + 0x04,0x20,0x39,0xbd,0x2c,0x5f,0x8e,0xc5,0x62,0x28,0x82,0xf8,0x9c,0x30,0xc4,0xe8,0x2b,0x69,0x9f,0x64,0xa3,0xb1,0x39,0x42,0x96,0x99,0x6e,0xfc,0xeb,0x92,0xbd,0x82,0xec,0x9c,0x20,0x8d, + 0x04,0x20,0x39,0xfa,0x3f,0x19,0x20,0xd6,0xce,0xbb,0x32,0x71,0x7b,0x2c,0x11,0xff,0x2d,0xd7,0xbd,0x98,0xbb,0x9b,0x3e,0x6e,0x97,0xd8,0x1a,0xdb,0xf9,0x76,0xc3,0xdc,0xb2,0x02,0x20,0x8d, + 0x04,0x20,0x3a,0x02,0x60,0xcf,0xde,0x38,0x79,0x3a,0xb0,0xea,0x66,0x33,0x65,0xdd,0x11,0x1b,0x1e,0xa3,0x68,0x00,0xe7,0xaf,0x96,0xb6,0x56,0xb4,0xa9,0x8d,0xdb,0x85,0x72,0x27,0x20,0x8d, + 0x04,0x20,0x3a,0xf4,0x57,0x45,0xb6,0x84,0x88,0x25,0x19,0x4a,0x83,0xef,0xa8,0xea,0x3a,0xd3,0x65,0x31,0x9b,0x9d,0x03,0x31,0x35,0x15,0x45,0x28,0x8c,0xd5,0x9b,0x00,0xc6,0x1c,0x20,0x8d, + 0x04,0x20,0x3a,0xfb,0x9e,0xf9,0x77,0xfe,0x71,0x0e,0xe6,0xd0,0xc7,0xcf,0x3b,0x7a,0xdf,0x92,0x82,0x1d,0xac,0xd1,0x4e,0xc6,0x65,0xa7,0x9e,0x1e,0x1b,0x2c,0x19,0xa2,0x97,0xf6,0x20,0x8d, + 0x04,0x20,0x3a,0xd0,0xd6,0xb5,0x34,0x93,0xa1,0x91,0x76,0x60,0xa4,0x62,0x5f,0xb8,0x9a,0x56,0xd9,0xbd,0xc4,0x9e,0xf0,0x96,0xd0,0xbd,0x8c,0x27,0x50,0xb1,0xec,0x44,0x08,0xa6,0x20,0x8d, + 0x04,0x20,0x3a,0xe4,0x83,0x96,0x98,0x01,0x5e,0xeb,0x88,0xf2,0x89,0xd6,0x7e,0x58,0x6a,0x18,0x3f,0xf4,0x57,0x96,0x63,0xdb,0x9d,0x48,0xce,0x2b,0x9b,0x2b,0x43,0x8a,0x6f,0x9b,0x20,0x8d, + 0x04,0x20,0x3b,0x1b,0x5c,0xa7,0xdf,0x84,0xf0,0x68,0x04,0x9c,0xa5,0x17,0x36,0x78,0xd9,0x3b,0xec,0x6f,0x84,0x7d,0x05,0x2d,0x6e,0x3d,0x11,0x01,0x1a,0xc0,0xc1,0xfd,0xe3,0xd7,0x20,0x8d, + 0x04,0x20,0x3b,0xd0,0x45,0x49,0x25,0x13,0x42,0x0e,0x26,0x5a,0x88,0xa8,0x5d,0x8d,0x7b,0x41,0xa7,0xa6,0xa6,0x4c,0xef,0x33,0x32,0xf1,0x14,0xbf,0xd2,0x78,0xc7,0x99,0x61,0xa0,0x20,0x8d, + 0x04,0x20,0x3c,0x2a,0x3b,0xf9,0xb8,0xe3,0xfc,0xb8,0xd0,0x20,0xfd,0x96,0x00,0x60,0x4d,0x1b,0x08,0xdc,0xe0,0xc2,0xdb,0x5a,0x9b,0x24,0x7f,0x59,0xca,0xd6,0xaa,0x99,0x6c,0x51,0x20,0x8d, + 0x04,0x20,0x3c,0x59,0x5b,0x47,0xf7,0xed,0x46,0x77,0x94,0x94,0x77,0x3c,0x0d,0x47,0x1b,0x34,0x59,0x3d,0x32,0x8b,0xf8,0x3f,0x13,0xa5,0xe0,0x04,0x3c,0x44,0x36,0x4c,0x8d,0x1b,0x20,0x8d, + 0x04,0x20,0x3c,0x93,0x31,0xb5,0x73,0xf7,0xfd,0x42,0xa8,0xc0,0x97,0x9d,0x95,0x46,0xc2,0x4c,0x40,0x6d,0x78,0x16,0x3a,0x99,0xfb,0x91,0x2e,0xaf,0x1b,0x4f,0xff,0xcb,0x56,0x96,0x20,0x8d, + 0x04,0x20,0x3d,0x57,0xd1,0xf4,0xc4,0x96,0x7f,0x58,0x7a,0x98,0x54,0xc0,0xb4,0x33,0x78,0x7d,0xa0,0x51,0xe2,0x71,0x39,0xb4,0xd5,0xc2,0xfb,0xe6,0x21,0xaa,0x7b,0xa7,0x35,0x43,0x20,0x8d, + 0x04,0x20,0x3d,0x5f,0xd8,0x93,0x06,0x5e,0x72,0x1c,0x64,0xa4,0x99,0xb5,0x64,0x05,0xf9,0xdc,0x95,0xb1,0x99,0xe8,0x47,0x38,0x17,0xc0,0xd9,0xa2,0xd5,0xb4,0x7f,0xbb,0x54,0x13,0x20,0x8d, + 0x04,0x20,0x3e,0x18,0x77,0xda,0x16,0x72,0x38,0x09,0xdb,0x4f,0x4e,0x95,0x05,0xab,0x2f,0xce,0x31,0xc7,0x90,0xc9,0xf9,0x3b,0x34,0x4f,0x03,0x8a,0xc8,0xd7,0x9b,0xf2,0x3e,0xdc,0x20,0x8d, + 0x04,0x20,0x3e,0x30,0x63,0x69,0x74,0xc0,0x7b,0xde,0x53,0xa3,0x94,0xe9,0xbc,0x5d,0x3b,0x02,0x94,0xe7,0x03,0x19,0x1d,0x34,0x8b,0x5f,0x7e,0xc6,0x87,0xbb,0x23,0x11,0x05,0x8a,0x20,0x8d, + 0x04,0x20,0x3e,0x4e,0xca,0xb2,0x8f,0xa9,0x84,0x0b,0x04,0x52,0xee,0x20,0x42,0x26,0x68,0xd2,0x17,0xdb,0xfb,0xd1,0xb4,0xd6,0x5f,0x01,0xeb,0x8d,0x8f,0x7d,0x04,0x86,0xb1,0x4e,0x20,0x8d, + 0x04,0x20,0x46,0x89,0xce,0x47,0xbd,0xa7,0x1c,0x10,0xce,0xa9,0x87,0xdf,0xd2,0x0c,0xf1,0x69,0xed,0x57,0x7a,0xf7,0xa0,0xcf,0x0e,0x41,0x57,0xf0,0xef,0x47,0x88,0x6a,0xab,0x9b,0x20,0x8d, + 0x04,0x20,0x47,0x39,0x55,0xea,0x71,0x08,0x1f,0x1e,0xf1,0xc2,0x0c,0x7b,0x90,0x40,0xe2,0x9d,0x00,0x15,0x2d,0xb4,0x34,0x9c,0xe2,0xb2,0xef,0xb6,0xa6,0xee,0x1a,0x3d,0x26,0xa7,0x20,0x8d, + 0x04,0x20,0x47,0x41,0x44,0x18,0x23,0x4f,0x8b,0x6b,0xf0,0x5f,0x8f,0xad,0x70,0x71,0x14,0xb2,0x92,0xec,0x81,0xf9,0x24,0xf1,0xa6,0x8d,0x9f,0xc3,0x7f,0x01,0xde,0x1e,0x2c,0x58,0x20,0x8d, + 0x04,0x20,0x47,0xec,0x81,0x10,0x2c,0xa1,0x07,0xcb,0xae,0xd0,0x22,0x6a,0xe2,0x5d,0x1d,0xa1,0xed,0xb9,0xcf,0x37,0x52,0x6d,0x88,0x2c,0x6e,0x6a,0xb4,0x11,0x09,0xe3,0xdb,0xf9,0x20,0x8d, + 0x04,0x20,0x47,0xf3,0xb0,0xf0,0x56,0x74,0xad,0x9f,0xc9,0x4d,0x16,0x54,0x36,0xd9,0x87,0x0a,0x9b,0xfc,0x2b,0xb4,0xad,0xd3,0x69,0xc6,0x64,0xcb,0x49,0x1e,0xcf,0x8c,0x0a,0x35,0x20,0x8d, + 0x04,0x20,0x40,0x48,0xb1,0xa8,0x26,0x20,0xab,0x50,0x3e,0x0c,0x5c,0xdc,0x3c,0xb6,0x8d,0xd9,0xdc,0x26,0xcf,0x54,0xf2,0xde,0xe1,0x32,0x76,0x2a,0x96,0xff,0xfa,0xef,0xf1,0x07,0x20,0x8d, + 0x04,0x20,0x40,0xb1,0x9a,0x24,0xbc,0x4b,0x9f,0x96,0xc4,0xcf,0x90,0x0c,0xc2,0xd0,0x55,0xe7,0xed,0x60,0xf3,0xb3,0x94,0x69,0x61,0xa6,0x84,0x7b,0xfe,0x73,0x83,0x47,0xc6,0x8f,0x20,0x8d, + 0x04,0x20,0x40,0xf8,0xfa,0x78,0xfc,0xfc,0xca,0xd6,0x3d,0x87,0xa4,0x61,0xdb,0x39,0x98,0x7c,0x19,0x7b,0x76,0x28,0xe2,0x6e,0x17,0xe9,0xf0,0x9f,0x7d,0x98,0x71,0x68,0x98,0xc3,0x20,0x8d, + 0x04,0x20,0x40,0xfe,0x20,0x70,0xbc,0xc0,0x7b,0x88,0x97,0xa8,0x9b,0xa0,0x2c,0xc1,0xfa,0x0c,0xb0,0x86,0xc1,0x2a,0xb5,0x1d,0xd6,0x57,0x37,0xf6,0xb9,0xd2,0x17,0x6d,0x62,0x75,0x20,0x8d, + 0x04,0x20,0x41,0x0e,0xb5,0xfa,0x48,0xbe,0x25,0x88,0x4c,0xb1,0x43,0xc3,0x31,0x79,0xc1,0xee,0x40,0x0d,0x46,0x0b,0x6a,0xe6,0x7a,0x5d,0x58,0x33,0x00,0xc7,0x68,0xe9,0xd9,0x59,0x20,0x8d, + 0x04,0x20,0x41,0x46,0xb6,0xb7,0x42,0xb9,0x22,0x9a,0x8b,0x84,0x31,0x1e,0x40,0xca,0xbd,0x33,0x54,0x68,0x4d,0xd5,0xb5,0x26,0x54,0x83,0x7f,0x74,0xa1,0xa3,0x6b,0x86,0x75,0xa5,0x20,0x8d, + 0x04,0x20,0x41,0x9b,0x2e,0xcf,0xc2,0x8b,0x71,0x0b,0xad,0xd2,0xfa,0xdb,0x53,0x89,0xeb,0x9a,0x1c,0x2a,0x4b,0x8e,0xbf,0x16,0x1b,0x73,0xfd,0xa1,0x97,0xfc,0x0a,0x79,0x4e,0xf1,0x20,0x8d, + 0x04,0x20,0x42,0x1c,0x80,0x21,0x48,0x8d,0x4f,0x1b,0x39,0x17,0x34,0x17,0xc9,0x85,0xaa,0x03,0x03,0xcf,0xe0,0x0c,0x94,0x72,0x83,0xfd,0xaf,0x44,0xfe,0x1a,0x31,0xa2,0xf8,0x49,0x20,0x8d, + 0x04,0x20,0x42,0x53,0xf6,0xf7,0x66,0x68,0x58,0x82,0x39,0x2a,0x24,0x3c,0xf9,0xe7,0x45,0x2d,0xe6,0x0a,0x1a,0x90,0x84,0x97,0x4a,0x63,0x51,0x8a,0x5c,0x8d,0x34,0x09,0x56,0xf0,0x20,0x8d, + 0x04,0x20,0x42,0xe6,0xce,0x85,0xed,0x28,0x1d,0x03,0x58,0x39,0x2e,0x32,0xed,0x6a,0xb0,0x39,0x9e,0x58,0x26,0x6a,0x1f,0xef,0x6f,0x09,0xf9,0x4c,0xe2,0xc0,0x34,0x04,0x99,0xae,0x20,0x8d, + 0x04,0x20,0x44,0xe7,0xbc,0xb5,0x52,0x8d,0x7a,0x30,0xb8,0x78,0xac,0x8f,0x56,0x2e,0x72,0x6d,0xb8,0x83,0xe4,0x6b,0x28,0x88,0xf3,0x04,0x51,0xdb,0xf3,0x14,0xdd,0x9e,0x1b,0xf3,0x20,0x8d, + 0x04,0x20,0x45,0x2a,0x39,0x4b,0x37,0x3f,0x88,0x2e,0xea,0xa5,0xcf,0x2d,0xab,0x48,0x12,0xb6,0x34,0xd3,0xd5,0xf3,0xab,0xa0,0xfe,0x6a,0x68,0xe2,0xa9,0x5d,0x69,0x91,0xc1,0xf2,0x20,0x8d, + 0x04,0x20,0x4e,0xae,0xe6,0x85,0xcf,0x49,0x1e,0x14,0xb6,0x87,0x87,0xe5,0x4e,0x1d,0xf6,0x08,0xb0,0xab,0xfe,0x50,0x8b,0x17,0xd6,0xe9,0xbf,0x5d,0x60,0x03,0xe2,0xff,0x97,0x02,0x20,0x8d, + 0x04,0x20,0x4e,0xe7,0xe7,0xdc,0xa9,0x58,0x54,0xb9,0xfa,0xb5,0x94,0x6e,0x07,0xab,0x42,0x9d,0xaf,0x28,0x59,0x57,0x3d,0x5c,0xdf,0xa3,0x82,0xe6,0x34,0xcd,0xd3,0x88,0x0e,0x4f,0x20,0x8d, + 0x04,0x20,0x4e,0xe6,0x38,0x25,0x11,0xba,0xf1,0xc2,0x8e,0xda,0x6d,0x08,0x08,0xa9,0x28,0x6b,0x19,0x68,0x7a,0xd4,0x7e,0xe9,0x0d,0x5d,0xaa,0x45,0xf1,0xcb,0xd6,0x4f,0xcf,0xd2,0x20,0x8d, + 0x04,0x20,0x4f,0xbf,0x52,0x77,0xf5,0x17,0x46,0xde,0xdc,0x4e,0x8d,0x0a,0x1e,0xa8,0xdf,0xc5,0xf1,0x9a,0x07,0x5f,0x91,0xb2,0x09,0x37,0x55,0xb1,0xdf,0x89,0x56,0x22,0x2a,0x8a,0x20,0x8d, + 0x04,0x20,0x4f,0x8f,0xc5,0x71,0x78,0x65,0xb7,0x96,0x4d,0x0d,0xeb,0x7f,0x56,0x6a,0xaf,0xf0,0x5a,0x98,0xf3,0x55,0x5a,0xb4,0xa3,0x57,0xe3,0x0d,0x1c,0x03,0x3f,0x28,0x3e,0xc6,0x20,0x8d, + 0x04,0x20,0x48,0x0c,0x10,0x5d,0x09,0x66,0x06,0xc0,0x5d,0x35,0xd4,0xe1,0xad,0xe0,0x2c,0x9c,0x07,0x04,0x60,0x6c,0xd4,0x00,0x15,0x0d,0xb4,0x90,0x9c,0x79,0x33,0xac,0x73,0xac,0x20,0x8d, + 0x04,0x20,0x48,0x96,0x9d,0xe8,0xd5,0xa3,0xf9,0x15,0x6d,0x50,0xf9,0x8f,0xdc,0x1c,0x78,0xc9,0x3e,0x1d,0x22,0x45,0x21,0xae,0x02,0x86,0x77,0x37,0x15,0xa1,0x66,0x5a,0x56,0x6a,0x20,0x8d, + 0x04,0x20,0x49,0x20,0x9e,0x7b,0x52,0x8e,0xbf,0xc3,0x34,0xed,0x37,0xc7,0xd4,0xbe,0xa4,0xa5,0x13,0xd0,0xfc,0xc2,0x7f,0x8f,0x26,0x7e,0x4a,0xa3,0x36,0x64,0x3b,0xa0,0x09,0xc5,0x20,0x8d, + 0x04,0x20,0x49,0xa9,0x76,0xa8,0x45,0x6f,0x23,0xc7,0x9b,0x0e,0x4f,0xc5,0x54,0x4b,0x05,0xb4,0x01,0x07,0xa8,0x7f,0x76,0xac,0x38,0x66,0x72,0x2a,0xfd,0x23,0xf0,0x22,0x17,0xb6,0x20,0x8d, + 0x04,0x20,0x49,0xf3,0x31,0x25,0x4c,0x7e,0xb6,0x01,0x97,0x3c,0x1a,0x19,0x8a,0x63,0x29,0x52,0x8a,0x16,0xbb,0x6d,0x29,0x89,0x0e,0x34,0x6f,0xe7,0x00,0xc1,0x34,0xb7,0x88,0xbf,0x20,0x8d, + 0x04,0x20,0x4a,0x7c,0x52,0x1d,0x70,0x42,0xc9,0xad,0x33,0x85,0x59,0xf9,0x44,0x89,0xba,0x2f,0x3f,0xd1,0x29,0x9d,0xcc,0x8a,0xda,0x78,0xbc,0x86,0x0a,0x13,0x47,0xfd,0x7c,0x28,0x20,0x8d, + 0x04,0x20,0x4a,0xd1,0xe8,0x2a,0xbf,0xe7,0x65,0xcb,0x5c,0xae,0x0f,0xa3,0x4b,0xd0,0x1a,0xf6,0x98,0x63,0xcd,0x3f,0x15,0x3f,0x03,0x1c,0x65,0x77,0xad,0x83,0x47,0x0a,0xf4,0x11,0x20,0x8d, + 0x04,0x20,0x4a,0xd5,0x55,0x60,0x0b,0x16,0x44,0x81,0xc7,0x1e,0x24,0x38,0x9b,0xe2,0xd5,0xf4,0xb3,0xb1,0x07,0x9e,0x07,0xb0,0xd8,0x55,0x7c,0x2a,0x01,0xe0,0x1f,0xb5,0x9e,0x4f,0x20,0x8d, + 0x04,0x20,0x4b,0x00,0x70,0x4e,0x57,0x49,0x8a,0x6d,0xa3,0x3f,0x3a,0x88,0xbe,0xad,0x45,0xfe,0xd5,0xa9,0x59,0x13,0x0a,0xc9,0x31,0x00,0xe7,0x02,0x72,0x78,0xcd,0xa3,0x4e,0xad,0x20,0x8d, + 0x04,0x20,0x4b,0x49,0x37,0x3e,0x20,0x1c,0x9c,0x3d,0xef,0x7a,0x04,0xad,0x6c,0x0a,0xf6,0x9d,0x86,0xad,0x70,0x2e,0xe9,0xa1,0x5d,0xf0,0x6a,0xd9,0xf3,0x7d,0x8a,0x25,0x12,0xdd,0x20,0x8d, + 0x04,0x20,0x4b,0xad,0xe2,0x4c,0x9d,0xa7,0x45,0x2d,0x67,0x6d,0x99,0x82,0x6c,0x1a,0x12,0x92,0x22,0x4b,0x81,0xc4,0x9f,0x45,0xc3,0xca,0x9b,0x9f,0x34,0xdd,0xd2,0xb3,0x10,0xa7,0x20,0x8d, + 0x04,0x20,0x4c,0xc6,0x19,0xf7,0x8d,0xf4,0xc4,0x20,0xd9,0xe1,0xac,0x01,0x8d,0xb7,0x6f,0x2b,0x62,0xca,0x71,0x40,0x34,0x33,0x33,0x1c,0xa0,0x5f,0xb5,0xeb,0x21,0x94,0xa7,0xb0,0x20,0x8d, + 0x04,0x20,0x4d,0xd4,0x65,0xfe,0x97,0x36,0x15,0xf2,0xe3,0xe1,0x1f,0x8e,0x95,0xab,0x02,0x17,0x86,0x19,0xc1,0x18,0x7d,0x41,0x36,0x72,0x3b,0xc7,0x08,0xb1,0xa7,0xe0,0x94,0x0e,0x20,0x8d, + 0x04,0x20,0x4d,0xd6,0x75,0x40,0x33,0x55,0x18,0x78,0x83,0xdd,0xd5,0x34,0x1f,0x75,0xa1,0x62,0x1b,0x57,0xc2,0xb9,0x4f,0x7f,0x9f,0xa0,0xf6,0x68,0xff,0x70,0xc2,0x3f,0x73,0x84,0x20,0x8d, + 0x04,0x20,0x57,0x26,0xb6,0x0f,0xa8,0x29,0xc3,0x7b,0x7d,0x3b,0x36,0x88,0x48,0x41,0x85,0xa0,0xc0,0x4d,0xa7,0x48,0xb2,0x7f,0x89,0xdc,0xd5,0xe0,0x21,0xdf,0x65,0x88,0xb5,0xda,0x20,0x8d, + 0x04,0x20,0x57,0x68,0xab,0xf3,0xdf,0x17,0x94,0x62,0xfe,0x55,0xab,0x8e,0xb2,0x09,0xa3,0x27,0xea,0x4a,0x7f,0x3b,0x9b,0xd5,0xf7,0x5b,0x9e,0x8e,0x1d,0xa2,0xeb,0xb7,0x30,0xf2,0x20,0x8d, + 0x04,0x20,0x57,0x83,0x2c,0x42,0xca,0x60,0xfb,0x46,0x5a,0x40,0xe3,0x94,0xe1,0x0f,0xb0,0x82,0x86,0x86,0x93,0xfe,0x23,0x5b,0x61,0xfb,0xc9,0x5e,0x50,0xff,0x70,0xe5,0x43,0x46,0x20,0x8d, + 0x04,0x20,0x50,0x18,0x09,0xe0,0xda,0x94,0x0e,0x11,0x1a,0xed,0x58,0x50,0x7d,0xd4,0xda,0x7c,0x6d,0x35,0x73,0x10,0x3b,0x42,0x42,0xa9,0x7e,0x10,0xd9,0x13,0x9c,0x34,0x36,0xce,0x20,0x8d, + 0x04,0x20,0x50,0xb1,0xc8,0x64,0xbb,0xce,0x5b,0x09,0x11,0x38,0xe5,0xbf,0x32,0x9e,0xfe,0xa8,0xe3,0x85,0x72,0x9b,0xb0,0x9c,0x30,0xef,0xff,0x3a,0x6f,0x91,0x39,0x61,0x2b,0x70,0x20,0x8d, + 0x04,0x20,0x52,0x5a,0xe5,0x0d,0x3b,0xf8,0x90,0xc3,0x48,0x98,0x1a,0xc6,0xc2,0x1f,0x10,0xa5,0x4c,0xee,0x8f,0xd4,0x80,0x89,0xf7,0xac,0x14,0xb4,0xc6,0xfb,0x65,0xec,0x2a,0x8d,0x20,0x8d, + 0x04,0x20,0x53,0xbe,0x83,0x63,0x0a,0xe0,0xe3,0xe7,0x16,0x47,0x97,0xfa,0xc0,0x9d,0x16,0x32,0x19,0xe2,0x3d,0xf8,0x93,0xc6,0x0f,0xf7,0xb8,0xf1,0x2e,0xb8,0x0d,0x58,0x63,0x6d,0x20,0x8d, + 0x04,0x20,0x53,0xab,0x26,0x50,0x6e,0x71,0x9a,0xa9,0xe1,0x27,0xa0,0xa5,0x65,0x33,0x4f,0x74,0x8e,0xbf,0xd6,0x48,0x5b,0xe4,0x17,0xce,0xf4,0x36,0x7f,0xa0,0x6b,0xe7,0x72,0x9c,0x20,0x8d, + 0x04,0x20,0x54,0x24,0xd7,0xcb,0x4e,0x7b,0xb6,0x40,0x24,0x14,0x10,0xf1,0x2f,0xb8,0xb2,0x97,0xb6,0xfd,0xb9,0x11,0x19,0x24,0x88,0x54,0x10,0x1a,0x20,0xcc,0xa7,0xc2,0x99,0x51,0x20,0x8d, + 0x04,0x20,0x54,0x7a,0x6a,0x2d,0xdb,0xa9,0xef,0x05,0x6b,0x4f,0x14,0xd6,0x17,0x8a,0x8a,0x5e,0x82,0xf5,0xb2,0x84,0x32,0xfa,0x3b,0x20,0xc2,0xf3,0xa6,0x8d,0x66,0x00,0x7b,0x29,0x20,0x8d, + 0x04,0x20,0x56,0x19,0x3b,0x83,0x15,0xa5,0x40,0x31,0xcc,0x07,0xc5,0xf6,0xa7,0xdd,0xb3,0x02,0x91,0xb3,0x31,0x6c,0x59,0x2f,0x45,0x1a,0xf6,0xfa,0x03,0xa8,0x4e,0xd4,0x80,0x41,0x20,0x8d, + 0x04,0x20,0x5e,0xa8,0x74,0x47,0x93,0xdb,0x21,0xe1,0x27,0x4b,0x1e,0x2f,0x94,0x60,0x72,0x56,0x0f,0xf5,0x69,0xb7,0xeb,0xae,0x78,0x6b,0x5b,0x0c,0x70,0x46,0xd7,0x06,0x97,0x91,0x20,0x8d, + 0x04,0x20,0x5f,0x06,0x9c,0x97,0xf1,0x52,0x74,0xd5,0x28,0xa6,0x24,0xf6,0xfd,0x47,0x52,0x3f,0x3d,0xea,0x0c,0x76,0x83,0xc3,0xf5,0x35,0xa3,0x0f,0xc3,0x05,0x82,0xc5,0xd8,0x5d,0x20,0x8d, + 0x04,0x20,0x58,0x04,0x52,0x5d,0x1e,0x63,0xad,0x37,0xb0,0xb1,0x68,0xc7,0x59,0x9e,0x42,0xca,0x2b,0x00,0x71,0xb8,0xad,0x7c,0xd3,0x6b,0x67,0x9a,0x9b,0xc9,0x16,0xe5,0x84,0x82,0x20,0x8d, + 0x04,0x20,0x58,0x79,0xdc,0x92,0xe6,0x9b,0x43,0xfd,0x57,0xfd,0xd4,0xba,0xbd,0x4f,0xbe,0x22,0x21,0xc1,0xd0,0xf0,0xac,0x72,0xaf,0x22,0x32,0xab,0xdf,0xc3,0xfa,0xf7,0x33,0x85,0x20,0x8d, + 0x04,0x20,0x59,0x38,0xaf,0xf9,0x3b,0xc4,0x83,0x8c,0x6d,0x13,0x3c,0x36,0xec,0x1c,0xe0,0x24,0x84,0x7f,0xb0,0x36,0x2c,0x20,0x51,0x64,0x9e,0xcf,0xe7,0x74,0x8f,0x0c,0xcb,0x5e,0x20,0x8d, + 0x04,0x20,0x59,0x90,0xb2,0x2f,0x38,0x3b,0x3a,0x46,0x7c,0xcd,0x64,0x19,0xcf,0x07,0xd4,0xd9,0xb4,0x80,0x33,0x43,0xb8,0x45,0xbc,0x59,0x53,0x58,0x61,0xe3,0x3d,0x01,0x79,0xf1,0x20,0x8d, + 0x04,0x20,0x59,0xf6,0xcc,0x22,0x5c,0x69,0x31,0x07,0x67,0xc4,0x8f,0x81,0x5e,0x0a,0xc5,0x2b,0xb1,0xd3,0x8c,0xc8,0x8b,0x2a,0xdc,0xf3,0x16,0xc7,0x59,0x54,0x68,0xc6,0x35,0x75,0x20,0x8d, + 0x04,0x20,0x5a,0x32,0xc2,0x14,0x9b,0x6a,0x63,0x12,0x2d,0x83,0xce,0x1b,0x83,0x9e,0x78,0x26,0x92,0x82,0x94,0xfc,0xd5,0xf5,0xff,0xdf,0x12,0x87,0xf3,0x00,0x92,0xa2,0x2a,0xb0,0x20,0x8d, + 0x04,0x20,0x5a,0x75,0x48,0xfe,0xe9,0x6d,0x97,0xc8,0x11,0x09,0x88,0x93,0xaf,0x73,0x8a,0x3a,0x57,0x91,0x64,0x5e,0xb2,0x1e,0x51,0x48,0xe4,0xad,0x30,0xda,0xac,0x26,0x28,0xa8,0x20,0x8d, + 0x04,0x20,0x5a,0x8e,0x83,0x61,0x7f,0x56,0x3f,0x9a,0x99,0x3b,0x02,0x11,0x30,0xb5,0x72,0x85,0xe7,0xac,0x9d,0x5c,0x6e,0x0d,0x2d,0xb1,0x1a,0x2b,0x95,0x10,0xbf,0x52,0x05,0xb4,0x20,0x8d, + 0x04,0x20,0x5a,0xee,0x3e,0x00,0x86,0x37,0x02,0x5e,0x69,0x41,0x88,0xe4,0x69,0xf3,0x60,0xca,0xc1,0x9a,0x69,0x5c,0x94,0x8d,0x93,0x5a,0x66,0x18,0x13,0x5d,0xbe,0xd7,0x98,0xe7,0x20,0x8d, + 0x04,0x20,0x5c,0x53,0x05,0x8c,0x65,0x32,0xea,0x2b,0x70,0x07,0xc8,0x9d,0x23,0x7d,0x90,0x9e,0x71,0xe0,0x80,0xf8,0x64,0x2e,0x2f,0x2b,0x7b,0x84,0x32,0xaf,0x77,0x3c,0x4e,0x35,0x20,0x8d, + 0x04,0x20,0x5c,0x71,0x2c,0x3d,0x97,0x55,0xee,0x73,0x03,0x1f,0xe1,0x94,0x6a,0x09,0xa5,0x37,0xde,0xfa,0x3c,0xb7,0x32,0x1d,0xca,0xec,0x6f,0xc8,0x4e,0xe2,0x63,0x19,0xc1,0xac,0x20,0x8d, + 0x04,0x20,0x5d,0x6c,0x2a,0x5f,0xc8,0xec,0x08,0xa0,0xbf,0x3e,0x6a,0x57,0x3f,0x98,0xea,0xf5,0x7a,0x3a,0xaf,0x65,0xd8,0x22,0x2e,0x4d,0xf1,0x0a,0xa9,0x76,0x4d,0x5c,0x4b,0xb7,0x20,0x8d, + 0x04,0x20,0x5d,0xb6,0x58,0xee,0x58,0x6a,0x73,0x98,0x3e,0x6e,0x73,0x6c,0x59,0xa1,0x9f,0xb3,0xc2,0x77,0xa0,0x9a,0xc1,0x7e,0xfc,0x27,0xdf,0xa8,0xda,0xea,0x67,0x4e,0xa8,0x47,0x20,0x8d, + 0x04,0x20,0x5d,0xa5,0xf5,0x4f,0x49,0x32,0x71,0xb5,0x52,0x37,0xbe,0x61,0x7b,0x5b,0xd1,0xfb,0x22,0x2e,0x1a,0x29,0x62,0x88,0xa3,0x98,0x4f,0x2d,0xb9,0x30,0x98,0x4d,0xe2,0xa7,0x20,0x8d, + 0x04,0x20,0x5d,0xe2,0x09,0x67,0xe3,0xac,0x41,0xe2,0x7e,0x6d,0xa2,0xf1,0x6e,0xda,0xa7,0xf1,0xfc,0xe4,0x11,0xbc,0x04,0x50,0x70,0x38,0xe9,0x20,0x15,0xc0,0xc9,0x77,0xeb,0x90,0x20,0x8d, + 0x04,0x20,0x5e,0x14,0x5e,0xc4,0xc2,0x03,0x84,0x1c,0x15,0x97,0x39,0xc5,0x0d,0x02,0x08,0xf9,0x34,0x9a,0xf6,0x28,0xbb,0x19,0x74,0x4b,0x11,0x2d,0x02,0x1f,0xbc,0xe0,0xa2,0x50,0x20,0x8d, + 0x04,0x20,0x5e,0x1f,0x3e,0x58,0x80,0xcb,0x21,0x16,0x7f,0x1c,0xe3,0x8e,0x31,0x6c,0x98,0xd6,0xdb,0xbb,0x90,0x88,0xf6,0x09,0x17,0x15,0x4d,0x09,0xbe,0x4d,0x15,0x65,0x50,0x14,0x20,0x8d, + 0x04,0x20,0x66,0x96,0xfb,0x81,0x01,0xef,0x69,0x39,0xda,0xbd,0xf9,0xb8,0xc4,0x95,0x31,0x8f,0xc7,0x09,0xfc,0x43,0xb7,0x01,0x0f,0xcb,0x8f,0x36,0xf3,0x7c,0x62,0xd4,0x74,0x63,0x20,0x8d, + 0x04,0x20,0x66,0xce,0x02,0x20,0xd6,0x01,0x5c,0x28,0xd0,0xde,0x2a,0x36,0x31,0x65,0xe0,0xbb,0x1d,0x6b,0x1b,0x63,0x93,0xc6,0x16,0xcf,0xa5,0x58,0x39,0x00,0x6c,0xf5,0x93,0x4e,0x20,0x8d, + 0x04,0x20,0x67,0xf2,0x94,0xc8,0x6e,0x37,0x20,0x47,0x7f,0xb7,0xea,0x75,0x28,0x23,0xe4,0x24,0xf6,0xa2,0x3d,0x10,0x8f,0xe8,0x24,0x21,0x4d,0xb3,0x6e,0x49,0xbf,0x2a,0x93,0x92,0x20,0x8d, + 0x04,0x20,0x60,0xe8,0xce,0x4a,0x70,0x80,0x53,0x2e,0x51,0xf2,0xe7,0x63,0x03,0x1e,0xef,0xb9,0x09,0xa8,0x58,0xea,0x80,0x78,0xa4,0x67,0x18,0xcb,0xc1,0xa4,0xc2,0x38,0xbc,0xd8,0x20,0x8d, + 0x04,0x20,0x61,0x56,0x0d,0x6e,0x3b,0x0b,0x87,0x25,0xd6,0x23,0xa5,0x49,0x33,0xd3,0x88,0x9d,0x08,0x9e,0xab,0xbe,0xaa,0xc6,0xf7,0xfd,0x9d,0x7d,0x3a,0x12,0xe1,0x55,0x86,0x9d,0x20,0x8d, + 0x04,0x20,0x61,0xfc,0xe5,0x0b,0x80,0xbc,0xee,0xf6,0x83,0x55,0x95,0x7c,0xc0,0x0c,0x97,0x23,0xcd,0xa8,0x9f,0x04,0x44,0x1b,0x08,0x96,0xda,0x7a,0xa6,0x6c,0x24,0x2c,0x6b,0x7f,0x20,0x8d, + 0x04,0x20,0x61,0xe0,0x5e,0x2d,0xa3,0x1e,0x28,0x9b,0x11,0x09,0x5e,0x8e,0xba,0xe2,0x05,0x21,0x0e,0xdd,0x58,0xf3,0x6a,0xc1,0x71,0xa7,0xec,0xe4,0x54,0x9b,0x94,0xb5,0xce,0x51,0x20,0x8d, + 0x04,0x20,0x62,0x84,0x77,0x4f,0x98,0x73,0xc6,0xad,0x86,0x93,0x98,0x09,0xa1,0x1e,0x34,0x23,0x69,0xad,0xdc,0xdd,0x94,0x47,0xb8,0xfc,0xc1,0xee,0x8c,0xa3,0x70,0x99,0x6b,0xc1,0x20,0x8d, + 0x04,0x20,0x63,0xa3,0x3b,0xd7,0x99,0xca,0xf1,0x47,0xc5,0x1f,0xa9,0xea,0xc4,0x68,0x43,0xe5,0x30,0x75,0x92,0x6b,0x4e,0xa9,0x33,0xf2,0x58,0xe4,0x6f,0x36,0x6b,0xcc,0xe7,0xc7,0x20,0x8d, + 0x04,0x20,0x63,0xc3,0x20,0x7c,0xcc,0xdc,0xde,0xfe,0xb4,0x12,0x5f,0x3b,0xb3,0x18,0xfc,0x5f,0x67,0x21,0x77,0x1d,0x56,0x36,0xf7,0xb1,0x66,0x2e,0x84,0x60,0xcf,0x32,0xd8,0xc2,0x20,0x8d, + 0x04,0x20,0x64,0x6a,0x0c,0x40,0x1e,0xb7,0xbb,0xc3,0x69,0xfe,0x51,0xa5,0x1e,0xae,0x32,0x3b,0x78,0x10,0x1d,0x80,0x16,0x9d,0xaf,0x4b,0xd8,0x24,0xea,0xcb,0xc2,0xcb,0x5b,0xbe,0x20,0x8d, + 0x04,0x20,0x64,0xce,0x81,0x44,0xd4,0xae,0x32,0x6c,0x16,0xe5,0x6f,0xa6,0xc1,0xca,0xcd,0x62,0xc6,0xfa,0xde,0xc2,0x40,0x75,0xdb,0x9b,0x66,0x38,0xda,0x0e,0xc2,0x73,0x70,0xfa,0x20,0x8d, + 0x04,0x20,0x65,0x52,0xe9,0xc2,0x53,0x24,0x9b,0x14,0x56,0x69,0x9b,0x26,0xf5,0xea,0x14,0x8d,0x55,0x82,0xec,0xd2,0x29,0x8b,0x36,0x25,0x9a,0xa3,0xd5,0x87,0x0e,0xea,0xb1,0xd9,0x20,0x8d, + 0x04,0x20,0x65,0x89,0x0f,0x62,0x84,0x8a,0xd2,0xf6,0xd6,0xcb,0x55,0x5a,0x7f,0x8e,0x8e,0x29,0x87,0xc8,0x7f,0x09,0x98,0x57,0x2f,0x9b,0x6c,0xa6,0x7f,0xcf,0xbc,0x6d,0x18,0xe7,0x20,0x8d, + 0x04,0x20,0x65,0xeb,0xb8,0xa1,0x37,0x07,0x0d,0xa6,0x18,0x05,0x3d,0xb0,0x0b,0xfd,0x62,0x2e,0x22,0x73,0xa1,0x60,0xe9,0xb9,0x16,0xb3,0x9e,0x15,0x88,0xc4,0x2c,0x8e,0xfb,0x94,0x20,0x8d, + 0x04,0x20,0x6e,0x83,0x44,0x23,0x82,0x5a,0xa6,0xdc,0x35,0x65,0x7e,0xc4,0x26,0x52,0xf2,0x35,0xaa,0xd3,0x50,0xd9,0x3b,0xcc,0x13,0x19,0x2c,0x8d,0xeb,0xfc,0x41,0x1f,0x31,0x12,0x20,0x8d, + 0x04,0x20,0x6e,0xd3,0x96,0x36,0xbf,0x7c,0xa5,0xce,0xae,0x21,0x88,0xbb,0xf9,0xcb,0x1b,0x36,0x5a,0xd8,0xf8,0x12,0xc3,0xa4,0x35,0x0d,0x6f,0x8a,0x16,0x2f,0x42,0x84,0xa1,0xbc,0x20,0x8d, + 0x04,0x20,0x6f,0x73,0x78,0x6b,0xc8,0x66,0xba,0x9e,0x40,0xd8,0x66,0x1c,0x70,0x03,0xa8,0xec,0xc4,0xf4,0x1e,0xe5,0x79,0x6c,0xab,0x15,0xce,0x57,0x66,0x8a,0xa1,0xee,0x06,0xb9,0x20,0x8d, + 0x04,0x20,0x6f,0xb9,0xee,0x8b,0x40,0x2f,0xa5,0xa2,0xe7,0x3a,0xea,0xd2,0xfa,0xfe,0xe9,0xa8,0x53,0xa3,0x4c,0xf0,0x02,0x17,0xf6,0xcb,0xd6,0x1f,0xab,0xe9,0x99,0x4a,0x71,0x4c,0x20,0x8d, + 0x04,0x20,0x6f,0xba,0xc2,0xb9,0x5a,0xa9,0x51,0x1f,0x71,0xcf,0xcd,0x2f,0x08,0x3d,0x97,0x69,0xe8,0x11,0x55,0xf8,0x44,0xc9,0xc5,0x5c,0xe5,0xd9,0xa3,0x2f,0xf8,0xf9,0x0a,0x70,0x20,0x8d, + 0x04,0x20,0x6f,0xad,0x89,0x9e,0x48,0x0b,0x96,0x1c,0xf8,0xe3,0xae,0xd4,0x3b,0x85,0xdb,0x08,0xce,0x5e,0xda,0x64,0x29,0x87,0xc9,0xaa,0x41,0xd6,0xb9,0x95,0x77,0xff,0x65,0xf1,0x20,0x8d, + 0x04,0x20,0x68,0x9c,0xb3,0xf4,0x02,0x5b,0x53,0x24,0xce,0x67,0x93,0x1b,0xf8,0x48,0x55,0xb5,0xf4,0xc2,0xf9,0x30,0xd6,0x7f,0xd1,0x5f,0x92,0x68,0x49,0x09,0xfd,0x8f,0x0a,0x72,0x20,0x8d, + 0x04,0x20,0x68,0xd8,0x4d,0x12,0x96,0xf6,0x2a,0x4f,0x85,0x3d,0xc0,0x36,0x0b,0x28,0xf5,0x06,0x5a,0x1d,0x98,0x14,0x02,0x07,0x6e,0xba,0xbe,0x83,0x0b,0xc5,0x40,0xc7,0x90,0x35,0x20,0x8d, + 0x04,0x20,0x69,0xa8,0xf1,0xf0,0x9f,0x3f,0x88,0xb1,0x8f,0xd3,0x6e,0xc1,0xfc,0x54,0x11,0xa2,0x5c,0xe6,0x4e,0xa9,0xd7,0xc6,0x22,0xd8,0xd9,0xf5,0x18,0x29,0x83,0xba,0x0e,0x0c,0x20,0x8d, + 0x04,0x20,0x69,0xdc,0xd1,0xad,0xd1,0xfb,0x25,0x67,0x49,0x52,0x25,0xdf,0x8d,0x6a,0x15,0x8b,0x07,0xa3,0x32,0x4a,0xbb,0x8e,0x3c,0xcf,0x72,0xcd,0x7f,0xbc,0xd5,0x4c,0x5d,0xbb,0x20,0x8d, + 0x04,0x20,0x69,0xe0,0x3b,0x71,0xef,0x8d,0xcd,0x5b,0xde,0x17,0x9a,0x07,0xb2,0xc6,0xfd,0x9f,0xf7,0x31,0x31,0x83,0x57,0x64,0x0b,0xfc,0x1c,0xd8,0xbb,0x51,0xf9,0xb0,0xb7,0x8b,0x20,0x8d, + 0x04,0x20,0x6a,0x39,0x4e,0xe9,0x2f,0x09,0x53,0x2f,0xd5,0x56,0x68,0xd6,0xe8,0xb4,0xfb,0xa7,0x49,0x92,0xaf,0xe4,0xf2,0x39,0x54,0x88,0x4f,0x70,0xb2,0xcb,0xf2,0xd0,0xb9,0x09,0x20,0x8d, + 0x04,0x20,0x6a,0x3e,0x67,0xe7,0xa0,0xdb,0x54,0xdf,0x1a,0xee,0xe5,0xcc,0x29,0x48,0x93,0xf5,0xa5,0xbf,0xa6,0x9f,0xe9,0x35,0x9e,0x8b,0xc0,0xcb,0x01,0x51,0x56,0x5d,0xb5,0xe2,0x20,0x8d, + 0x04,0x20,0x6a,0x23,0xb4,0xd7,0xf6,0xd9,0xd6,0x4a,0x44,0x79,0xfe,0x0b,0x68,0xec,0xbc,0x0b,0x31,0x6f,0x88,0x9f,0xa6,0xe2,0xd5,0x97,0xd9,0xfc,0xc3,0x77,0x23,0xfe,0x4d,0x9a,0x20,0x8d, + 0x04,0x20,0x6a,0x48,0x24,0x7b,0xf0,0x16,0x09,0xce,0x89,0x7d,0x7b,0xf9,0x67,0xcd,0x8b,0xf9,0x95,0xfb,0x2e,0x10,0x4b,0x49,0x9f,0x38,0x3f,0x7c,0xbf,0xcb,0x29,0xe5,0x1a,0x4f,0x20,0x8d, + 0x04,0x20,0x6a,0x96,0xd3,0x87,0xcb,0x7a,0x2d,0x37,0xdd,0x37,0x50,0xcb,0x33,0xb4,0x4a,0x78,0x81,0x23,0x92,0xc3,0xa0,0x69,0x35,0xf7,0xdb,0x65,0x5e,0x7d,0x5d,0x23,0x08,0x2e,0x20,0x8d, + 0x04,0x20,0x6a,0xe4,0xaf,0x69,0x5a,0xbe,0x2a,0x48,0xb2,0x3f,0x0f,0xcb,0xf1,0x5a,0x77,0x1c,0x4c,0xae,0x35,0xed,0x25,0x99,0x1d,0xb9,0x8a,0xfd,0x00,0x63,0x3a,0x47,0x10,0xf3,0x20,0x8d, + 0x04,0x20,0x6b,0x89,0x4a,0xa2,0x97,0x15,0xac,0xb5,0x3d,0x72,0x68,0x99,0xb7,0x96,0x9d,0x84,0xef,0xf0,0xed,0x4d,0x11,0x6e,0x4e,0xcc,0xb0,0xe5,0x7e,0x8a,0xef,0xda,0x92,0x9d,0x20,0x8d, + 0x04,0x20,0x6c,0x34,0x5b,0x0e,0x13,0xdc,0x0b,0xb2,0xa8,0xa7,0x5b,0x62,0xb6,0xc8,0x4c,0x8d,0x04,0xd4,0x46,0x54,0x6c,0x89,0x98,0xed,0x45,0x90,0xbe,0x98,0xa7,0x8d,0x0e,0x64,0x20,0x8d, + 0x04,0x20,0x6c,0xba,0xfd,0x14,0x1b,0x01,0x62,0x04,0x36,0x38,0x6a,0xb8,0x3c,0xa4,0xa1,0x95,0x54,0xdb,0x79,0x20,0x77,0x64,0x69,0x56,0xb5,0xd1,0x24,0x0b,0x74,0x3c,0xd8,0x90,0x20,0x8d, + 0x04,0x20,0x6d,0x98,0x9b,0xa0,0xde,0x06,0x64,0xf7,0x17,0x40,0x3b,0x2a,0x02,0x2a,0xe4,0x0f,0x95,0x8b,0x0c,0x35,0x2e,0xc7,0xd8,0xdd,0x63,0xc3,0xa2,0xc8,0xb2,0xa7,0xd4,0x4b,0x20,0x8d, + 0x04,0x20,0x6e,0x62,0xff,0xdb,0x57,0x8f,0xc4,0x70,0x25,0xb6,0x45,0x7f,0xa7,0x10,0x1e,0x50,0xf8,0xfa,0xac,0x9d,0x60,0x61,0x03,0xb6,0xa7,0x51,0xf8,0x43,0x35,0xf8,0x9e,0x1a,0x20,0x8d, + 0x04,0x20,0x77,0xe2,0xca,0x61,0xde,0xa7,0x8c,0xda,0xb6,0x18,0xea,0xd9,0x7a,0xd6,0x0c,0x0e,0xc7,0xf4,0x7e,0x77,0x88,0xe3,0x3d,0x36,0x5c,0xaa,0x62,0xe9,0x4c,0x55,0x08,0xe3,0x20,0x8d, + 0x04,0x20,0x71,0x34,0x87,0x8b,0x20,0x31,0x9d,0x2c,0x81,0x84,0x55,0x41,0xd0,0x37,0xa8,0x1c,0x84,0xc0,0xd8,0xab,0x19,0x3d,0x88,0x61,0x98,0xc5,0x49,0x7b,0xe2,0x36,0xcd,0xf0,0x20,0x8d, + 0x04,0x20,0x71,0x4a,0x11,0xcf,0x3b,0xa8,0x47,0x8a,0xa4,0xa3,0x1b,0xf9,0xf7,0x72,0xaa,0x70,0x97,0xd0,0xa4,0x42,0xfa,0xce,0xeb,0x82,0x53,0xff,0x22,0x00,0x28,0xc3,0xdf,0xd3,0x20,0x8d, + 0x04,0x20,0x71,0x91,0x9d,0x1a,0xb7,0xae,0xcc,0x98,0xee,0x6d,0xd3,0xa5,0xac,0x6d,0xf2,0x15,0x61,0xbf,0x94,0x26,0x54,0x4a,0x93,0x70,0x5d,0x87,0xef,0xe6,0x30,0x86,0xee,0x87,0x20,0x8d, + 0x04,0x20,0x71,0x9a,0xd9,0x6a,0x9d,0x08,0xd9,0x6a,0x7b,0xce,0x54,0xe2,0xba,0x60,0x51,0x73,0x61,0xc4,0xca,0x17,0x84,0xbe,0x38,0x37,0x39,0x4b,0xa4,0xa7,0x04,0xaf,0x36,0x7c,0x20,0x8d, + 0x04,0x20,0x71,0xc4,0xfe,0x0c,0xc1,0x70,0x42,0x4d,0xe3,0x7a,0xfd,0xaf,0x89,0x78,0xc3,0x72,0xd7,0x43,0x93,0x37,0xa8,0x5c,0x93,0xdb,0xa8,0xb9,0xc3,0x4a,0x37,0x51,0x66,0x5c,0x20,0x8d, + 0x04,0x20,0x71,0xcb,0xdc,0x4e,0x40,0x7c,0xea,0x92,0xb2,0x26,0x99,0x89,0x2c,0x3c,0x3b,0x74,0x81,0xec,0xeb,0xec,0x4f,0x7b,0x16,0xae,0xf2,0x64,0x51,0x2b,0xc4,0x2d,0xbf,0xab,0x20,0x8d, + 0x04,0x20,0x72,0xb4,0xeb,0x41,0x49,0x3c,0xa4,0xbc,0x5a,0xae,0xfb,0xf1,0x37,0x89,0x25,0xf7,0x39,0xb9,0x8e,0xa6,0x97,0x64,0x7e,0xd7,0x35,0x7c,0x1c,0x05,0x15,0x8e,0xe7,0x01,0x20,0x8d, + 0x04,0x20,0x72,0xdf,0xe7,0x72,0xa7,0xcb,0x40,0x59,0xad,0x8d,0x59,0xd0,0x14,0xdd,0xee,0xc0,0x1c,0xf1,0xd2,0x39,0x92,0x21,0x51,0x1c,0xfd,0xea,0x8f,0xb1,0x12,0x08,0x02,0x2c,0x20,0x8d, + 0x04,0x20,0x73,0x57,0x80,0x92,0x53,0x92,0x23,0xb9,0xa4,0x81,0xba,0x4f,0xa3,0xf7,0x50,0xd4,0x39,0x73,0x4f,0x51,0x7d,0xf7,0x9e,0xf8,0x03,0xca,0x73,0x87,0x7a,0x2a,0xf2,0x5d,0x20,0x8d, + 0x04,0x20,0x74,0x8a,0x0c,0xd6,0x3e,0xef,0xd3,0x45,0x1c,0x78,0x4f,0xe2,0xe9,0x4c,0xa6,0xef,0xd7,0x9c,0x78,0x5f,0x35,0x41,0x70,0x9f,0xf4,0x5e,0xd2,0x05,0x3d,0xea,0x9a,0x24,0x20,0x8d, + 0x04,0x20,0x74,0xd7,0x0e,0x8d,0xf4,0x71,0x2f,0x5a,0x6a,0x85,0xa6,0xb7,0x9d,0x45,0xb7,0xdd,0x42,0x49,0xb9,0x1b,0x56,0x27,0x75,0x82,0x6c,0x3f,0xd6,0xea,0x2a,0xce,0x5c,0x4e,0x20,0x8d, + 0x04,0x20,0x75,0xab,0x5b,0x79,0x2e,0xcd,0x4f,0x99,0x18,0xdd,0x0d,0x85,0x45,0x66,0xad,0x79,0x64,0xeb,0x02,0xdc,0x7b,0x33,0xb0,0xcf,0x24,0x9c,0x27,0x69,0x8e,0x7d,0x68,0x51,0x20,0x8d, + 0x04,0x20,0x75,0xf7,0xe4,0x5f,0x40,0x12,0xe0,0xb4,0x2e,0x0d,0x8f,0x53,0xeb,0xa7,0x64,0x88,0xc8,0xd8,0x87,0x1f,0xef,0x01,0xa8,0xf3,0x95,0xb7,0x6e,0xb4,0x06,0x0b,0xb0,0x48,0x20,0x8d, + 0x04,0x20,0x75,0xcb,0x04,0xb9,0x7e,0xde,0xfa,0x49,0x7b,0x20,0x0a,0x24,0x53,0xa5,0x69,0x06,0x14,0x3f,0xc9,0x1b,0x93,0x51,0xc6,0xa9,0x36,0x73,0x4d,0xd1,0xd3,0x36,0xfc,0xed,0x20,0x8d, + 0x04,0x20,0x76,0x70,0xda,0x9e,0xd4,0x27,0x5b,0xf5,0x41,0x48,0xad,0xff,0x8f,0x3b,0x49,0x81,0x3c,0x09,0xd2,0x51,0xa4,0xdf,0x4e,0x8b,0x94,0xd0,0xe9,0x81,0xe7,0x16,0x25,0x92,0x20,0x8d, + 0x04,0x20,0x7e,0xc4,0x76,0x1b,0x58,0x2c,0x41,0x8d,0xaa,0x87,0x1b,0x89,0xf6,0x9f,0x99,0x55,0xd9,0x0d,0x39,0xef,0xde,0x69,0xf8,0xe5,0xa1,0xfd,0x76,0x6c,0x40,0x11,0xc4,0x6e,0x20,0x8d, + 0x04,0x20,0x7e,0xef,0xe1,0x40,0x48,0x56,0xcf,0x61,0x9c,0x95,0x64,0x1b,0x68,0xd0,0xf2,0x40,0xcc,0x39,0x42,0xb7,0xb0,0x44,0xcc,0x2c,0x0e,0xa3,0xf9,0xfd,0x45,0xe2,0x74,0x5f,0x20,0x8d, + 0x04,0x20,0x7f,0x84,0x36,0x20,0xe6,0x4b,0xf1,0x4e,0x8e,0x5d,0x90,0x5e,0x5b,0x26,0x42,0x2e,0xad,0xd5,0xcf,0x10,0x34,0xec,0xe0,0x92,0x83,0xff,0x09,0xc8,0xdc,0x0c,0x98,0xd6,0x20,0x8d, + 0x04,0x20,0x78,0xae,0xba,0xa8,0xc0,0x0c,0x9d,0x66,0x46,0xfd,0xe0,0x7a,0x13,0x40,0xcb,0x24,0x64,0x73,0x14,0x47,0x8f,0xae,0x0a,0xc4,0xe1,0x2b,0x4d,0x14,0x0d,0xeb,0xc9,0xcb,0x20,0x8d, + 0x04,0x20,0x79,0x2b,0xc3,0x40,0x24,0x92,0x5a,0xc0,0x6b,0x46,0x69,0xcc,0x27,0xfb,0x87,0x48,0xc8,0xd9,0xb7,0xe2,0x2e,0xb3,0x4b,0x30,0x4b,0x29,0x39,0x6e,0xd4,0x67,0xa2,0x43,0x20,0x8d, + 0x04,0x20,0x79,0x61,0x1f,0xa8,0x0b,0xd9,0x0b,0x99,0xdd,0x06,0x88,0x62,0x30,0xf6,0x15,0x3b,0xb2,0xfc,0xde,0x10,0x05,0xa7,0xd1,0xe1,0x81,0x5b,0x90,0x20,0xc4,0x9a,0x63,0xfe,0x20,0x8d, + 0x04,0x20,0x7a,0xbb,0x69,0xc4,0xee,0x9f,0x60,0x0e,0x15,0x22,0x90,0xf9,0xbd,0xd3,0xc9,0xf5,0x59,0xf6,0xda,0x5a,0x52,0x0b,0xeb,0xd8,0x38,0xf8,0x1b,0x34,0x9f,0x3b,0x49,0xf6,0x20,0x8d, + 0x04,0x20,0x7b,0x50,0xc3,0x37,0x7d,0xc0,0x51,0x84,0x93,0x7f,0xfc,0x96,0xce,0xd9,0x1f,0x07,0x18,0x45,0x66,0x25,0x4a,0x1d,0x00,0xb9,0xcb,0x4f,0xca,0x77,0x03,0xc1,0x44,0xde,0x20,0x8d, + 0x04,0x20,0x7b,0xe8,0x9c,0x1b,0x85,0xf7,0xac,0xfc,0x6a,0x36,0x98,0xd1,0x4d,0x8d,0xd2,0x87,0x7d,0xb6,0x57,0xa7,0x12,0x18,0xc0,0x38,0x04,0xc3,0x7b,0x14,0x02,0x9c,0x54,0x39,0x20,0x8d, + 0x04,0x20,0x7b,0xeb,0x51,0x99,0xa7,0x44,0x53,0x31,0xc5,0x64,0x36,0xdb,0x89,0xe2,0x49,0x1f,0xfa,0x64,0xc9,0x52,0x1e,0xe5,0xc0,0xbe,0x16,0xaf,0xf9,0x08,0xb8,0x39,0x5f,0x41,0x20,0x8d, + 0x04,0x20,0x7c,0x6c,0xf5,0x11,0x69,0xbf,0xc8,0xc0,0xc8,0xe0,0x2b,0xcd,0x0e,0x42,0x25,0x50,0x1b,0x55,0xc0,0xa6,0xb6,0x6c,0xc3,0xe4,0xb2,0x1c,0x6b,0xbb,0xd6,0x56,0xd8,0x79,0x20,0x8d, + 0x04,0x20,0x7d,0xb4,0xe8,0x7e,0x95,0x2e,0xee,0x6d,0x08,0xdc,0xe7,0x38,0xea,0x43,0xc0,0x84,0x54,0xc2,0xea,0x60,0x85,0xba,0xe4,0x65,0xa6,0x39,0x02,0x88,0x50,0xf7,0xae,0x2d,0x20,0x8d, + 0x04,0x20,0x7e,0x29,0x06,0x05,0x28,0x59,0x42,0x9a,0x77,0xb5,0x08,0x21,0x73,0x88,0xc6,0xac,0xb5,0x16,0x5a,0x46,0x37,0x50,0xcd,0x18,0x41,0xb4,0x98,0xd0,0xd5,0x51,0x40,0xc9,0x20,0x8d, + 0x04,0x20,0x7e,0x57,0x37,0x18,0xa4,0x2b,0x39,0x91,0xc9,0x3f,0x64,0xee,0x38,0x74,0x4f,0xfc,0x6d,0xc7,0x7d,0xa8,0xce,0x1d,0x32,0x4c,0x1d,0xc8,0xc2,0x9f,0xbb,0x1f,0xd4,0x55,0x20,0x8d, + 0x04,0x20,0x87,0x2c,0x02,0x2d,0x34,0x0b,0x6c,0x29,0xfe,0x9c,0x72,0xed,0xcb,0x47,0xef,0x9d,0x07,0x4a,0x3e,0x39,0xb7,0x07,0x3a,0xdc,0x08,0x75,0xf0,0x74,0x9e,0x83,0x7b,0xfa,0x20,0x8d, + 0x04,0x20,0x87,0x51,0x10,0x09,0xff,0x9b,0x7b,0xf2,0xa8,0xe7,0x11,0x2c,0x03,0xd2,0xfc,0xab,0x8a,0xdc,0xaa,0x0c,0x2a,0x56,0x39,0xb8,0x12,0x87,0x8f,0xce,0xd6,0xf5,0xee,0xbc,0x20,0x8d, + 0x04,0x20,0x80,0x1a,0xd7,0x5b,0x43,0x0a,0xa4,0x41,0xd7,0xf6,0x32,0x38,0x9e,0x99,0xe6,0x79,0x75,0x02,0x98,0x09,0x4e,0x56,0x46,0xb0,0x5f,0xab,0x22,0x5c,0x7e,0xea,0xa6,0xba,0x20,0x8d, + 0x04,0x20,0x80,0xd1,0xd0,0xd7,0x2a,0x66,0x25,0x72,0x68,0x1f,0xa6,0xdb,0x6c,0x4e,0xd0,0x84,0x42,0xea,0x26,0xe6,0xf8,0xe4,0xca,0x2a,0x8a,0x29,0x74,0xc4,0x9c,0x50,0x92,0x59,0x20,0x8d, + 0x04,0x20,0x81,0xc1,0x1f,0x3f,0x74,0xf3,0xb0,0x47,0x85,0xa6,0x28,0x6e,0x29,0x5c,0x78,0xca,0xbe,0xd6,0x32,0xf6,0xfd,0xdb,0x85,0x72,0x49,0x45,0x26,0x96,0x36,0xff,0xcd,0x5b,0x20,0x8d, + 0x04,0x20,0x82,0x37,0xf9,0xfc,0x41,0x86,0x82,0xa2,0xb8,0xb0,0xab,0x10,0xc7,0x0c,0x2b,0x86,0xa0,0xc7,0x71,0x2c,0x6f,0xdb,0x44,0x57,0xa4,0xc1,0xe7,0x78,0x85,0x3a,0xda,0xf6,0x20,0x8d, + 0x04,0x20,0x82,0x16,0x72,0x68,0x80,0x31,0xf5,0x64,0xf1,0x13,0x72,0x4b,0xcb,0xfd,0x94,0x70,0x14,0x5d,0xcc,0x3f,0x6f,0x23,0x50,0xf6,0x77,0xe8,0x90,0x78,0x1e,0x3e,0x3a,0x8d,0x20,0x8d, + 0x04,0x20,0x83,0x59,0x75,0xc9,0x71,0x3b,0xa0,0xe9,0x36,0x85,0xd5,0x79,0xd8,0xc9,0x05,0x35,0x9b,0x21,0xa7,0x84,0xfe,0x6c,0xaa,0xad,0xc8,0xf4,0xe8,0x1a,0xa9,0xa3,0x37,0xc0,0x20,0x8d, + 0x04,0x20,0x83,0xaf,0xa3,0x57,0x29,0x66,0x82,0x7c,0xe5,0x7f,0xdf,0x95,0x53,0xaa,0x0e,0xe8,0xdb,0x1c,0x80,0x71,0xa6,0x0b,0x90,0x2c,0x59,0x3e,0xaf,0xc3,0x6c,0xb4,0xee,0x9d,0x20,0x8d, + 0x04,0x20,0x85,0x18,0x7c,0xc7,0x10,0xd3,0x8c,0x7b,0x86,0x34,0x90,0x17,0x31,0xbb,0x9e,0xf5,0xff,0x27,0xca,0x1e,0x39,0x86,0x4a,0xb0,0x79,0x82,0x0f,0x07,0x3c,0x44,0x82,0xa4,0x20,0x8d, + 0x04,0x20,0x85,0x4a,0x42,0xd1,0x75,0x04,0xf5,0xec,0x8d,0xaa,0x74,0xfb,0x7c,0x29,0x23,0x67,0xdb,0x27,0x50,0x2c,0x5c,0x4d,0xbb,0xc6,0x76,0xcc,0x19,0x2e,0xb6,0x5b,0xa1,0xb4,0x20,0x8d, + 0x04,0x20,0x85,0x4a,0x72,0x58,0xe4,0xc9,0x82,0x82,0x3c,0x22,0xf8,0x69,0xf7,0x2e,0x4c,0x70,0x5c,0x86,0xcf,0x6f,0x54,0x71,0xef,0xda,0x8c,0x3c,0x8f,0x88,0x3a,0x4d,0x78,0x66,0x20,0x8d, + 0x04,0x20,0x85,0xcd,0x65,0x5a,0xcc,0xa2,0xf6,0xbb,0x94,0x66,0x24,0xe5,0x5a,0xac,0x84,0x46,0x74,0x11,0x9d,0x10,0xe9,0xf9,0xdd,0x6e,0x30,0xfd,0xcb,0xe1,0x68,0x45,0xbd,0xc5,0x20,0x8d, + 0x04,0x20,0x86,0x75,0xea,0xd8,0xc4,0x81,0x2e,0x1c,0x91,0xe8,0xac,0xad,0x0f,0x87,0x02,0x7d,0x12,0x36,0x9e,0x63,0xe6,0xdf,0x19,0x33,0x9a,0xfc,0x4b,0x4f,0x13,0x60,0xad,0x8d,0x20,0x8d, + 0x04,0x20,0x8e,0xab,0x0f,0xe6,0x33,0x03,0xe5,0x2e,0x0e,0xfa,0x28,0x6f,0xf2,0xb3,0x77,0xc1,0xbe,0x6b,0x0c,0xd0,0xf3,0x23,0xbd,0x14,0x45,0xf5,0x1d,0x54,0x6c,0xb3,0xf1,0x46,0x20,0x8d, + 0x04,0x20,0x8f,0x1a,0xc8,0xcb,0x44,0xb5,0x74,0x12,0xcb,0xd9,0xe6,0x7e,0x0f,0x61,0xe2,0x26,0x3c,0xd1,0xb3,0x16,0x25,0x2d,0xd7,0xd1,0x53,0x6a,0xde,0x22,0x49,0x7b,0x26,0xba,0x20,0x8d, + 0x04,0x20,0x8f,0xf2,0x1b,0x6a,0x57,0xec,0x87,0xb3,0x29,0x4e,0x7e,0x9e,0xed,0x14,0x7d,0xde,0x3d,0x79,0x67,0xeb,0x68,0x9f,0x6c,0x88,0xd8,0xaf,0xbc,0x69,0xca,0x30,0xfe,0x00,0x20,0x8d, + 0x04,0x20,0x88,0xb7,0xdd,0x54,0x50,0xc3,0x99,0xd1,0xbf,0x4a,0xf2,0x61,0x0b,0x16,0xc1,0x27,0x89,0xaf,0xa6,0xc0,0xca,0xb6,0x89,0xb9,0x30,0xbc,0x73,0x41,0x0a,0x29,0x14,0x23,0x20,0x8d, + 0x04,0x20,0x88,0xb7,0xf5,0xf8,0x12,0xd3,0x33,0x5a,0x7a,0x32,0x91,0x9f,0x49,0x63,0x5b,0xa1,0xe6,0x3c,0x92,0x23,0xe8,0x87,0xb6,0xb8,0x04,0xac,0xd0,0xa9,0xd7,0xad,0x19,0xd3,0x20,0x8d, + 0x04,0x20,0x88,0x81,0x5e,0x13,0xd4,0xcf,0xfe,0xed,0xbb,0xd0,0xf4,0x6e,0x4b,0xc9,0x10,0x6a,0xeb,0x5f,0xcc,0xb9,0x90,0xb7,0x27,0x6a,0xc2,0xb7,0x2d,0x08,0xc9,0x0f,0x77,0xfc,0x20,0x8d, + 0x04,0x20,0x88,0xe9,0x14,0x02,0x7d,0x3f,0x24,0xa1,0x66,0x1f,0xc1,0x29,0x8f,0x8a,0xba,0x20,0xa1,0x1c,0x4b,0x3b,0x08,0x56,0x5a,0x3b,0xb9,0xfd,0x38,0xfd,0xfc,0xc0,0xfd,0x40,0x20,0x8d, + 0x04,0x20,0x89,0x14,0xf2,0x8c,0xe1,0x35,0x28,0x34,0x0b,0xd6,0x97,0x64,0x26,0xbd,0x04,0x45,0xd3,0x9f,0x61,0x1a,0x39,0x0d,0xf4,0x90,0xfb,0x5a,0x77,0x85,0x68,0x57,0x66,0xbe,0x20,0x8d, + 0x04,0x20,0x89,0x1f,0xbc,0xcc,0x1c,0xd9,0xa9,0x09,0x5e,0x80,0x23,0x3b,0xc4,0xa9,0x38,0xf6,0x22,0x69,0x21,0xf7,0x45,0xf7,0x03,0x9e,0xad,0x9e,0x94,0x82,0x2b,0xe5,0x71,0xd2,0x20,0x8d, + 0x04,0x20,0x89,0x7d,0x5f,0x12,0xdf,0x32,0x76,0x19,0xad,0x7a,0x39,0xc3,0x12,0xd7,0x25,0x0c,0x15,0xb0,0x46,0xa4,0xea,0x2c,0x3d,0xe1,0x2c,0x16,0x18,0xcb,0xe2,0xc4,0x46,0x7c,0x20,0x8d, + 0x04,0x20,0x89,0x8a,0x59,0xb2,0x6e,0x02,0x31,0x1a,0x07,0x7d,0x1d,0x28,0x0e,0x61,0xd5,0xca,0x54,0x5a,0x32,0x96,0xa2,0x8a,0x69,0x80,0xd8,0x57,0xf7,0x87,0x42,0x44,0x59,0x32,0x20,0x8d, + 0x04,0x20,0x8a,0x65,0x55,0xdb,0x7c,0x38,0x17,0xff,0x71,0x50,0xac,0xb4,0xc2,0x78,0x03,0xbf,0x68,0x2b,0x17,0x84,0xed,0x3f,0xf4,0x2e,0x1d,0x06,0x60,0xbd,0x54,0x24,0x98,0x90,0x20,0x8d, + 0x04,0x20,0x8b,0x7f,0x0b,0xa8,0x27,0xe3,0xe8,0xaf,0x7a,0x2d,0x0d,0xce,0x7b,0xec,0xbe,0x6c,0xca,0x2f,0x55,0x39,0x5f,0x40,0xd5,0x37,0x28,0x11,0xec,0xf3,0x43,0x74,0x5e,0x7c,0x20,0x8d, + 0x04,0x20,0x8b,0xb4,0xb4,0x40,0xa6,0x0a,0x5f,0x80,0x8b,0xdd,0x05,0x30,0xf8,0x89,0x87,0xb1,0x4a,0x8f,0x59,0x1f,0x50,0x98,0x34,0x08,0x79,0xae,0xf1,0xea,0x12,0x91,0x56,0x39,0x20,0x8d, + 0x04,0x20,0x8c,0x38,0xca,0xb7,0x97,0xab,0x66,0xd6,0x5b,0xf2,0x73,0x23,0xa0,0xa2,0x92,0xb4,0xd0,0xad,0xf6,0xb7,0x71,0x9a,0x40,0xea,0x36,0x87,0xa4,0xf7,0x53,0xa5,0xc6,0xdb,0x20,0x8d, + 0x04,0x20,0x8c,0x3a,0x05,0xa8,0x77,0xa0,0xd2,0x41,0xc9,0x6e,0x22,0x3b,0x4e,0xdf,0x7f,0xe1,0x01,0x29,0x82,0x0e,0xbd,0x87,0xc7,0xf6,0x43,0x4e,0xc9,0x69,0x13,0xbc,0x89,0x94,0x20,0x8d, + 0x04,0x20,0x8c,0x6e,0x97,0xbe,0x70,0xbd,0x71,0x72,0x43,0xd0,0xf9,0x11,0xf2,0x7a,0x1e,0x7f,0x03,0x03,0xff,0xb5,0x99,0xdc,0xb1,0x4c,0x9b,0x97,0x3a,0xb3,0x68,0xf1,0xb3,0xa1,0x20,0x8d, + 0x04,0x20,0x8d,0x5f,0x62,0x56,0x46,0x78,0xd0,0xfc,0xe8,0x96,0x33,0x28,0x92,0x15,0x6d,0x46,0xce,0xbf,0x94,0x37,0x5f,0x16,0xa5,0xcd,0x22,0xba,0x65,0x92,0xc4,0x59,0x1d,0xf1,0x20,0x8d, + 0x04,0x20,0x8d,0xc8,0x9a,0x06,0xd6,0xf7,0xc8,0x61,0x5b,0xd2,0x79,0x29,0xc4,0xd5,0xbb,0xa1,0xf8,0x7e,0x8c,0x51,0x72,0x87,0xb0,0x90,0x6e,0xb8,0x35,0x00,0xf2,0xda,0xb6,0xbe,0x20,0x8d, + 0x04,0x20,0x96,0x8f,0xa3,0x0d,0x59,0xeb,0x15,0xc8,0x44,0xa2,0x32,0x08,0x27,0x08,0x2a,0x53,0x80,0xf9,0x1e,0x99,0x91,0x7a,0xcb,0xb7,0xa2,0x5f,0xbe,0xf9,0xe4,0xd3,0x8c,0x2b,0x20,0x8d, + 0x04,0x20,0x96,0xd4,0x2a,0xb8,0x45,0x35,0x4e,0x55,0x83,0x3c,0x73,0x95,0xbc,0xdf,0x07,0x82,0xe7,0xb5,0x0b,0x3d,0xcd,0x9a,0x49,0x5e,0x9b,0x85,0x35,0xab,0xb1,0x4c,0xba,0x80,0x20,0x8d, + 0x04,0x20,0x97,0x24,0x0c,0xbd,0xa4,0x97,0xbf,0x18,0x1a,0xea,0x59,0x7a,0xbf,0x42,0x26,0xca,0x32,0x0c,0x53,0x0c,0x80,0xf4,0x22,0x1e,0x3d,0xce,0xc6,0xdb,0x41,0x3a,0x9b,0x9a,0x20,0x8d, + 0x04,0x20,0x97,0x27,0xe2,0x3a,0x34,0xf0,0x79,0x79,0x7e,0x98,0x4f,0x1f,0xf0,0x9e,0x0e,0x0e,0xff,0xb0,0x6a,0x54,0x3c,0xfe,0x63,0x04,0x80,0x11,0x2a,0x85,0xd9,0x3f,0xee,0x97,0x20,0x8d, + 0x04,0x20,0x97,0xe8,0xe3,0x19,0x4c,0x95,0x68,0x72,0x97,0x8a,0xd4,0x7a,0x96,0xcc,0x42,0x47,0x53,0x68,0xd9,0xa9,0x31,0x83,0xa5,0x6b,0x36,0x36,0xe5,0xc2,0x33,0xf7,0x3f,0x51,0x20,0x8d, + 0x04,0x20,0x90,0x13,0x63,0xb6,0xb1,0x06,0x9f,0x80,0xee,0x5e,0xdb,0xd0,0xda,0x19,0x60,0x5a,0x28,0xdf,0xfa,0xc2,0xbd,0xcf,0x92,0xd0,0x1d,0x4f,0x7e,0x8c,0x37,0x77,0xfd,0x85,0x20,0x8d, + 0x04,0x20,0x90,0x30,0x0a,0x03,0xdd,0x3a,0x00,0x24,0xa6,0xd5,0xbd,0xd4,0x9b,0x35,0xe3,0xf1,0x04,0x9b,0x3a,0xda,0x9d,0x7c,0xaf,0xa2,0x8f,0xdd,0x77,0x28,0x92,0x00,0xe8,0xa1,0x20,0x8d, + 0x04,0x20,0x93,0x38,0xc2,0x74,0x27,0xa6,0xad,0x8f,0x06,0x9c,0xb7,0x76,0x4d,0x58,0xa5,0x52,0x00,0xb0,0x48,0x27,0xf1,0x5a,0x94,0x54,0xbb,0xd0,0x60,0x93,0xa5,0xa9,0x58,0x7d,0x20,0x8d, + 0x04,0x20,0x93,0xf3,0x65,0x80,0x66,0x54,0xcd,0xe9,0xc0,0x3c,0x65,0x1f,0x3c,0x2c,0xb4,0x1b,0xa0,0x0b,0xcb,0x26,0xcf,0x0e,0xe5,0xaa,0x45,0x9c,0x71,0x86,0x35,0x93,0x74,0x3d,0x20,0x8d, + 0x04,0x20,0x94,0x58,0x2a,0xc3,0x0c,0x25,0x8a,0x4c,0x35,0x63,0x33,0x8e,0xaa,0x71,0xf1,0xf5,0xa3,0x77,0x4e,0x83,0x2e,0x37,0xc5,0x96,0x29,0x93,0x9c,0x49,0xea,0x75,0x94,0x68,0x20,0x8d, + 0x04,0x20,0x94,0xfc,0x29,0xc9,0x1d,0xa6,0x6a,0xe0,0x96,0x10,0xfc,0x41,0x01,0x6a,0xc1,0xca,0xbf,0x37,0xb4,0x86,0x95,0x56,0x41,0xd9,0xcf,0x60,0x48,0x6c,0x16,0xe7,0x7a,0xb4,0x20,0x8d, + 0x04,0x20,0x95,0x2c,0x3a,0xf4,0x20,0x3f,0x68,0x36,0x4e,0x68,0x8e,0xfb,0x76,0x62,0xd2,0xd7,0x80,0x63,0x94,0xb8,0xf3,0x87,0xc2,0x25,0xd2,0xb9,0x4f,0xd5,0xfc,0xc6,0x81,0x03,0x20,0x8d, + 0x04,0x20,0x95,0x5d,0xcb,0x45,0x86,0x7f,0x99,0x61,0x7b,0x89,0x58,0xb3,0xb6,0x38,0x17,0x39,0xc5,0x9b,0x04,0x7c,0xc5,0x2c,0xc8,0xa1,0x5c,0x94,0x82,0x09,0x06,0x4b,0x7f,0xba,0x20,0x8d, + 0x04,0x20,0x96,0x2d,0x61,0x8b,0xf8,0x6f,0x35,0x07,0x1d,0xf0,0xa2,0x82,0x71,0xb6,0xed,0xd3,0xe6,0xca,0xfb,0x9b,0xe2,0xe9,0xd2,0xdd,0x04,0xa3,0xa1,0x0d,0xfc,0x55,0x87,0xe6,0x20,0x8d, + 0x04,0x20,0x96,0x47,0xa6,0xe0,0x3d,0xae,0xed,0x69,0x1c,0x3e,0x4c,0x06,0xa0,0x17,0x3c,0x55,0x1d,0x4a,0xd0,0x70,0xde,0x5b,0xb6,0x6e,0xa2,0xdf,0xbf,0x10,0x0e,0xe3,0x47,0x86,0x20,0x8d, + 0x04,0x20,0x9e,0xfb,0x9b,0xe5,0x1e,0x0b,0x27,0x0d,0x69,0x96,0x1b,0x30,0x6c,0x25,0xcf,0x3b,0x6b,0x3f,0xd8,0x95,0xac,0x6e,0x26,0x34,0x5a,0x7f,0x8d,0xc7,0x25,0xf6,0x3c,0xdc,0x20,0x8d, + 0x04,0x20,0x98,0x9d,0x1a,0xcb,0x18,0x3a,0x33,0x46,0x13,0x9d,0xf2,0x6e,0x89,0xf1,0x96,0xbc,0x35,0x33,0x41,0x4a,0xd6,0xb5,0x26,0xb2,0x39,0xe3,0xd0,0x4c,0x81,0x64,0x4f,0x6a,0x20,0x8d, + 0x04,0x20,0x99,0x27,0xc2,0x11,0x1d,0xa2,0x17,0x31,0x0c,0x7b,0x9f,0x8d,0x64,0x12,0x9d,0x3c,0x4a,0xc2,0xeb,0x49,0x22,0xbb,0x77,0xb7,0x31,0xa4,0x88,0xa4,0x9d,0x39,0x98,0x23,0x20,0x8d, + 0x04,0x20,0x99,0x8c,0x16,0x01,0x57,0xcc,0x47,0xf4,0xb1,0xc5,0x9f,0x54,0xda,0xa8,0xd1,0x87,0x6a,0x68,0x1b,0xa8,0x04,0x78,0x32,0x9c,0x30,0x4f,0x36,0x43,0xd5,0x0c,0xb8,0x6a,0x20,0x8d, + 0x04,0x20,0x99,0xe7,0x94,0xd3,0x88,0xcf,0x6b,0x89,0x89,0x3d,0x56,0xf4,0x64,0x5e,0x7b,0xc8,0x0d,0x09,0x02,0x98,0x56,0xcd,0x58,0x0a,0xd7,0xc3,0x04,0x12,0xea,0x87,0xd0,0xda,0x20,0x8d, + 0x04,0x20,0x99,0xee,0xe0,0x4b,0xc9,0x44,0x7a,0x96,0x2a,0x2e,0x46,0x51,0x66,0x20,0x82,0xac,0x55,0x3a,0x00,0x71,0xf2,0xf6,0x4e,0xa9,0x0f,0x3d,0xfe,0x4f,0x02,0xc7,0xea,0x12,0x20,0x8d, + 0x04,0x20,0x9a,0x0c,0xb7,0x33,0x0e,0x64,0x67,0x64,0x19,0x8e,0xbf,0x16,0x0c,0x8e,0xbd,0x09,0x60,0x2a,0x0a,0x50,0xd5,0xd2,0x86,0x22,0x6b,0x97,0xeb,0x5d,0x0b,0xeb,0x1b,0x8a,0x20,0x8d, + 0x04,0x20,0x9a,0xaf,0x7d,0x16,0xb9,0xe0,0xec,0x86,0x6d,0x52,0x87,0xb8,0x90,0x8b,0x84,0xcb,0xa6,0x36,0xfe,0x6c,0x01,0xde,0x23,0x1a,0x95,0x1b,0x5f,0x11,0xdd,0x26,0x66,0xbe,0x20,0x8d, + 0x04,0x20,0x9b,0xd2,0xbc,0x32,0x43,0x02,0xf0,0x0b,0x2f,0xd0,0xc5,0xb8,0xa9,0x88,0x09,0xe7,0x98,0xd0,0xf6,0x4b,0xc9,0x90,0xb7,0x79,0x8e,0x45,0x8e,0xaf,0x60,0xf2,0x92,0x69,0x20,0x8d, + 0x04,0x20,0x9d,0xc0,0x03,0xc0,0xea,0xf7,0x58,0xdb,0xe4,0x6d,0x0b,0xa1,0xe3,0xdb,0xe1,0xf9,0xa0,0xd4,0xd6,0x7c,0x04,0x9f,0x07,0x69,0x0a,0xa7,0x76,0xb5,0x77,0xf5,0x50,0xfe,0x20,0x8d, + 0x04,0x20,0x9e,0x6e,0x55,0x14,0x89,0x66,0x57,0xed,0xf2,0x10,0xc0,0x44,0xff,0x08,0xaa,0xb7,0xf8,0x7c,0xc7,0x1e,0x28,0x77,0xfd,0x06,0x58,0xf2,0xc5,0xbf,0xc8,0x8c,0x24,0x0c,0x20,0x8d, + 0x04,0x20,0xa6,0xb9,0xb0,0xb4,0xbb,0x7f,0x79,0x45,0x93,0x94,0x6f,0x54,0x39,0x64,0x5b,0x6f,0x46,0x2a,0xbd,0x3c,0x73,0x8a,0x33,0x06,0x9d,0xcc,0x15,0x68,0x44,0x4a,0x22,0x64,0x20,0x8d, + 0x04,0x20,0xa6,0x9a,0x97,0xdd,0x94,0xcc,0xa6,0x4c,0x61,0x8f,0xbc,0x33,0xdc,0xbd,0x9f,0x06,0xa3,0xb1,0x05,0xb6,0x78,0xbf,0x46,0x94,0xca,0xec,0x35,0x8d,0xae,0x76,0xc7,0x14,0x20,0x8d, + 0x04,0x20,0xa6,0xc8,0x38,0xcf,0x24,0x1d,0x7b,0x36,0x65,0x19,0x03,0x16,0x9f,0x37,0x8a,0x63,0xcb,0x16,0xf0,0x8a,0xad,0xca,0x97,0xe4,0x14,0xbb,0xb1,0xc4,0xbe,0x5b,0x74,0x72,0x20,0x8d, + 0x04,0x20,0xa6,0xe0,0x7b,0xd8,0x61,0x62,0x55,0x2d,0x1c,0x25,0x75,0x20,0x2a,0xb8,0x96,0x09,0x40,0x34,0xba,0x62,0x31,0x5a,0xbf,0x77,0xc0,0x38,0x77,0xb4,0x33,0x1c,0x03,0x41,0x20,0x8d, + 0x04,0x20,0xa7,0x04,0x38,0x9a,0x21,0x60,0xdb,0x7c,0xd8,0x51,0x28,0x88,0x90,0x89,0xea,0x70,0xb7,0x43,0x50,0x8e,0xa2,0xfb,0xa0,0xa2,0x22,0x97,0x8e,0x52,0x25,0x66,0x2b,0xd5,0x20,0x8d, + 0x04,0x20,0xa0,0xa6,0x1a,0xaa,0x6d,0xf4,0x5f,0x11,0xf6,0x20,0xd8,0x72,0xb6,0x5f,0x4d,0x59,0x9d,0x1d,0xb1,0xa4,0x5e,0x93,0x4f,0x79,0x04,0x4e,0x14,0x59,0xae,0x2e,0x2a,0xf1,0x20,0x8d, + 0x04,0x20,0xa1,0x0c,0x9c,0x3d,0x58,0x98,0x3b,0xda,0x68,0xfd,0x7c,0x81,0x05,0xd0,0x4f,0x76,0xe4,0xcd,0x9e,0x34,0x64,0xb0,0x6e,0x63,0xf0,0xd7,0x15,0x7b,0x6d,0x77,0x9a,0x95,0x20,0x8d, + 0x04,0x20,0xa1,0x95,0x0d,0xa9,0x7e,0xa3,0x52,0xce,0xd4,0xbf,0x9e,0xd7,0xc1,0x11,0xa9,0x97,0xf6,0x24,0x02,0x50,0x85,0x22,0x38,0x33,0x02,0xe6,0x51,0xd4,0xcc,0x3d,0xfd,0xf4,0x20,0x8d, + 0x04,0x20,0xa2,0x38,0x8d,0x2e,0x64,0x39,0x44,0x75,0x6c,0xaa,0x6f,0x8b,0x29,0x02,0x3c,0x83,0xb7,0xba,0xfe,0x18,0x26,0xe6,0x47,0x65,0x4c,0xc1,0x8e,0x9a,0x9a,0x01,0xb0,0x74,0x20,0x8d, + 0x04,0x20,0xa3,0x7e,0x09,0x5b,0x37,0xe1,0x92,0x4c,0x33,0x49,0x37,0x1b,0xee,0x9d,0xfb,0x6b,0x0c,0x5a,0x9f,0xbc,0x79,0xd4,0x87,0xfe,0x09,0x7d,0x06,0x40,0x25,0x83,0x50,0xcf,0x20,0x8d, + 0x04,0x20,0xa4,0x95,0xe9,0x6f,0x0a,0x2e,0x61,0xa6,0x3a,0xdf,0x13,0x2f,0xee,0xe7,0x00,0x81,0x44,0xa1,0xa4,0x59,0x52,0xbc,0x06,0x33,0x6e,0x24,0x05,0x28,0xa1,0x78,0xf5,0x6d,0x20,0x8d, + 0x04,0x20,0xa4,0x96,0xa4,0x92,0xd0,0x3f,0x70,0x08,0x3e,0x71,0x2e,0xd6,0x36,0x19,0x09,0xb5,0x1b,0x7d,0x5f,0x38,0x78,0x01,0x3c,0x62,0x4e,0x51,0x64,0x13,0x95,0x4d,0x83,0xa3,0x20,0x8d, + 0x04,0x20,0xa4,0xa7,0xfd,0x67,0x76,0x91,0x88,0x51,0x25,0x45,0xc0,0x43,0xa0,0x84,0xf8,0xa3,0xf5,0x91,0x0d,0x03,0xc8,0xef,0x99,0x70,0x0c,0x9a,0xf1,0xfa,0x06,0xba,0x5a,0x4c,0x20,0x8d, + 0x04,0x20,0xa6,0x6e,0x88,0x1c,0x92,0xf2,0xa4,0x50,0xb1,0x7d,0xbf,0xf9,0xc9,0xd7,0xa1,0x7a,0xa6,0x92,0x1d,0xc4,0x1f,0xbe,0xbd,0x94,0x24,0x23,0x8b,0xbb,0xc3,0x17,0x87,0x1f,0x20,0x8d, + 0x04,0x20,0xae,0xf5,0xf1,0x37,0x32,0xb7,0xca,0x72,0x21,0x9e,0xd9,0x89,0xa7,0x77,0x95,0x74,0xcd,0x90,0x47,0x0f,0x8d,0x49,0xca,0x4a,0xf9,0x80,0x2a,0xec,0x90,0x56,0x15,0x1b,0x20,0x8d, + 0x04,0x20,0xa8,0x02,0x67,0xf1,0x1f,0x5d,0x19,0xe5,0x09,0x57,0xf4,0xda,0x10,0xf4,0xc1,0x68,0xb5,0x2a,0x8f,0x65,0x29,0x1c,0x1d,0x8c,0x4e,0x8d,0x62,0xe8,0x0a,0xec,0x26,0xde,0x20,0x8d, + 0x04,0x20,0xa8,0x14,0xc8,0x00,0x55,0x8a,0xab,0xba,0x95,0xce,0x87,0xa5,0xf9,0x13,0x70,0xf4,0x67,0x89,0xd2,0xbd,0x7a,0xbe,0xe3,0xbb,0xbe,0x8f,0x83,0xc8,0x1d,0x7c,0x64,0x0a,0x20,0x8d, + 0x04,0x20,0xa8,0x9c,0x2f,0xac,0x6b,0x58,0xbd,0x83,0x60,0x6a,0x40,0x09,0xe6,0x39,0xf7,0x29,0xe8,0xd2,0x0c,0xc2,0x7a,0x42,0x79,0x7b,0x6c,0x53,0x3d,0x5f,0xce,0x28,0xa8,0xf8,0x20,0x8d, + 0x04,0x20,0xa8,0xb3,0x7b,0x4d,0x2b,0x52,0x16,0x49,0x9e,0x96,0xfe,0x23,0x02,0xb4,0x43,0xea,0xd4,0x5c,0xf9,0x25,0x91,0x14,0xbb,0x8a,0x1b,0x0f,0x31,0x82,0x1b,0xd7,0x5d,0x56,0x20,0x8d, + 0x04,0x20,0xa9,0x0c,0xbf,0x09,0x88,0xca,0xdc,0x38,0x52,0xc0,0xb5,0x9b,0xa3,0x26,0x65,0xba,0xdc,0x07,0xe8,0xed,0x81,0xc5,0xcc,0x3e,0xdc,0x64,0x33,0x3f,0xc1,0x67,0x52,0xdc,0x20,0x8d, + 0x04,0x20,0xa9,0x40,0x1a,0xbc,0x3d,0x96,0xc4,0x18,0xfd,0x65,0x13,0x50,0xce,0x8b,0xc9,0x7d,0x57,0x2e,0xed,0xfd,0x2f,0x2a,0xdc,0x91,0x61,0xa7,0xfb,0x73,0x51,0x86,0xec,0x29,0x20,0x8d, + 0x04,0x20,0xa9,0x63,0xba,0xbf,0x68,0x2c,0x65,0x80,0x76,0x99,0x2d,0xa3,0xe5,0x39,0xee,0x5b,0x8e,0x65,0x9e,0x3c,0x04,0x9d,0xd3,0xcd,0x8e,0xfa,0x65,0xd2,0x61,0xae,0xd9,0x63,0x20,0x8d, + 0x04,0x20,0xa9,0xa4,0x0d,0x47,0x4b,0x73,0xa8,0x41,0x93,0x86,0x8f,0xc7,0x52,0x8d,0x72,0x87,0x75,0x1a,0x85,0xe3,0x1a,0x17,0x3c,0xfa,0x3d,0x8d,0x9e,0x98,0x59,0xe3,0x66,0x59,0x20,0x8d, + 0x04,0x20,0xab,0x3d,0x24,0x57,0xa9,0x5f,0x6c,0x70,0xeb,0x50,0x84,0x6e,0x4f,0x74,0x4d,0xa4,0xf7,0x49,0x89,0x86,0x03,0xbf,0x30,0x25,0x4d,0x28,0xd9,0x3e,0x40,0x2a,0x90,0xe9,0x20,0x8d, + 0x04,0x20,0xab,0x1c,0x14,0x86,0x08,0xe0,0x9d,0x2d,0x7a,0x87,0xe3,0xdb,0x33,0x20,0x8b,0xbe,0x64,0xcf,0x4a,0xdb,0xe6,0x4f,0x05,0xa2,0xa9,0x01,0x0d,0x96,0xbd,0x70,0x4a,0xe5,0x20,0x8d, + 0x04,0x20,0xab,0x31,0x92,0xae,0x37,0x27,0x76,0xb8,0xe5,0x25,0x47,0x84,0xd9,0x17,0xbf,0x47,0x06,0xea,0xb5,0x13,0xc3,0xd2,0x7c,0x3a,0xaa,0x3f,0x67,0xe9,0xfd,0x6d,0xda,0xfc,0x20,0x8d, + 0x04,0x20,0xab,0xbd,0xfd,0xa9,0x19,0x3d,0x55,0xed,0x5a,0xe3,0x92,0x29,0xe1,0x17,0xb1,0x33,0x00,0xf5,0x4e,0xf7,0xd2,0xff,0x99,0xde,0xb9,0x2c,0x9a,0x3a,0x7a,0x4f,0x0f,0x68,0x20,0x8d, + 0x04,0x20,0xab,0x94,0xc5,0xf5,0xfd,0xe1,0x9d,0x0f,0xec,0xb4,0x1b,0xdd,0xa8,0xe6,0x30,0xd1,0x4d,0x72,0x29,0xae,0x02,0x7d,0xc0,0xfb,0x8b,0x80,0xb8,0x7a,0xc1,0xc7,0x22,0xe4,0x20,0x8d, + 0x04,0x20,0xac,0x2f,0xa9,0x9f,0xf3,0x9f,0x9a,0x63,0x6d,0xb4,0x12,0x2e,0x3c,0xae,0xb6,0xe7,0x43,0xf6,0x83,0x89,0xec,0xa2,0xab,0x0a,0x0b,0x33,0xb9,0x54,0x5e,0xbd,0x52,0x3b,0x20,0x8d, + 0x04,0x20,0xac,0xce,0x37,0xc9,0x6e,0x77,0x03,0x51,0xc1,0x66,0xc3,0x0f,0x9f,0xc6,0x05,0x71,0x6d,0xed,0xa6,0xba,0x41,0x28,0x48,0x02,0xde,0x43,0x6f,0x19,0xf5,0xc2,0x3f,0xc6,0x20,0x8d, + 0x04,0x20,0xad,0x12,0xd2,0x90,0xbe,0xdb,0x4f,0x56,0x6c,0xa3,0xc1,0x74,0x5b,0x2a,0x26,0xb0,0xc2,0x6b,0xf1,0x8e,0xaf,0x56,0x57,0xca,0x56,0x6b,0xd0,0xc0,0x9f,0x15,0xd4,0x31,0x20,0x8d, + 0x04,0x20,0xad,0x52,0xf0,0x0c,0xac,0x35,0x9c,0x25,0x6e,0x07,0x57,0x98,0x3c,0x66,0x28,0x12,0x16,0x69,0x04,0xc0,0xca,0x8d,0x5b,0x4f,0xfd,0x69,0x70,0x7b,0xa1,0x7d,0xb3,0x8d,0x20,0x8d, + 0x04,0x20,0xad,0xf1,0x28,0x47,0xa5,0xdd,0x98,0x26,0xb5,0x6a,0x14,0xf6,0x9f,0xad,0xef,0x4a,0x1b,0x8c,0x7e,0xac,0x43,0x4b,0xf8,0x13,0x53,0x9d,0x9f,0x22,0xde,0x37,0x9a,0x43,0x20,0x8d, + 0x04,0x20,0xae,0x56,0x40,0x4d,0xa2,0xb9,0x96,0x0c,0x97,0x16,0xf1,0x7c,0xa2,0x41,0x1b,0xd7,0xfc,0x5d,0x1c,0x96,0x32,0x24,0xe7,0xa0,0x77,0x3e,0x99,0x7d,0xd2,0xf4,0xe2,0x0a,0x20,0x8d, + 0x04,0x20,0xb6,0xa1,0x54,0xdd,0xba,0x22,0xd3,0x1e,0x9b,0x52,0xf3,0x78,0xf6,0xe2,0x1a,0xfa,0x6d,0x8c,0x0e,0x64,0x91,0x46,0x9d,0x65,0x7e,0x54,0xb3,0xb1,0x02,0x0e,0x83,0x11,0x20,0x8d, + 0x04,0x20,0xb6,0xc2,0xaf,0x27,0xaa,0xee,0xca,0xcb,0xf3,0x05,0xe7,0xd0,0x8f,0x2d,0x20,0xf5,0x65,0x33,0x2b,0x5e,0xea,0x2f,0x4c,0x44,0xcb,0x3b,0xd0,0xbe,0xf0,0x48,0x88,0x9d,0x20,0x8d, + 0x04,0x20,0xb7,0x1e,0x2b,0xd4,0x90,0xf3,0x25,0x26,0xab,0xe4,0x31,0xbc,0x3a,0x46,0xdf,0x68,0xf2,0xd9,0xfc,0x43,0xfb,0xca,0xde,0xc3,0x65,0xf5,0x25,0x0e,0xc0,0xcc,0xbf,0x26,0x20,0x8d, + 0x04,0x20,0xb7,0xe9,0x76,0x85,0xee,0xfb,0x7a,0x45,0x45,0x69,0x9b,0x7e,0x0c,0x1e,0x2c,0x88,0x53,0x02,0x0c,0xbf,0xca,0x2e,0xfc,0x2d,0x32,0x8d,0xb4,0x13,0xfb,0xe5,0xa8,0x4b,0x20,0x8d, + 0x04,0x20,0xb0,0x12,0x68,0x3f,0x4a,0xbe,0xf4,0x7d,0x58,0x81,0xdc,0x06,0x19,0x03,0x91,0xa2,0x1b,0xcc,0xed,0xeb,0xb8,0x8d,0xfb,0x8e,0x65,0x27,0xfb,0x47,0x48,0xcc,0xb6,0xde,0x20,0x8d, + 0x04,0x20,0xb0,0x5f,0xab,0x43,0x1b,0x87,0x29,0x9c,0xbd,0x12,0xd7,0x8b,0xf3,0xd4,0x80,0x72,0xaa,0x12,0xf5,0x2d,0x56,0xf3,0xcd,0x49,0x21,0xaf,0xa8,0x0a,0x5a,0x1e,0x76,0x36,0x20,0x8d, + 0x04,0x20,0xb0,0xe5,0x84,0x11,0xd5,0x9c,0xe6,0x97,0x1b,0x47,0x18,0xc2,0x2e,0x35,0xd0,0xdd,0xc6,0x8c,0x4d,0x12,0xfb,0x4f,0x45,0xf5,0x52,0xd4,0x50,0x4e,0x3d,0x64,0x29,0x37,0x20,0x8d, + 0x04,0x20,0xb1,0x68,0x51,0x13,0xfa,0x0b,0x54,0x70,0x13,0xfd,0x46,0x1a,0x37,0x85,0x07,0xcc,0x7f,0xeb,0x8b,0xcd,0x59,0x0e,0x7c,0xa0,0xf1,0x6b,0x20,0x38,0x63,0x57,0x64,0x69,0x20,0x8d, + 0x04,0x20,0xb1,0xf6,0x21,0xc9,0xa9,0xc2,0xeb,0x18,0x9c,0x2d,0x44,0xbf,0xb2,0xe2,0x32,0xc7,0x76,0x5c,0x15,0x40,0x49,0xc2,0x5f,0x8d,0x6e,0x0a,0x44,0x24,0xbf,0xa9,0xe9,0x2b,0x20,0x8d, + 0x04,0x20,0xb1,0xfa,0x87,0xad,0xc8,0x91,0x27,0x8b,0xa2,0x19,0xa4,0xca,0x3e,0xa8,0x1a,0xb9,0x5e,0xd2,0xca,0x59,0x99,0xec,0x41,0x59,0xcc,0x66,0x24,0x87,0xed,0x22,0x08,0x37,0x20,0x8d, + 0x04,0x20,0xb3,0x4f,0x12,0xa7,0x69,0xab,0xca,0xeb,0x40,0x1c,0xc1,0x78,0xcd,0xf4,0xe0,0x12,0x34,0x9b,0x9a,0xf0,0xd4,0xe8,0x64,0xc5,0x07,0xfc,0xf4,0xaf,0xa3,0x29,0xdf,0xbf,0x20,0x8d, + 0x04,0x20,0xb3,0x84,0xa5,0x22,0x4e,0xe8,0x0a,0x7e,0x7c,0xcf,0x78,0x17,0x05,0xe2,0x30,0x18,0xde,0x90,0x14,0xd3,0x87,0x65,0x89,0x51,0xea,0x1a,0x2d,0x69,0x41,0xbe,0x39,0xa1,0x20,0x8d, + 0x04,0x20,0xb4,0x4e,0x85,0x5d,0x4f,0xb4,0xa4,0x7d,0x25,0xbb,0x13,0x10,0x28,0x9b,0x2f,0x45,0x80,0x6a,0xdf,0x76,0x2d,0x62,0x18,0xb9,0x20,0x88,0x36,0xd2,0x05,0x76,0x06,0x8e,0x20,0x8d, + 0x04,0x20,0xb4,0xbb,0xa3,0xe9,0xa1,0x53,0x68,0x19,0x74,0xf6,0x8a,0xd4,0x01,0xfe,0x71,0x9c,0x5f,0x4d,0x83,0xaa,0x84,0x13,0x34,0x20,0xdf,0x25,0x17,0x65,0x1b,0xff,0xff,0x6b,0x20,0x8d, + 0x04,0x20,0xb4,0xc7,0x93,0x5b,0x9e,0xb8,0x70,0x34,0x53,0xe2,0xe5,0xfa,0xe4,0xe2,0xa2,0xe6,0x7d,0x47,0xb3,0x13,0xa0,0x0c,0x72,0x63,0xea,0xf3,0x4e,0xf0,0x01,0xb3,0x63,0x2c,0x20,0x8d, + 0x04,0x20,0xb5,0xdb,0x05,0x00,0x68,0xfb,0x22,0x70,0x05,0x33,0xfe,0xb4,0xb9,0xd5,0x3b,0x77,0x73,0x46,0x0d,0x69,0x20,0x2c,0x45,0x17,0xe6,0x57,0x64,0xb1,0x40,0x5a,0x28,0xc2,0x20,0x8d, + 0x04,0x20,0xbe,0x99,0x8f,0x18,0xc6,0x26,0x21,0xa5,0x0c,0x77,0x8e,0x82,0x01,0xef,0x57,0xf2,0xe8,0x00,0xd2,0x57,0xb0,0xc2,0x01,0x75,0x34,0x83,0xf9,0x9b,0x65,0x30,0xbe,0x1d,0x20,0x8d, + 0x04,0x20,0xbe,0x9b,0xf9,0x28,0x32,0x00,0xa8,0x18,0xe6,0x4d,0xa8,0xd3,0xdc,0xca,0x71,0xf4,0x93,0x23,0x66,0xad,0xf7,0x9e,0x3d,0x4d,0x4c,0xc8,0x47,0x9c,0xff,0x3d,0x79,0xd9,0x20,0x8d, + 0x04,0x20,0xbe,0xe4,0x29,0x2b,0xd7,0xe9,0x5d,0x2f,0x1d,0xae,0x42,0xfb,0xa6,0x6e,0xc4,0x21,0xcf,0xb2,0x90,0x85,0x85,0x93,0x5f,0xce,0x11,0x2a,0x49,0x17,0x49,0xd0,0x1d,0x46,0x20,0x8d, + 0x04,0x20,0xbf,0x19,0x64,0x59,0x52,0x4f,0x5e,0x45,0xfb,0xfa,0x59,0x86,0xc9,0x5c,0x53,0x5c,0xda,0x40,0x2c,0x39,0x18,0x37,0xc1,0x0f,0x54,0x8f,0xae,0xd6,0x1f,0x8e,0xd9,0xcc,0x20,0x8d, + 0x04,0x20,0xb8,0x60,0x1c,0x77,0xc4,0x14,0x0f,0x98,0x5b,0xa4,0xd7,0x41,0x04,0xf9,0x23,0xf8,0x77,0x3f,0x85,0x57,0x77,0xd4,0x7a,0x9f,0x7f,0x49,0x8c,0x92,0x1e,0x4f,0xc1,0xfe,0x20,0x8d, + 0x04,0x20,0xb8,0x6e,0x79,0xd4,0xd9,0xc7,0x10,0xac,0x59,0x0c,0xfe,0x56,0x4a,0x0a,0x81,0x93,0x57,0xf2,0x16,0x0e,0xb0,0xdd,0x0a,0x28,0xa9,0x37,0x18,0xac,0xcb,0x92,0x8f,0xaa,0x20,0x8d, + 0x04,0x20,0xba,0x19,0x26,0xb6,0x08,0x2c,0x9f,0x05,0x46,0xaa,0x19,0x03,0x28,0xdd,0x86,0x36,0x57,0x4f,0x70,0xf2,0xba,0x5f,0xb8,0x5b,0xbd,0xa3,0xa4,0x55,0xd4,0x26,0x7f,0x55,0x20,0x8d, + 0x04,0x20,0xba,0xf7,0x25,0xa5,0x9b,0x7b,0x68,0xb0,0xa7,0xed,0x8e,0x5e,0xf5,0x0b,0x85,0x6d,0xa7,0x72,0x4d,0x8f,0xc6,0xb9,0x1c,0xae,0x90,0xbc,0x79,0x4c,0x3f,0x60,0xa3,0x66,0x20,0x8d, + 0x04,0x20,0xbb,0x23,0xd2,0x3c,0x76,0xa5,0x70,0xbb,0x48,0x95,0xcc,0x37,0xa7,0x59,0x07,0x55,0xd5,0x60,0x23,0x06,0x3c,0x43,0xc6,0x26,0x92,0x2b,0x83,0xf1,0x80,0x0c,0x4b,0x30,0x20,0x8d, + 0x04,0x20,0xbb,0x78,0x28,0x84,0xe9,0xc6,0x04,0x14,0xe9,0xe0,0xdc,0x29,0x5f,0x6f,0x7b,0x46,0xae,0xf6,0x48,0x41,0xcc,0x8e,0xc9,0x48,0x27,0xa0,0x8e,0x2f,0xf0,0x7e,0xa3,0xce,0x20,0x8d, + 0x04,0x20,0xbb,0xc7,0x29,0xf9,0x7a,0x10,0x56,0x07,0x86,0x3c,0xa0,0x51,0xaa,0x86,0xad,0xd1,0xc3,0x18,0xf5,0x9c,0x92,0x57,0xd1,0xfd,0x11,0x7e,0x43,0xdc,0x2f,0x2e,0xd6,0x94,0x20,0x8d, + 0x04,0x20,0xbc,0x47,0xc7,0x7c,0x32,0xfe,0xbf,0xa7,0x84,0xf0,0x9c,0xe1,0x9c,0xd0,0x65,0x78,0xf2,0x9a,0xe5,0xcf,0x10,0x66,0x35,0x5c,0x97,0x22,0x49,0x40,0x9e,0x68,0x32,0x26,0x20,0x8d, + 0x04,0x20,0xbc,0xfa,0xf9,0xe8,0xcd,0xd4,0x1a,0xf8,0xe7,0xb5,0xa8,0xc2,0x49,0xf1,0xfc,0xb1,0x8b,0xb2,0x24,0x30,0xff,0xcd,0x40,0x63,0xa5,0xca,0x57,0x73,0x37,0xe3,0x63,0x73,0x20,0x8d, + 0x04,0x20,0xbc,0xd1,0xc5,0x0d,0x7c,0x72,0x65,0x2e,0x75,0xc8,0x77,0x4e,0x08,0xe4,0xc7,0x21,0x3f,0x98,0xea,0xc7,0xcb,0xba,0x66,0xf3,0xe5,0xff,0x22,0x63,0xf0,0xfb,0xaa,0xe1,0x20,0x8d, + 0x04,0x20,0xbe,0x79,0xed,0xa8,0xc3,0x91,0xc8,0xf4,0x97,0xe6,0x9b,0x65,0x74,0x05,0x20,0x73,0x26,0x1a,0x2a,0x47,0xd5,0x85,0xce,0x7e,0xe6,0x05,0x99,0x15,0xf0,0x21,0x28,0x72,0x20,0x8d, + 0x04,0x20,0xc0,0x52,0x8d,0x4a,0x55,0x17,0x12,0x4e,0x0a,0x19,0x08,0x07,0xa7,0x8b,0x31,0x38,0x1a,0x27,0x1d,0xb8,0xc7,0xbc,0xe3,0x48,0x2f,0x36,0xc7,0xe0,0xc9,0xf5,0x3f,0x81,0x20,0x8d, 0x04,0x20,0xc1,0x4c,0xed,0xee,0x68,0xa7,0xad,0xb6,0xc6,0xad,0x2e,0x2d,0xa6,0xb1,0xe2,0xb4,0xca,0xec,0xa1,0xa2,0x9b,0x7b,0xfe,0xfb,0xd8,0xea,0xf8,0x72,0x8a,0x73,0xa5,0x4c,0x20,0x8d, - 0x04,0x20,0xc1,0x59,0x44,0x81,0x9e,0x78,0x3f,0xda,0xb3,0xef,0xec,0x3e,0x6a,0x99,0x4e,0x14,0x32,0x2b,0x33,0xeb,0x30,0x5a,0xe1,0xda,0x6c,0xc9,0x6d,0xfa,0x4b,0x1d,0x1d,0x56,0x20,0x8d, - 0x04,0x20,0xc1,0x5f,0x0b,0x67,0x90,0x71,0x8d,0xa8,0xf6,0x43,0xb1,0x0c,0x63,0x1b,0x3f,0xf3,0xd8,0x7b,0xcc,0x86,0x6a,0x25,0x9e,0xf6,0x91,0xb6,0xc8,0x6a,0x8a,0x1a,0x26,0xc0,0x20,0x8d, - 0x04,0x20,0xc1,0x5f,0x41,0x32,0xbc,0xcc,0x9f,0x89,0xd0,0x32,0xe9,0x1e,0xdc,0x93,0x97,0x17,0x12,0xe8,0x37,0x1d,0xd4,0xbe,0x82,0xa5,0x5b,0xad,0x3d,0xce,0x02,0xf6,0x51,0x70,0x20,0x8d, - 0x04,0x20,0xc1,0x61,0xb9,0x12,0xe9,0xbe,0x69,0x6b,0x7e,0x6d,0xb0,0xbe,0x94,0xe8,0x93,0x3a,0x29,0xd2,0xf6,0x3e,0xe9,0x2c,0xfc,0x7b,0xce,0x96,0xdd,0x93,0xb8,0x89,0x27,0xda,0x20,0x8d, 0x04,0x20,0xc1,0x67,0x44,0x50,0x1f,0xe1,0x64,0xf6,0xc0,0x0d,0xa8,0x11,0x3d,0x73,0xd0,0x6f,0xaa,0xc0,0x07,0x80,0x76,0x18,0xf4,0x8f,0x6e,0x63,0xdf,0x4e,0x79,0x2a,0x87,0xff,0x20,0x8d, - 0x04,0x20,0xc1,0x6f,0x9e,0xec,0xc3,0x0d,0xe9,0xd3,0x81,0xe6,0xd9,0x3a,0xa0,0x03,0xaf,0xc5,0xde,0x18,0xbd,0x10,0x5f,0x93,0xf9,0x14,0x9c,0x47,0xcb,0x04,0xf0,0x2b,0x7c,0x1f,0x20,0x8d, - 0x04,0x20,0xc1,0xbb,0x70,0x92,0x59,0x45,0x10,0x04,0x1a,0xd8,0xba,0x62,0xde,0x8b,0xa7,0xaa,0x7c,0x5b,0x90,0xbc,0xe9,0x06,0xbf,0xbd,0x11,0xfc,0x51,0x26,0xc7,0xd4,0x6f,0x89,0x20,0x8d, - 0x04,0x20,0xc1,0xbf,0xd2,0x8b,0xbb,0x12,0x04,0x19,0x02,0x31,0x79,0x6b,0xa9,0x70,0x51,0x7a,0xaf,0xea,0x8d,0x34,0x0f,0x2a,0x0f,0x8a,0xa1,0x1d,0x05,0x6c,0x9e,0x45,0xf4,0x08,0x20,0x8d, - 0x04,0x20,0xc1,0x85,0x96,0xe9,0x6b,0x81,0xd5,0x2d,0xb8,0xf7,0xa9,0x44,0xae,0x2a,0x5c,0xe9,0x14,0x6e,0x5e,0x3b,0x5b,0xa2,0x8c,0x61,0xad,0x22,0x6d,0xa4,0x95,0x88,0xf9,0xd3,0x20,0x8d, - 0x04,0x20,0xc1,0x86,0x5b,0x44,0xdb,0xdc,0xb7,0x0b,0x20,0x11,0xb5,0xc2,0x44,0x81,0x6a,0x44,0x59,0x0a,0x23,0x76,0x4e,0x7f,0x62,0x88,0x4f,0x8a,0x63,0x8f,0x05,0x9d,0x58,0x3d,0x20,0x8d, - 0x04,0x20,0xc1,0x8f,0xc3,0xdf,0x94,0x30,0x1e,0x81,0xda,0xee,0x1a,0x93,0x1f,0x54,0xcb,0xf5,0x54,0x08,0x55,0x04,0xaa,0xb4,0x44,0x20,0x9f,0xae,0xc9,0x6a,0x55,0x35,0x36,0x99,0x20,0x8d, - 0x04,0x20,0xc1,0x97,0x5a,0xb4,0x3b,0x1a,0xb5,0x53,0xea,0xd6,0x33,0xc4,0xda,0xb3,0xd3,0xe2,0xcc,0x11,0x9d,0xb5,0x7e,0x38,0x92,0xa7,0x64,0x27,0x28,0x60,0xf2,0xf9,0xaa,0x63,0x20,0x8d, - 0x04,0x20,0xc1,0x9d,0x27,0x85,0xbf,0x18,0xba,0x0f,0x1c,0x10,0xa4,0x78,0x47,0x13,0x4e,0x4f,0x93,0x39,0xa5,0xc7,0x97,0x37,0x13,0xaf,0xac,0xd6,0x97,0x38,0xd0,0xfc,0x2e,0x7a,0x20,0x8d, - 0x04,0x20,0xc1,0x9d,0x6b,0x67,0xdf,0x55,0x6b,0x14,0x69,0x62,0xb2,0x9b,0x21,0x76,0xe9,0x1e,0x7e,0x52,0x82,0x7d,0x9c,0x14,0xcf,0x95,0x97,0x8c,0x72,0x53,0x56,0x0d,0xbb,0xae,0x20,0x8d, - 0x04,0x20,0xc1,0xad,0x4b,0x67,0xa0,0xa4,0xca,0x2e,0x4e,0x0b,0xa6,0x28,0xe2,0x04,0xc7,0x17,0xcb,0xe5,0x99,0x38,0x53,0x3c,0xe7,0xc7,0x0d,0x3e,0xcf,0xaa,0x95,0xfc,0xbb,0x0e,0x20,0x8d, - 0x04,0x20,0xc1,0xf8,0x41,0xa6,0xaf,0x0b,0xbb,0xda,0xc8,0x0d,0x51,0xfe,0x4d,0xee,0x9f,0xf9,0x1f,0xf2,0x00,0xfd,0x3f,0x4d,0x52,0x9a,0x9f,0x9f,0xd8,0x10,0xfd,0x4a,0x62,0x6a,0x20,0x8d, - 0x04,0x20,0xc1,0xf9,0x47,0x60,0xb9,0x26,0x3b,0xb1,0xb5,0xc9,0xf6,0x59,0xb2,0xc5,0x07,0x39,0xac,0xf8,0x16,0x0a,0xb6,0xfd,0x24,0xb2,0x12,0xa9,0x5a,0xbd,0xc6,0x0e,0x3c,0xbb,0x20,0x8d, - 0x04,0x20,0xc1,0xfb,0x49,0x7c,0x6a,0xd7,0x67,0x3b,0xaa,0x7e,0x62,0x09,0x19,0x6c,0x20,0xca,0xd9,0xb4,0xa2,0x8c,0x97,0x5b,0x6c,0xf9,0x99,0x1f,0x11,0xe5,0x37,0xae,0x46,0x52,0x20,0x8d, - 0x04,0x20,0xc1,0xc6,0x3c,0x05,0xef,0xf2,0xcd,0x4d,0xf1,0x1f,0xa5,0x22,0x38,0x1b,0xa9,0xcb,0x4a,0x30,0x26,0xd1,0xf8,0x9d,0xb9,0xd9,0x10,0x2f,0xde,0x66,0xa7,0x98,0x49,0xb2,0x20,0x8d, - 0x04,0x20,0xc1,0xd1,0x2b,0x2e,0x6a,0x8c,0xb7,0x47,0xd5,0x51,0xc1,0xa5,0x44,0x3a,0x9d,0x46,0x9a,0x96,0xe2,0xea,0xd9,0xad,0x39,0x30,0x51,0xee,0x1b,0xc5,0x95,0x0d,0xca,0x0a,0x20,0x8d, - 0x04,0x20,0xc1,0xd2,0xac,0x2c,0x53,0x2f,0x7f,0xf1,0x90,0xc2,0xfd,0x0a,0x52,0xd4,0xdb,0x34,0x87,0x73,0x36,0xfe,0xe3,0xc6,0x7c,0x96,0x89,0xba,0x4c,0x53,0x86,0x8b,0x64,0xc5,0x20,0x8d, - 0x04,0x20,0xc1,0xdb,0x90,0xf5,0xec,0x10,0x48,0x88,0x4b,0xc1,0xbb,0x37,0x7a,0xe4,0x78,0xd0,0xcc,0x15,0xcc,0x88,0x95,0xab,0x59,0x9b,0xd5,0x3a,0xa8,0xce,0x99,0x29,0xb7,0xc0,0x20,0x8d, - 0x04,0x20,0xc1,0xe1,0x89,0xd1,0x66,0xb0,0xe7,0x57,0x65,0x27,0xa6,0x1c,0x3d,0x0a,0x85,0x6a,0x82,0x7f,0xf5,0x86,0xc5,0xb9,0xb5,0x7a,0xde,0xd8,0x0f,0xa2,0xe6,0x8b,0x92,0x8b,0x20,0x8d, - 0x04,0x20,0xc1,0xe7,0x72,0xd0,0xbd,0xcd,0xe0,0xe8,0x2a,0x8e,0x19,0x5e,0xcc,0xc9,0xad,0x64,0xd9,0xbe,0xf3,0x1d,0x8c,0xc9,0x78,0x3d,0x73,0xea,0xf6,0x55,0x67,0x2a,0x92,0x54,0x20,0x8d, - 0x04,0x20,0xc1,0xeb,0x8b,0xa4,0xa0,0xa3,0xe6,0xf9,0x26,0x37,0x89,0x76,0xeb,0xce,0xbd,0xca,0xd3,0x4d,0x18,0x6f,0x44,0xed,0x20,0x04,0x4c,0x4f,0x4c,0x37,0xa6,0x3e,0x47,0x33,0x20,0x8d, - 0x04,0x20,0xc1,0xee,0x23,0x3f,0x1a,0x0d,0xac,0x73,0xbd,0x86,0x22,0xd7,0x83,0x1d,0x2f,0x55,0xbe,0x22,0xc5,0x2b,0x87,0xa7,0x18,0x6b,0x0b,0xdf,0xb7,0xa8,0xdc,0x91,0xb0,0x58,0x20,0x8d, - 0x04,0x20,0xc2,0x34,0xae,0x3a,0x6c,0xb5,0x12,0x6f,0x85,0x1d,0x45,0xbe,0x4b,0x41,0xb3,0x6d,0xc3,0xaf,0x27,0x0f,0x5d,0xfb,0x7c,0x2b,0xe1,0x4d,0x6a,0x0a,0x4f,0x58,0xd3,0x0e,0x20,0x8d, - 0x04,0x20,0xc2,0x37,0xa7,0x30,0xff,0x39,0xfb,0xc7,0x11,0xd3,0xe2,0x35,0x92,0x6a,0x68,0x2f,0x17,0xc1,0x58,0x67,0xcd,0xee,0xde,0x07,0x2c,0x9c,0x22,0xe9,0x96,0xf1,0x23,0xe7,0x20,0x8d, - 0x04,0x20,0xc2,0x38,0x6b,0xc3,0x1e,0xd8,0xa5,0x49,0xa8,0x80,0xde,0x65,0x2d,0x3a,0x38,0xcf,0x0c,0x49,0xeb,0x47,0x11,0x4c,0x86,0xd8,0x44,0x4e,0x3d,0xd3,0x6f,0xa4,0x17,0x67,0x20,0x8d, - 0x04,0x20,0xc2,0x38,0xda,0x98,0xee,0xaa,0x47,0xd0,0xe4,0x41,0x3a,0x27,0x52,0x64,0xfc,0xa5,0x8d,0xbd,0x37,0xd1,0xd6,0xc9,0x3f,0x6f,0x6e,0x1a,0xc0,0x2a,0x70,0x80,0x61,0x70,0x20,0x8d, - 0x04,0x20,0xc2,0x3b,0x7f,0x22,0x4d,0x32,0x7e,0xf4,0x56,0x3d,0xb4,0xfc,0x8d,0x8e,0x2d,0x9a,0xe1,0x2a,0x87,0x28,0x4b,0xc7,0x8d,0x77,0x8b,0x0a,0x46,0xd4,0x1e,0xec,0x2e,0x34,0x20,0x8d, - 0x04,0x20,0xc2,0x3d,0x46,0x29,0x4b,0x08,0x7d,0x58,0xf1,0x3f,0xe8,0x68,0xe9,0x4b,0xea,0x82,0x8c,0x29,0x0e,0x57,0xe9,0x6a,0x64,0x77,0xe7,0xfa,0x7a,0x1c,0xd1,0x64,0x71,0x36,0x20,0x8d, - 0x04,0x20,0xc2,0x02,0x62,0x95,0xee,0xf8,0xd0,0xcc,0x55,0x2b,0x0e,0x4b,0x1d,0x8d,0xac,0x6a,0xf5,0x1e,0x9c,0x31,0x7d,0xc3,0x31,0x3d,0x52,0x99,0xe4,0xa7,0x7a,0x83,0x94,0x55,0x20,0x8d, - 0x04,0x20,0xc2,0x11,0x84,0x52,0xcd,0x97,0x3b,0x93,0xb1,0x56,0x46,0xec,0x9a,0x32,0x07,0x6e,0x0a,0xab,0x28,0x07,0x09,0x8c,0x3f,0x1e,0x37,0x9b,0x63,0x72,0xc2,0xcd,0xd5,0x47,0x20,0x8d, - 0x04,0x20,0xc2,0x12,0x3b,0xb1,0x66,0x69,0x45,0x68,0x87,0xb9,0xbd,0x44,0x74,0x9c,0xd3,0x17,0x77,0xdf,0xb0,0x82,0xa3,0x9e,0xc4,0x36,0x89,0x53,0x9a,0xef,0x86,0xc9,0x34,0x29,0x20,0x8d, - 0x04,0x20,0xc2,0x24,0x4f,0xf5,0x2a,0x91,0xb5,0xf9,0x9f,0xfc,0x0d,0xdd,0xb0,0x7a,0x22,0x8e,0xcf,0x4a,0xc5,0xcc,0x3b,0x28,0x76,0xb3,0x1b,0x6e,0xda,0x61,0x18,0xaf,0x01,0xa1,0x20,0x8d, - 0x04,0x20,0xc2,0x24,0x41,0xfe,0x45,0xdd,0xf3,0x26,0xac,0xc6,0x25,0x10,0xe0,0x4b,0x4e,0x2f,0x05,0x18,0xad,0x6a,0x7e,0x74,0x62,0x84,0x78,0xf8,0xba,0x2c,0x48,0x1d,0x95,0xd1,0x20,0x8d, - 0x04,0x20,0xc2,0x25,0x5a,0x55,0x90,0x9b,0x7f,0x63,0xcf,0xc3,0x68,0xe3,0x0c,0xc8,0x6b,0xfd,0x69,0x27,0xde,0xd1,0x61,0x6d,0x6a,0x75,0xdf,0xb2,0xc6,0xdc,0xb7,0x8c,0x0e,0x48,0x20,0x8d, - 0x04,0x20,0xc2,0x26,0x22,0x61,0xdb,0xb5,0x74,0xc5,0x77,0xce,0x65,0x7c,0xc7,0x37,0x6d,0xf8,0xc4,0x58,0xfd,0x28,0x31,0x86,0xcc,0xad,0x93,0x42,0x9e,0xe0,0x33,0x4e,0x9a,0x09,0x20,0x8d, - 0x04,0x20,0xc2,0x28,0x49,0x42,0x02,0xfe,0xda,0xdf,0xaa,0xe0,0x18,0x2a,0xc5,0xd8,0x5f,0xc3,0x04,0x89,0x67,0x2a,0xf8,0x6f,0x2d,0x84,0x7c,0x2d,0xa8,0x20,0x38,0x4c,0x27,0xa0,0x20,0x8d, - 0x04,0x20,0xc2,0x33,0xf1,0xe9,0x6a,0x32,0xb4,0xc2,0xcd,0xfe,0x47,0x49,0xa9,0xc0,0xee,0x9c,0x15,0x04,0x9a,0xe1,0x1b,0x32,0x16,0x95,0x76,0xac,0x90,0xec,0x17,0x03,0x84,0x6a,0x20,0x8d, 0x04,0x20,0xc2,0x76,0x69,0x71,0xb5,0xa3,0x24,0x5c,0xcc,0x16,0x6f,0xd5,0x4e,0x09,0x8d,0x24,0x75,0x95,0xb0,0x4d,0xea,0x94,0x4d,0xec,0xdc,0x4e,0xab,0x8b,0x5e,0x51,0x83,0x02,0x20,0x8d, - 0x04,0x20,0xc2,0x77,0x0e,0x22,0x92,0x9d,0xca,0x28,0x70,0x28,0x90,0x69,0x6d,0xa6,0xb0,0x17,0xde,0x7d,0x18,0xcb,0x1f,0x7c,0xca,0xe2,0xf0,0xa9,0xad,0xa9,0xb2,0x48,0x68,0x6c,0x20,0x8d, - 0x04,0x20,0xc2,0x7d,0xef,0x16,0xe9,0x18,0xeb,0x9e,0x5f,0x2a,0x3c,0xf2,0x73,0xf7,0x76,0xaa,0x90,0xe0,0xd5,0x0b,0x18,0xb3,0x9b,0x87,0x6c,0x45,0xd2,0x87,0xc2,0x08,0x80,0x33,0x20,0x8d, - 0x04,0x20,0xc2,0x46,0x71,0xd2,0x27,0xf5,0x61,0x7a,0x61,0x46,0x65,0x24,0xa7,0x80,0x29,0xca,0x5a,0x8d,0x90,0xf7,0xb9,0xf7,0x98,0x76,0x24,0x1d,0x3a,0x78,0x0d,0x87,0x1d,0xba,0x20,0x8d, - 0x04,0x20,0xc2,0x54,0xe4,0xd5,0x32,0x37,0xb0,0x72,0xa7,0x4b,0x6e,0x82,0xf1,0x44,0xfa,0x27,0x8b,0x1e,0x6a,0x8b,0xde,0x33,0x22,0x04,0x39,0xd2,0x95,0x89,0x9b,0xef,0x2e,0xb3,0x20,0x8d, - 0x04,0x20,0xc2,0x68,0x3c,0xca,0x56,0xc5,0x4b,0x0c,0x12,0x67,0xd1,0x0c,0x72,0xd4,0x86,0xb9,0xbd,0x9f,0x50,0x2d,0xbf,0xf4,0xa6,0x41,0x2b,0x49,0xc6,0x4b,0x44,0x4a,0xb7,0x7c,0x20,0x8d, - 0x04,0x20,0xc2,0xb4,0x57,0x38,0xae,0x41,0x6e,0x60,0xc5,0xfd,0x07,0x3a,0xe5,0x58,0x24,0x5c,0x65,0x5c,0x08,0xd0,0x35,0xb5,0xcb,0xd7,0xbe,0x3b,0x29,0x0b,0xad,0xec,0xb7,0x99,0x20,0x8d, - 0x04,0x20,0xc2,0xb9,0x22,0x44,0x55,0xc6,0x6b,0x0b,0x98,0x26,0x6f,0xe5,0x16,0x78,0x84,0x45,0x57,0x97,0x03,0x73,0xe4,0xb3,0xbf,0x6c,0x18,0x30,0xb0,0x24,0x50,0x22,0x41,0x10,0x20,0x8d, 0x04,0x20,0xc2,0x8f,0xb9,0xf3,0x99,0x4b,0x92,0xf4,0xff,0xce,0xa4,0x08,0xef,0x7b,0x4b,0x49,0xf0,0x2d,0x4f,0xc4,0xdb,0x10,0xa2,0x7f,0xc8,0x83,0xc8,0xb1,0x0f,0x33,0x30,0x2f,0x20,0x8d, - 0x04,0x20,0xc2,0x94,0x75,0xb7,0xd7,0xf1,0xc4,0xc3,0xe2,0x37,0xec,0x6e,0x02,0xec,0x5d,0x05,0x0f,0xd5,0x71,0xeb,0x8b,0xc0,0x89,0x22,0x72,0xf6,0xe3,0xbd,0x90,0x56,0x53,0x26,0x20,0x8d, - 0x04,0x20,0xc2,0xa0,0x43,0xd9,0x7c,0xf9,0xed,0x87,0xd0,0xe7,0xa5,0x2e,0xa7,0xb8,0x97,0x70,0x96,0x3a,0xad,0x68,0xbc,0x0e,0xf5,0xbe,0x58,0xf6,0x19,0xee,0xd4,0x29,0x28,0x37,0x20,0x8d, - 0x04,0x20,0xc2,0xa9,0xa1,0x2e,0xd1,0xdd,0xf6,0xd1,0xe4,0xa9,0x1a,0xb6,0xee,0x49,0xee,0xcc,0xdd,0x0c,0x79,0xa3,0x04,0xd4,0x46,0xf6,0xce,0x79,0x80,0xf3,0x7e,0x0a,0xae,0x1f,0x20,0x8d, - 0x04,0x20,0xc2,0xad,0x1b,0x50,0xa5,0xb5,0x41,0x75,0xd9,0x15,0x9e,0xce,0xb3,0xe3,0x3a,0xc3,0xbb,0x71,0x93,0xe3,0xb7,0x2f,0xef,0xe0,0xc2,0xe5,0xcf,0xa9,0xf9,0x9c,0x47,0x44,0x20,0x8d, - 0x04,0x20,0xc2,0xf4,0xf8,0x90,0x01,0xc6,0xb1,0x0c,0x1d,0x95,0x46,0x21,0xcf,0x45,0xc0,0x7d,0x1e,0xc6,0xa1,0x33,0xd1,0xb6,0xcc,0xb2,0xb6,0x9d,0xdf,0x3a,0xe0,0x39,0xfc,0x43,0x20,0x8d, - 0x04,0x20,0xc2,0xf5,0x29,0xc8,0xe0,0x76,0x5f,0x88,0x4e,0x93,0xfb,0x3c,0xb6,0xf3,0xf9,0xd4,0x0e,0xb2,0x0d,0x4d,0xa5,0x8e,0x84,0xf9,0x55,0xbc,0xa8,0x00,0x23,0x8d,0xb6,0x3c,0x20,0x8d, - 0x04,0x20,0xc2,0xf7,0xf6,0xe0,0xfb,0xad,0x13,0x9d,0x17,0x11,0xce,0xc8,0xe8,0x3a,0x64,0x45,0xf0,0x8c,0xec,0x69,0xec,0x4a,0xd6,0xb2,0x26,0x58,0x8c,0x29,0x5b,0x21,0x24,0x02,0x20,0x8d, - 0x04,0x20,0xc2,0xf6,0x17,0x77,0x36,0xb4,0x8d,0xd1,0x84,0xf1,0x88,0x92,0xaa,0xbb,0x15,0xb5,0xae,0xfd,0xa8,0x23,0x33,0xe2,0x72,0x79,0x83,0xee,0x9c,0x1d,0x2e,0x20,0xfe,0x1b,0x20,0x8d, - 0x04,0x20,0xc2,0xc0,0xec,0x59,0xce,0x22,0x6a,0xf2,0xba,0x44,0xb5,0xd9,0x8b,0xa4,0xe2,0xd0,0x0e,0x52,0x3d,0x21,0xad,0x30,0x91,0x71,0xff,0x0e,0x19,0x64,0x44,0x97,0x5a,0x86,0x20,0x8d, 0x04,0x20,0xc2,0xc0,0xf8,0x9a,0xd3,0x47,0x07,0x2a,0x32,0xfd,0xbd,0x56,0x7a,0x2f,0x64,0x91,0x77,0x84,0x6c,0x81,0xc6,0x28,0x10,0xe8,0x76,0x29,0xac,0x4d,0xe7,0x12,0xae,0xc9,0x20,0x8d, - 0x04,0x20,0xc2,0xc2,0xb6,0xc4,0x7a,0x4b,0x4a,0x99,0xd2,0x53,0x5f,0xb1,0x3f,0x3d,0x17,0xe3,0x0d,0x08,0xf6,0x10,0x71,0x2b,0x46,0xb2,0xca,0xde,0x89,0xe2,0xde,0x1e,0xa2,0x76,0x20,0x8d, - 0x04,0x20,0xc2,0xc7,0x3b,0xfd,0xdd,0xc7,0x52,0x5d,0x52,0x71,0x8c,0xe0,0x5e,0xe0,0xbd,0xf0,0x14,0xe5,0xf7,0xb6,0x04,0x65,0xaa,0x5a,0xf4,0xaa,0x5d,0x40,0xd2,0x53,0x8c,0xd9,0x20,0x8d, - 0x04,0x20,0xc2,0xcf,0xba,0xad,0x14,0x7f,0x95,0xaf,0xbe,0x7a,0x99,0xed,0xcb,0x98,0xa6,0xa2,0x32,0x80,0x3a,0x41,0xee,0x36,0xea,0x90,0x9c,0xb7,0x87,0x9b,0x08,0x3e,0x38,0xbc,0x20,0x8d, - 0x04,0x20,0xc2,0xe5,0x56,0xa6,0x11,0x11,0x81,0x35,0x65,0x3d,0x31,0x55,0x69,0xf8,0x59,0xd6,0xfd,0x9f,0xfb,0x15,0x33,0xc9,0x45,0x98,0xd9,0x62,0xf7,0x70,0xfe,0x6d,0x0c,0xa7,0x20,0x8d, - 0x04,0x20,0xc2,0xe9,0x62,0x0a,0xcb,0x40,0x4b,0xd1,0xdb,0x52,0xa3,0xfd,0xc1,0xc3,0x86,0x97,0x04,0x51,0x9e,0x6a,0x29,0xdd,0x8e,0x8a,0x59,0x8d,0x69,0xfe,0xd9,0x69,0x24,0x00,0x20,0x8d, - 0x04,0x20,0xc2,0xf1,0x43,0x2d,0xfd,0x0e,0x9f,0xee,0x99,0x88,0x71,0x4e,0x4d,0x22,0x2f,0xbc,0xac,0xb3,0x90,0x43,0x20,0x8d,0xf1,0xeb,0xf0,0x38,0xac,0x43,0x90,0xd1,0xd1,0x0a,0x20,0x8d, - 0x04,0x20,0xc3,0x0d,0x87,0x0e,0xb9,0x99,0x65,0xc6,0xb5,0x09,0x4b,0x6c,0x8a,0xf8,0x80,0x19,0x27,0x74,0xb3,0xfe,0xea,0x2b,0xb8,0xe2,0x98,0x3c,0xa1,0xca,0x3d,0xa9,0xb3,0x44,0x20,0x8d, - 0x04,0x20,0xc3,0x11,0x6d,0x8f,0x8a,0x59,0x1e,0x7b,0x52,0xc1,0x51,0x86,0xf5,0xae,0x32,0xf1,0xe5,0x20,0xf2,0x55,0x11,0xb5,0x46,0x7e,0x43,0x66,0xcf,0x26,0xb5,0x52,0x0b,0x6a,0x20,0x8d, - 0x04,0x20,0xc3,0x1b,0x87,0x8f,0xf7,0x66,0x74,0x55,0x03,0x51,0xe6,0x2f,0x58,0x69,0x01,0x2f,0xe3,0x51,0xe1,0x7e,0x21,0x18,0xf7,0xbb,0xfc,0x89,0x48,0x7a,0x68,0x7a,0x74,0x14,0x20,0x8d, - 0x04,0x20,0xc3,0x1e,0xfe,0xa5,0x60,0x55,0x8a,0x74,0xe8,0x2e,0xcd,0xbd,0x6d,0xee,0x00,0x42,0xd5,0x18,0x06,0x2e,0x46,0x6e,0xcd,0xbc,0x65,0xbd,0x52,0x30,0xc5,0x56,0x9e,0x2f,0x20,0x8d, - 0x04,0x20,0xc3,0x23,0x46,0xb3,0x55,0x3b,0x81,0x1b,0x7e,0x2f,0x77,0x92,0x36,0x43,0x8c,0x25,0x7a,0x7c,0xfb,0x74,0x62,0xd2,0xa4,0x7b,0xb0,0xd5,0x77,0xaf,0xd5,0x8d,0xb7,0xac,0x20,0x8d, 0x04,0x20,0xc3,0x27,0xa3,0x8c,0xa6,0x1d,0xdd,0xa0,0x5a,0xa9,0xd2,0xb9,0x8e,0xcc,0x2f,0xa8,0x1e,0x9f,0xf5,0x3f,0xae,0xf9,0x3a,0xd5,0x71,0x86,0x39,0xc5,0xca,0xb5,0x18,0x9a,0x20,0x8d, - 0x04,0x20,0xc3,0x29,0x42,0x83,0xa1,0x8f,0xfa,0xb4,0x4a,0xc5,0x88,0x7c,0xf3,0x33,0x67,0x17,0x9d,0xef,0x99,0xb9,0x3e,0x0d,0xfa,0xbc,0xae,0xd4,0x25,0x6d,0xbb,0x16,0xfb,0x3e,0x20,0x8d, - 0x04,0x20,0xc3,0x2e,0x40,0x7f,0x92,0x95,0x93,0x88,0x56,0xbf,0x4c,0x8f,0xfe,0x0d,0xb5,0x43,0x05,0x28,0x72,0x2d,0x03,0xbb,0x7e,0x9b,0xe3,0x2a,0x5a,0x12,0xe3,0xdf,0x72,0x77,0x20,0x8d, - 0x04,0x20,0xc3,0x76,0x0a,0xba,0xc3,0x57,0x44,0xeb,0xfe,0x19,0xdf,0x25,0xb8,0x23,0x3a,0xa7,0x53,0xab,0x9b,0x68,0x8d,0xc4,0xa3,0xe5,0x0a,0x2a,0x6b,0xd1,0x09,0x30,0x88,0xd1,0x20,0x8d, - 0x04,0x20,0xc3,0x41,0xcc,0xba,0x30,0xef,0xc8,0x73,0x1c,0x96,0x59,0x0c,0x0f,0xac,0x3c,0xc9,0xaf,0xb9,0xf1,0x66,0xaf,0x55,0xae,0x3a,0x35,0xf8,0x79,0x01,0x1b,0x5f,0x95,0x70,0x20,0x8d, - 0x04,0x20,0xc3,0x45,0xf2,0x8b,0xe3,0xce,0xb9,0x2d,0xe9,0x4f,0xf3,0x9e,0x35,0x06,0xae,0x38,0x7f,0xc7,0x05,0x84,0xe2,0x4c,0xed,0xc5,0x4a,0xaa,0x73,0x8b,0x49,0x77,0x21,0x91,0x20,0x8d, - 0x04,0x20,0xc3,0x50,0xba,0xe6,0x94,0x59,0x81,0xa9,0xae,0xba,0x38,0x90,0x2f,0x83,0x02,0xec,0x1e,0x3e,0x37,0x3f,0x8f,0xe4,0xd9,0x60,0x89,0x7f,0x2b,0x7b,0x36,0xeb,0x73,0x4b,0x20,0x8d, - 0x04,0x20,0xc3,0x55,0x5f,0xb5,0x27,0xf1,0xd3,0xdb,0x92,0xd7,0xbe,0x36,0x6a,0xcd,0xb4,0xf3,0x85,0x8a,0xd3,0x93,0x34,0x57,0xb3,0x36,0xdd,0xbd,0xd4,0x37,0x96,0x47,0x02,0xde,0x20,0x8d, - 0x04,0x20,0xc3,0x60,0x6c,0xb9,0x35,0x1d,0xab,0xa8,0xd1,0x1a,0x8a,0xc8,0x23,0x87,0x5a,0x27,0x4f,0x68,0x21,0xeb,0x9d,0x24,0x36,0x95,0x55,0xfc,0xbd,0xd4,0x67,0xc5,0x34,0x5b,0x20,0x8d, - 0x04,0x20,0xc3,0xb9,0x85,0x4f,0xe7,0x69,0x9e,0xf0,0x55,0xd6,0xf9,0x75,0x2c,0xef,0xc0,0x4a,0xfd,0x6d,0xf0,0x36,0xf4,0x22,0x22,0x90,0x9e,0x46,0xe5,0xe4,0xa9,0x9e,0x91,0x1d,0x20,0x8d, - 0x04,0x20,0xc3,0x81,0x3d,0x07,0x9e,0x3e,0x49,0x43,0xe3,0xed,0xef,0xcc,0x96,0x16,0xe6,0x7b,0xc8,0x8d,0xdd,0xb9,0x1d,0xed,0x25,0xe9,0x0f,0x17,0x5b,0x8f,0x77,0xc9,0xfe,0x5f,0x20,0x8d, - 0x04,0x20,0xc3,0x83,0x10,0x7e,0x3b,0x51,0x26,0x9a,0x1e,0x3c,0x37,0x04,0x51,0xc2,0x8c,0x91,0x33,0xc7,0x33,0x44,0x21,0x6a,0xc3,0x5e,0x37,0x87,0xed,0x76,0xa9,0xd4,0xcb,0x04,0x20,0x8d, - 0x04,0x20,0xc3,0x8c,0x5b,0x8c,0x4e,0xd7,0xb9,0x34,0x84,0x24,0x22,0xb5,0xa7,0x6b,0xcb,0xcb,0x69,0xa3,0x69,0x56,0xac,0xb8,0xb6,0x16,0x7b,0x40,0x77,0x72,0x2d,0xa3,0x01,0xa6,0x20,0x8d, - 0x04,0x20,0xc3,0x99,0x6b,0x94,0x48,0x5a,0x40,0x3f,0x6c,0xc8,0x10,0x47,0xdf,0xf7,0xee,0x37,0x17,0x87,0x89,0xe7,0xe9,0x7a,0xc8,0x0d,0xd4,0xea,0x93,0xd8,0xba,0xca,0xc3,0xa6,0x20,0x8d, - 0x04,0x20,0xc3,0x9b,0xd3,0x67,0x90,0xfc,0x9c,0x81,0x23,0x88,0xfa,0x4b,0xac,0x80,0x48,0xa4,0x90,0xec,0x33,0xbe,0x4b,0xb4,0x10,0x4f,0x7e,0xdc,0xe3,0xb7,0x91,0xc8,0xa4,0x62,0x20,0x8d, - 0x04,0x20,0xc3,0x9c,0x10,0xff,0x43,0xc4,0xfd,0xa6,0xf4,0x6f,0x95,0x36,0x08,0x3e,0x00,0xda,0xd8,0x54,0xf8,0xc5,0xa4,0x5a,0xee,0x79,0xde,0xab,0x20,0x30,0xbe,0xd0,0xb6,0xf4,0x20,0x8d, - 0x04,0x20,0xc3,0xa6,0x28,0x61,0xa9,0xd7,0x15,0xa1,0x29,0x0b,0x77,0x78,0x74,0x9c,0xb3,0x4d,0x2b,0x5b,0x20,0x02,0x0e,0x5d,0x10,0x40,0x5a,0x54,0x3b,0x59,0xb2,0x57,0x5b,0xa5,0x20,0x8d, - 0x04,0x20,0xc3,0xf6,0x9a,0x3b,0xfe,0xd8,0xd8,0x8f,0xc7,0x07,0x55,0x76,0xa8,0x69,0x7a,0xf6,0x84,0xb5,0xc6,0x34,0xf2,0xa5,0xd9,0xaf,0x22,0x1a,0xee,0x30,0x29,0x88,0x7e,0xf2,0x20,0x8d, - 0x04,0x20,0xc3,0xf9,0xf3,0x50,0x7e,0x2a,0x65,0x54,0x9a,0x9d,0xe3,0x90,0x20,0x70,0x3b,0x42,0x79,0x92,0xc4,0x80,0x14,0xc4,0x07,0x37,0xc5,0xbf,0xeb,0xf7,0x94,0x37,0x0c,0x6b,0x20,0x8d, - 0x04,0x20,0xc3,0xfc,0xa5,0x99,0xb1,0xaa,0x25,0x0f,0xee,0x06,0xe0,0xd5,0xae,0xf4,0xff,0xa3,0x74,0xaf,0xbc,0x2a,0xf7,0xbc,0x99,0xe4,0x5a,0xd4,0x6e,0x99,0x68,0x8d,0xf7,0x1c,0x20,0x8d, - 0x04,0x20,0xc3,0xc0,0x0c,0x97,0x59,0xdc,0xfa,0x38,0x66,0x83,0x5e,0x0c,0x94,0xbf,0x01,0xd5,0x2a,0xaf,0x6c,0xd4,0x75,0x65,0x3c,0xd0,0x32,0x71,0xc2,0x12,0x39,0x8e,0x61,0x26,0x20,0x8d, - 0x04,0x20,0xc3,0xc0,0xac,0x4a,0x7c,0x08,0x4e,0x7d,0x26,0x90,0x1f,0xa3,0xfb,0xe1,0x90,0x6c,0x4d,0x6b,0xec,0x80,0x49,0x14,0xf3,0x79,0xdd,0x0f,0x0a,0x0c,0x88,0x58,0xdb,0x2c,0x20,0x8d, - 0x04,0x20,0xc3,0xd4,0x95,0x4f,0x83,0x6e,0x21,0x8f,0x4a,0xa4,0x16,0x06,0x83,0x4e,0x76,0x6c,0x93,0xdb,0xfb,0x9b,0xb7,0x88,0x35,0x7a,0x19,0x39,0x5d,0xa3,0xaa,0xf7,0xa7,0x16,0x20,0x8d, - 0x04,0x20,0xc3,0xd8,0x85,0x4e,0x5b,0x90,0x00,0x52,0xa7,0x54,0x77,0x72,0xc5,0x04,0x02,0xeb,0x3f,0x76,0x84,0x2b,0xba,0x82,0x77,0xdb,0xb7,0x9d,0xc2,0x06,0x01,0x30,0x2e,0xfd,0x20,0x8d, - 0x04,0x20,0xc3,0xda,0x86,0x82,0x3a,0x3e,0x03,0x5d,0xa4,0x6e,0xac,0x7e,0x0b,0xfe,0x64,0x87,0xac,0xfc,0xd6,0x36,0xf3,0x7f,0xc1,0x4a,0x1f,0x20,0xdd,0x2d,0x9f,0x34,0x61,0xf4,0x20,0x8d, - 0x04,0x20,0xc3,0xdc,0x86,0xe4,0xd0,0x5e,0xf2,0xee,0x8f,0x72,0x9c,0x5e,0xc0,0x35,0xa1,0x50,0xe6,0xd1,0xdd,0x57,0x58,0x13,0x63,0x09,0xe0,0x4f,0x1a,0x60,0x8b,0xac,0x84,0x73,0x20,0x8d, - 0x04,0x20,0xc3,0xdf,0xfd,0xbe,0xba,0xa8,0x92,0x58,0x6b,0x6b,0x9d,0x8e,0xe4,0xd2,0x24,0x65,0xee,0x55,0x36,0xd3,0x32,0xaf,0x2a,0xd8,0x9b,0xb2,0x06,0xb0,0x12,0xb8,0xbe,0xf8,0x20,0x8d, - 0x04,0x20,0xc4,0x3f,0x2f,0x3c,0x9f,0x4e,0x63,0x94,0xf6,0x97,0x5b,0xa3,0x89,0xda,0xe3,0xe8,0x65,0xc5,0x2d,0x38,0xab,0xf5,0xf0,0x28,0x71,0x78,0x1a,0x6f,0xfb,0xb8,0x1e,0xe4,0x20,0x8d, - 0x04,0x20,0xc4,0x1a,0x05,0xf1,0xe7,0xc7,0xed,0x9d,0xae,0x4e,0x46,0xb7,0x1c,0xa3,0x01,0xef,0x82,0xd0,0xe6,0xb5,0xc3,0xf1,0xa6,0x1b,0xaf,0x73,0x73,0x15,0x7b,0x70,0x7e,0x2a,0x20,0x8d, - 0x04,0x20,0xc4,0x1c,0x88,0x4f,0x6c,0x72,0xd3,0xcc,0x1a,0x1c,0xe6,0x70,0xc2,0x74,0xc3,0x09,0x88,0x4f,0x88,0x13,0x59,0x78,0xd1,0xa6,0x3c,0x66,0x10,0x81,0x0e,0x94,0xb2,0x09,0x20,0x8d, - 0x04,0x20,0xc4,0x2a,0x70,0xb2,0xa2,0xe7,0x51,0x8d,0x8e,0x2b,0xfb,0x44,0x4a,0x1e,0x86,0x1c,0xf4,0x52,0x56,0xd7,0xe5,0xfb,0xbc,0x80,0xa8,0x77,0x8f,0xaf,0x6b,0xca,0x2a,0xed,0x20,0x8d, - 0x04,0x20,0xc4,0x40,0xc0,0x86,0x0b,0xca,0x99,0xe7,0x75,0xea,0x17,0x61,0xdf,0x6d,0xa9,0xac,0x54,0x50,0x2d,0x70,0x70,0x6b,0x21,0x55,0xe3,0x42,0xba,0xeb,0x04,0x73,0x69,0xc2,0x20,0x8d, - 0x04,0x20,0xc4,0x47,0x36,0xcf,0x8b,0x53,0xf1,0x2c,0x62,0x35,0x8e,0x20,0x7b,0xdb,0x6a,0xe6,0xbe,0x6b,0xdb,0x28,0x74,0x87,0x34,0x3c,0xba,0x18,0x90,0x57,0x50,0xd6,0xcb,0x98,0x20,0x8d, - 0x04,0x20,0xc4,0x56,0x2e,0x47,0x70,0x28,0xa3,0xcb,0xf6,0xcd,0x12,0x29,0x38,0x8e,0xa0,0x94,0x5e,0x03,0xba,0x3b,0xa2,0x35,0xd5,0x98,0x66,0x55,0xc2,0x89,0xef,0x36,0x9b,0x2c,0x20,0x8d, - 0x04,0x20,0xc4,0x58,0xf0,0x48,0x69,0x60,0x7f,0xf7,0x35,0xdc,0x17,0xa2,0x93,0xeb,0x85,0x4f,0x4d,0x3f,0x84,0x29,0xbf,0xdb,0x7a,0x47,0x13,0x53,0x2e,0x1b,0x5b,0x46,0x03,0x3d,0x20,0x8d, - 0x04,0x20,0xc4,0x60,0xe5,0xd8,0x0e,0xbb,0xc1,0xbd,0x0a,0xda,0xc9,0x0c,0xd0,0x18,0xcc,0x6a,0x28,0x48,0xfb,0xd4,0x61,0x57,0x96,0xa4,0x1e,0x18,0x9f,0xfa,0x0e,0x0f,0x03,0x80,0x20,0x8d, - 0x04,0x20,0xc4,0x6c,0xa9,0x20,0xcf,0xbf,0x0a,0xe8,0x2e,0xcd,0x2f,0x85,0x7b,0x4d,0xef,0xbe,0xb3,0xa6,0x49,0xcc,0x7a,0x0d,0xfd,0x8d,0x42,0x66,0xf8,0xfb,0x49,0x98,0xe8,0x6d,0x20,0x8d, - 0x04,0x20,0xc4,0x70,0x13,0xb3,0x44,0x97,0x24,0x8a,0x3d,0x2d,0xc2,0x4a,0x5a,0xa0,0x8c,0xac,0x2f,0xae,0x32,0x09,0xeb,0x51,0x66,0x6a,0xc5,0xef,0xa4,0xf1,0xc1,0x76,0x05,0x39,0x20,0x8d, - 0x04,0x20,0xc4,0x73,0x65,0xee,0x21,0x2a,0x6f,0xf2,0x60,0x38,0x4d,0x5a,0x9c,0xeb,0x1f,0x83,0x2a,0xf6,0xa8,0x97,0x53,0x30,0xb8,0x3e,0xd2,0x0f,0xd1,0x57,0x9b,0xc2,0x3f,0x34,0x20,0x8d, - 0x04,0x20,0xc4,0xb4,0xca,0x62,0xa2,0x6b,0xc6,0x01,0x92,0x73,0xc8,0x2a,0xb2,0x1f,0xf0,0x8b,0x7f,0x3f,0x47,0xe4,0xd4,0xdc,0x12,0xbf,0xf8,0xb9,0x67,0x30,0x7c,0x99,0xd2,0x3d,0x20,0x8d, - 0x04,0x20,0xc4,0x8e,0xfd,0x1b,0xc1,0xee,0xda,0x32,0x13,0x3b,0xe3,0x6e,0xd5,0x70,0x39,0xf0,0xa0,0x1c,0xac,0xb7,0x80,0xcc,0x64,0x7c,0x33,0x82,0xed,0x9b,0xe6,0x82,0xfc,0xac,0x20,0x8d, - 0x04,0x20,0xc4,0xa1,0xd8,0xcd,0xe5,0xca,0xb3,0xd3,0x4f,0x52,0xf6,0x90,0x30,0xc8,0x7f,0x91,0x05,0x9d,0xa4,0x8f,0xca,0xe8,0xff,0x1e,0x05,0xec,0xe6,0x3a,0x4e,0x43,0x65,0x8d,0x20,0x8d, - 0x04,0x20,0xc4,0xb1,0x7e,0x90,0x06,0xb3,0x60,0xf2,0x91,0x99,0xd3,0x4f,0x61,0x5e,0x5a,0x16,0xc9,0x42,0x41,0x5d,0x2e,0xd2,0xdc,0x57,0x05,0x81,0x5a,0xed,0xbc,0xab,0x14,0x0b,0x20,0x8d, - 0x04,0x20,0xc4,0xf5,0x5a,0x07,0xcb,0x58,0x88,0x6b,0xd2,0x82,0xa6,0xd0,0x45,0x26,0x05,0x7b,0x03,0x8c,0xf1,0x51,0x25,0x2f,0x7e,0x4a,0x9a,0x7c,0x04,0x49,0xdb,0xea,0x0a,0x82,0x20,0x8d, - 0x04,0x20,0xc4,0xc1,0xf8,0x7e,0xbd,0x5a,0xb3,0x3e,0x67,0x0f,0xdb,0x39,0xc1,0x5c,0x43,0x9e,0x19,0x73,0x32,0x90,0x1b,0x66,0xd0,0x1b,0x3e,0x3e,0xcf,0x64,0x0d,0x90,0x71,0x01,0x20,0x8d, + 0x04,0x20,0xc4,0x22,0xd5,0x31,0xb6,0x7e,0xb6,0x01,0xe2,0x56,0x4d,0x5b,0x5b,0x7e,0x98,0x94,0xbf,0x59,0x84,0xa2,0x40,0x95,0x0f,0x50,0xdf,0x46,0xfa,0x30,0x15,0x86,0x2a,0x47,0x20,0x8d, + 0x04,0x20,0xc4,0x89,0xef,0x0d,0x22,0x1c,0x56,0xc4,0xd6,0xeb,0xc2,0x03,0x8c,0x13,0x72,0xfc,0x7a,0x7a,0xf3,0xfc,0x44,0xc8,0x09,0x6e,0x6f,0x5c,0x34,0xfd,0x14,0x0c,0x95,0xd4,0x20,0x8d, + 0x04,0x20,0xc4,0xc2,0x40,0x14,0x0b,0x78,0xa6,0xb9,0x5f,0x52,0xd4,0x1e,0x76,0x82,0xca,0x00,0x67,0x4d,0x24,0x3b,0x6d,0x41,0x15,0x5a,0xbd,0xf8,0x60,0x36,0x5c,0xcc,0x39,0x34,0x20,0x8d, 0x04,0x20,0xc4,0xd1,0xa7,0x16,0x50,0x37,0xd5,0xcc,0x85,0x6d,0xf0,0x21,0x7e,0x66,0x00,0x74,0x75,0x97,0xb1,0x72,0x20,0x70,0xb4,0xdd,0x74,0xfa,0x45,0x99,0x26,0x13,0x1f,0x05,0x20,0x8d, - 0x04,0x20,0xc4,0xd4,0xa8,0x11,0x0a,0xff,0xf2,0x94,0xd8,0x01,0x90,0xd6,0x29,0xd2,0x8c,0xdf,0xd3,0x1d,0xc7,0x51,0x37,0x84,0xab,0xd0,0x79,0x07,0xf1,0xf9,0xa0,0x0b,0x84,0x75,0x20,0x8d, - 0x04,0x20,0xc4,0xe1,0xca,0x3a,0xd1,0xf5,0x6d,0x84,0xb2,0x29,0xa8,0x05,0xf0,0x21,0x89,0x4a,0xf3,0x85,0x95,0x87,0x81,0xdb,0xbc,0xf0,0x82,0x23,0x59,0xd1,0x8f,0xd4,0xd0,0x85,0x20,0x8d, - 0x04,0x20,0xc4,0xe0,0x79,0x39,0x6a,0xfb,0xe1,0x48,0xf4,0x54,0xd1,0x41,0x78,0xd0,0x87,0xad,0xff,0xac,0x21,0x16,0x0e,0xf6,0xfe,0x4b,0x23,0x6e,0x50,0x34,0xc1,0x52,0x03,0x5f,0x20,0x8d, - 0x04,0x20,0xc4,0xe1,0x98,0xb3,0xe5,0x51,0x36,0xa8,0x18,0xfd,0x0f,0xb5,0x30,0x43,0xf8,0xc1,0x12,0x69,0x8f,0x78,0xbd,0x80,0x82,0xa7,0x4f,0x43,0x1d,0x00,0x96,0x1c,0x7f,0xee,0x20,0x8d, - 0x04,0x20,0xc4,0xe2,0x7a,0xe2,0x4c,0x7f,0x11,0x0d,0x42,0x8c,0x1c,0x5e,0x67,0xf7,0x90,0xdd,0x24,0x75,0x17,0xbb,0x0f,0x91,0xc7,0x5d,0xe3,0x19,0xb9,0x16,0x2d,0x5f,0x38,0x41,0x20,0x8d, - 0x04,0x20,0xc4,0xf0,0xdd,0x13,0x61,0x53,0x0c,0x0a,0xc7,0x06,0x7a,0xbb,0x1c,0xe0,0x65,0x1b,0x0e,0xf5,0x12,0x22,0x10,0xa0,0x20,0x2a,0x5b,0xbc,0xda,0x13,0x43,0xb0,0x96,0x0d,0x20,0x8d, - 0x04,0x20,0xc4,0xf3,0xe7,0x57,0xcb,0xeb,0x8a,0x74,0xd0,0x6b,0x2a,0x3a,0xad,0x79,0x72,0x37,0x2b,0xbf,0x3f,0xf7,0xb0,0x90,0x02,0xe3,0x52,0x18,0x29,0xc1,0x37,0xce,0xcd,0xcc,0x20,0x8d, - 0x04,0x20,0xc4,0xf2,0xd6,0x79,0x36,0x03,0xcd,0xd3,0xec,0xa8,0x8a,0x19,0x00,0xfc,0x0e,0xd1,0xbf,0x44,0x1c,0x0a,0x36,0xcd,0x3f,0x1c,0x4f,0x2c,0x14,0xa3,0x0b,0x04,0x62,0x96,0x20,0x8d, + 0x04,0x20,0xc4,0xd9,0xd4,0x1e,0xce,0x2d,0x2f,0xc5,0x4e,0xe7,0x9d,0xc1,0xce,0xc8,0xe1,0x48,0x08,0xbc,0x07,0x2c,0x68,0x7f,0x48,0x21,0x6b,0x7d,0xf4,0x8c,0x33,0xb3,0x50,0x5b,0x20,0x8d, 0x04,0x20,0xc5,0x3c,0x85,0x9a,0xe9,0x29,0x4a,0x30,0xec,0xb0,0xfc,0xa3,0x6b,0x33,0x3e,0xc3,0x1f,0xb2,0xdc,0x24,0x8c,0xa6,0xf5,0xfa,0xa3,0x70,0x99,0x70,0xc6,0x25,0xe9,0x37,0x20,0x8d, - 0x04,0x20,0xc5,0x3e,0x2e,0xa9,0x26,0x62,0xc4,0x8e,0x02,0x2e,0x2b,0xcd,0x0e,0x8f,0x50,0x97,0x4b,0x50,0xdb,0x79,0x00,0xbb,0xa6,0x81,0x8f,0x6e,0xaa,0x2f,0x56,0xe8,0x60,0xbd,0x20,0x8d, - 0x04,0x20,0xc5,0x0a,0x4d,0xbb,0xb7,0xfc,0x9f,0x80,0xcb,0xb3,0x55,0x3d,0xc8,0xf8,0xf9,0x0c,0x45,0xcf,0x52,0x1e,0x46,0x55,0x8f,0x67,0x63,0xc5,0x42,0x0d,0x61,0x81,0x5d,0x48,0x20,0x8d, - 0x04,0x20,0xc5,0x0e,0x40,0xcd,0xe1,0xf5,0x22,0xf9,0x46,0x3b,0x36,0xea,0xaf,0xcc,0x4b,0xea,0xdf,0xd1,0xcf,0xea,0x10,0x13,0xfc,0xbc,0xce,0xbf,0x63,0xcb,0xf9,0xf3,0xc4,0xaf,0x20,0x8d, - 0x04,0x20,0xc5,0x20,0xe4,0x1e,0x3c,0x7f,0xfd,0x3d,0x62,0x8f,0xbd,0x04,0x8a,0x44,0x4f,0xcc,0x90,0x9e,0xa3,0x7a,0x23,0x52,0xb9,0x61,0xb0,0x74,0x75,0xd2,0x9c,0x75,0x40,0xef,0x20,0x8d, 0x04,0x20,0xc5,0x2f,0xbd,0x67,0xd1,0xea,0xc9,0x83,0x84,0x71,0x30,0xdf,0x34,0x72,0x46,0x35,0xf0,0xec,0x6f,0x7e,0x80,0x7f,0xb4,0x03,0xd2,0x57,0x48,0x62,0xad,0x1d,0x84,0xaa,0x20,0x8d, - 0x04,0x20,0xc5,0x74,0x4c,0x92,0x10,0x29,0x1c,0xf8,0xcd,0x1b,0xf4,0x38,0x51,0xcb,0x62,0x54,0x39,0xba,0x8e,0xbf,0xaa,0xa7,0x02,0xbd,0xba,0x6b,0xeb,0xe4,0x49,0xa1,0xb8,0x31,0x20,0x8d, - 0x04,0x20,0xc5,0x7e,0x04,0x34,0x38,0xbe,0x7d,0x62,0x25,0x27,0x7a,0x4d,0x9b,0xf8,0xc7,0x13,0x98,0x3b,0x0f,0x6a,0xf9,0x44,0xb8,0xd3,0x96,0x73,0x9d,0x71,0x3a,0xb8,0x4d,0xa2,0x20,0x8d, - 0x04,0x20,0xc5,0x7e,0xb5,0x8b,0x03,0xb5,0x51,0xa6,0x72,0xef,0x6d,0x16,0x73,0x5c,0x51,0x49,0x3d,0x59,0x5a,0x72,0x04,0xa9,0xd0,0x85,0x86,0xbd,0x15,0xb5,0x99,0x6d,0xdf,0xe6,0x20,0x8d, - 0x04,0x20,0xc5,0x4d,0x9a,0xb0,0xfc,0x69,0x91,0xbf,0x66,0xad,0xfb,0xc9,0xb0,0xb8,0x52,0xba,0x7c,0xf1,0x08,0x05,0x3f,0xeb,0xeb,0x32,0x56,0x50,0xdc,0x10,0xdc,0x79,0x3e,0xc3,0x20,0x8d, - 0x04,0x20,0xc5,0x4f,0x55,0xf4,0x35,0x4b,0xfa,0xb4,0xb1,0xce,0xa2,0x59,0x6f,0xf2,0xc3,0xc4,0x1a,0x7a,0xd9,0x6c,0xe7,0x3f,0xef,0x5a,0xc6,0x87,0x66,0x76,0xe4,0x53,0xc3,0x51,0x20,0x8d, - 0x04,0x20,0xc5,0x5a,0xf7,0xd7,0x6d,0xd9,0xec,0x4b,0xae,0xb4,0x31,0x6a,0x8b,0x57,0x7b,0xc0,0x81,0x5b,0x8e,0xcd,0x3e,0xb8,0x37,0xcb,0xb5,0x7e,0xf1,0xf5,0x5b,0xca,0xc9,0x37,0x20,0x8d, - 0x04,0x20,0xc5,0x64,0xe5,0x5b,0xde,0x67,0xd5,0x08,0x41,0x37,0x0f,0x18,0xd9,0xa6,0xb6,0x3b,0x5e,0xe7,0x55,0xc4,0x17,0xa3,0x17,0xc2,0x63,0xc9,0x3c,0x51,0xd5,0xe1,0x9d,0x67,0x20,0x8d, - 0x04,0x20,0xc5,0x68,0x3d,0x17,0xd6,0x0f,0x9f,0x42,0x0b,0x97,0x86,0xc1,0xec,0x46,0x80,0xbe,0xba,0x9c,0x0e,0x04,0x7b,0xac,0x7c,0xfb,0xb4,0xaa,0xc3,0x50,0xae,0x58,0x47,0xb9,0x20,0x8d, - 0x04,0x20,0xc5,0x6a,0xe1,0xda,0x01,0xdc,0xb2,0xb3,0x2a,0xfc,0x21,0x85,0x88,0x7e,0x0c,0x3b,0xf0,0xe8,0x5c,0x78,0xb8,0xda,0xa9,0x5d,0x7e,0x7b,0xda,0xc0,0x19,0xb2,0xa7,0x1a,0x20,0x8d, - 0x04,0x20,0xc5,0xbf,0x38,0x02,0x89,0x69,0x96,0xf4,0xb1,0x20,0x57,0x63,0xf9,0x5e,0xa9,0x37,0x0d,0x02,0x50,0x36,0x24,0xd9,0xd3,0xf7,0x84,0xf9,0x42,0x56,0xff,0x17,0xfa,0x8d,0x20,0x8d, - 0x04,0x20,0xc5,0x82,0xf8,0xc9,0x0e,0x19,0xa6,0xb1,0x6a,0x0e,0xa0,0x6a,0xe9,0xf6,0x0c,0xd6,0x96,0xe3,0x52,0x71,0xd0,0xc2,0x8c,0xb1,0x6e,0x68,0xf8,0x31,0x20,0xaa,0x58,0x2f,0x20,0x8d, - 0x04,0x20,0xc5,0x95,0x75,0x83,0x03,0x73,0xd1,0xec,0x19,0x24,0x31,0xa7,0x5e,0xe5,0xaf,0x9a,0xa2,0xb1,0xe6,0x47,0xfb,0xc8,0x6f,0x58,0x01,0x52,0x58,0x2a,0x71,0x5b,0x3b,0x02,0x20,0x8d, - 0x04,0x20,0xc5,0x98,0x7e,0xe4,0x57,0xdc,0x75,0x11,0xff,0x2c,0x56,0x2f,0xd5,0x61,0x86,0xba,0xb9,0xb5,0xc8,0x0c,0x41,0x3b,0xa5,0x04,0xe0,0xc4,0x2d,0x0c,0x38,0x7d,0x9b,0x8d,0x20,0x8d, - 0x04,0x20,0xc5,0xa1,0xe7,0x5c,0x65,0x1d,0x56,0x81,0x4f,0x62,0xa0,0x24,0x3d,0x81,0x55,0x12,0xf9,0xf4,0x5b,0xc1,0xbe,0x15,0x1a,0xa8,0x0b,0x23,0x22,0x2c,0x43,0x38,0xc8,0x96,0x20,0x8d, - 0x04,0x20,0xc5,0xa0,0xa1,0xa9,0x07,0x7e,0x63,0xb3,0xdf,0xcb,0x06,0x97,0x98,0x48,0xd4,0x74,0x03,0x4b,0x29,0xbb,0xf4,0x05,0x10,0xa8,0xf5,0x5c,0xc7,0xed,0x64,0x71,0x35,0x1f,0x20,0x8d, - 0x04,0x20,0xc5,0xa0,0xfd,0xa9,0x36,0x11,0xd5,0x37,0x6b,0x92,0x77,0x1a,0xde,0x38,0xb0,0xeb,0x3a,0x2e,0x77,0x81,0x9b,0x55,0x4b,0xf5,0x37,0x2c,0xd4,0xa8,0x67,0xde,0x1d,0x05,0x20,0x8d, - 0x04,0x20,0xc5,0xa1,0x83,0x4b,0xfa,0x86,0x6e,0x15,0x24,0x8a,0x26,0x56,0x79,0x36,0x32,0x2b,0x5b,0x56,0x7b,0xc8,0x32,0x9d,0x52,0xb8,0xfa,0xf7,0xe3,0x4f,0x9d,0xdb,0x84,0xef,0x20,0x8d, - 0x04,0x20,0xc5,0xaa,0xfc,0x52,0x3c,0x6e,0x3d,0x93,0x96,0xef,0x95,0x41,0xc6,0x1f,0xc2,0x1f,0x0f,0x3b,0x72,0x1f,0xc2,0xef,0xf9,0xa2,0x52,0x6d,0xc8,0x7b,0x1b,0x41,0x40,0xfa,0x20,0x8d, - 0x04,0x20,0xc5,0xf6,0xd6,0xe2,0xf8,0xd9,0xf8,0x4b,0xeb,0x54,0x80,0xd3,0x62,0x3c,0xee,0x7c,0x66,0x4d,0xf1,0x24,0x5b,0x54,0xf8,0xf2,0x80,0xd8,0xf5,0xb5,0x4b,0xf0,0xba,0x63,0x20,0x8d, - 0x04,0x20,0xc5,0xc1,0xa4,0x53,0xbe,0x2b,0xf8,0x8e,0x32,0xf9,0x1a,0x99,0x5f,0xde,0xf1,0x5d,0x31,0x79,0xab,0x0b,0x85,0x49,0x7a,0x08,0x88,0xad,0xf8,0x58,0x5c,0x29,0xc6,0x58,0x20,0x8d, - 0x04,0x20,0xc5,0xcd,0x57,0xfb,0xcb,0x5e,0xc5,0xe5,0x3b,0xf6,0xe1,0xd9,0xfb,0xd7,0x2e,0x28,0xf6,0x20,0xed,0x54,0xda,0x53,0x01,0x72,0xc8,0x38,0x1e,0xdc,0x2b,0x76,0xba,0x12,0x20,0x8d, - 0x04,0x20,0xc5,0xd6,0x0b,0xa0,0x00,0x9e,0x0a,0xd8,0xdf,0x6b,0xd5,0x4e,0x1e,0x3f,0xc3,0xdf,0x3e,0x34,0xe6,0x97,0xff,0x4c,0x25,0xe8,0x7b,0xd8,0x30,0x35,0xda,0x4f,0x77,0x6d,0x20,0x8d, - 0x04,0x20,0xc5,0xd7,0x67,0xb2,0x49,0x18,0x5e,0xb1,0x9d,0x1d,0x3a,0xf2,0xe7,0xa2,0x48,0x73,0x76,0x88,0x05,0x39,0x7d,0x70,0x00,0x10,0x3c,0xc4,0xa7,0xbc,0xff,0x70,0x09,0xa1,0x20,0x8d, - 0x04,0x20,0xc5,0xdb,0x49,0x2d,0x3f,0x3c,0x97,0x66,0x38,0xa7,0xdf,0x81,0xbf,0xca,0x6b,0x67,0x52,0x96,0xc3,0x9e,0xad,0x6b,0x86,0xcc,0xbc,0xd5,0x2d,0xbc,0xd1,0xd4,0x74,0xf7,0x20,0x8d, - 0x04,0x20,0xc5,0xe1,0xb0,0xa6,0xc3,0x88,0x95,0xb5,0x95,0x75,0xb2,0x2e,0x9d,0x14,0x5a,0x5f,0xdf,0x98,0x34,0x80,0xea,0xfe,0x2a,0x0a,0xa8,0x03,0x1c,0x2f,0x6c,0x1a,0xbb,0xb2,0x20,0x8d, - 0x04,0x20,0xc5,0xe2,0x40,0xf4,0x09,0xa0,0xda,0xf9,0xec,0x3f,0xcf,0x4f,0x84,0x64,0x09,0xf5,0x0a,0x61,0xf3,0xce,0xde,0xf9,0x69,0x8e,0x94,0xc0,0x00,0xa0,0xba,0xf6,0xcc,0xcc,0x20,0x8d, - 0x04,0x20,0xc6,0x36,0x16,0xcb,0x2b,0x1e,0xa6,0x10,0xe0,0x7c,0xe9,0x74,0x9f,0x86,0x71,0x08,0xf3,0xa7,0xf7,0x32,0xa6,0x50,0x4d,0x7d,0x68,0x84,0x7f,0x73,0x28,0xa7,0xdf,0xe2,0x20,0x8d, - 0x04,0x20,0xc6,0x3f,0x1a,0x48,0xe4,0x3e,0x85,0x0d,0x5c,0xc7,0x7c,0x87,0x95,0xc6,0xfc,0x33,0xc8,0x93,0x16,0xb2,0x29,0xe1,0xed,0xef,0x63,0xd2,0x67,0x31,0x3a,0xa7,0x3f,0x52,0x20,0x8d, - 0x04,0x20,0xc6,0x0d,0x71,0x8a,0xb8,0x7f,0xa6,0xde,0x7a,0x8c,0x7b,0x2e,0xb9,0x1a,0x48,0xf0,0xa2,0x6d,0x5d,0x22,0x3d,0x0e,0x8d,0xb9,0x4e,0x0b,0x8b,0x2b,0xf0,0x70,0x35,0xa8,0x20,0x8d, - 0x04,0x20,0xc6,0x1d,0xd9,0x72,0x3e,0xb4,0x7c,0xff,0xaf,0xaf,0xed,0x18,0xb7,0xfe,0xe6,0x0f,0x3f,0x43,0x11,0xf3,0xa1,0xa4,0x2a,0xf0,0xd5,0x7c,0xaf,0x54,0xae,0xd8,0x61,0x5f,0x20,0x8d, - 0x04,0x20,0xc6,0x23,0xa7,0x92,0x19,0x6d,0x12,0x48,0xee,0x7e,0xde,0x30,0x75,0x88,0x12,0x4b,0x46,0x13,0xad,0x75,0x9d,0xee,0xa6,0x0a,0xb1,0xfb,0xf9,0x8b,0xbe,0x99,0x4c,0x45,0x20,0x8d, - 0x04,0x20,0xc6,0x2c,0xc1,0x68,0xe7,0x57,0xe7,0xdf,0x13,0xe9,0xa3,0x7d,0xa7,0x20,0x70,0x2c,0xfc,0x9a,0xce,0xb5,0x5e,0x16,0x4b,0xa0,0xf9,0x30,0xa3,0x35,0x66,0xe4,0xe8,0x2f,0x20,0x8d, - 0x04,0x20,0xc6,0x76,0x8c,0xdc,0xbe,0x78,0xe7,0x1d,0xd0,0x41,0x8a,0x28,0xee,0x05,0xe6,0x4b,0x75,0x54,0x48,0x03,0xe5,0x4c,0xe1,0x2a,0x64,0xbb,0x5f,0x5d,0xc4,0xa6,0x04,0x76,0x20,0x8d, - 0x04,0x20,0xc6,0x78,0xbf,0x82,0x02,0x49,0x76,0xb1,0x0e,0x63,0x15,0x2e,0xeb,0xad,0x24,0x1c,0x45,0x15,0xbb,0x6b,0xa7,0x95,0x33,0xcb,0x41,0xaa,0x48,0xe4,0x2f,0x96,0x85,0xf6,0x20,0x8d, - 0x04,0x20,0xc6,0x7a,0x8f,0x49,0x63,0xc5,0xa3,0xa6,0x43,0x27,0xec,0x19,0x67,0x40,0xa6,0x94,0xc1,0xd2,0xfb,0xe1,0x30,0xcf,0x07,0x18,0x89,0x4b,0x1e,0x46,0x99,0x7b,0x5a,0xc0,0x20,0x8d, - 0x04,0x20,0xc6,0x40,0xa3,0x3a,0x2d,0x89,0xf3,0x92,0x35,0xe2,0x5b,0xb8,0x03,0xe0,0x08,0xea,0xef,0x23,0x79,0x89,0x87,0x33,0x1b,0x2c,0xf0,0x9e,0xca,0x5e,0x48,0x2b,0xba,0x39,0x20,0x8d, - 0x04,0x20,0xc6,0x42,0xa0,0x6a,0x58,0x30,0x7a,0x48,0x1a,0x26,0x56,0xa5,0x58,0x21,0xbd,0x3a,0xf6,0x32,0xa9,0xb9,0x28,0xdb,0xeb,0x66,0xcd,0x11,0x2f,0x22,0x25,0x91,0x7f,0x6c,0x20,0x8d, - 0x04,0x20,0xc6,0x4f,0xa4,0x34,0x84,0x2a,0xb2,0xe3,0x89,0x5f,0xaa,0xac,0x22,0x93,0xda,0x55,0x5e,0xb9,0x2f,0x1d,0xbb,0x78,0x36,0x33,0x5d,0x2b,0xee,0x14,0xc3,0x55,0x06,0xf8,0x20,0x8d, - 0x04,0x20,0xc6,0x50,0x67,0x48,0xa4,0xbb,0xc4,0xef,0x7c,0x58,0xd9,0x37,0xab,0x90,0xeb,0x7d,0x9d,0x1d,0xfc,0xaf,0xee,0x99,0x8e,0xbe,0xd3,0x8e,0xaf,0x26,0xa7,0x6c,0xba,0xfe,0x20,0x8d, - 0x04,0x20,0xc6,0x50,0x90,0xfd,0xf4,0xf3,0x23,0x11,0xd8,0x3f,0x92,0xa9,0xa2,0x6c,0x8f,0x2e,0x22,0xa3,0xaf,0xf3,0xd0,0x3f,0xad,0xd4,0x08,0x94,0x28,0xb8,0xee,0x2e,0x05,0xdd,0x20,0x8d, - 0x04,0x20,0xc6,0x56,0x04,0x6f,0xb1,0x00,0xc6,0x3d,0x28,0x69,0x6d,0x14,0xd9,0x7e,0x9d,0x9f,0x19,0xc6,0x99,0x1d,0x19,0x62,0xb8,0x7f,0x44,0xf2,0xe0,0x5d,0x1d,0xfd,0x1e,0x55,0x20,0x8d, 0x04,0x20,0xc6,0x5d,0xaa,0xe7,0x8a,0xa2,0x26,0xce,0xef,0x36,0xc3,0x54,0xcf,0x8c,0x65,0x1d,0xba,0x49,0x0a,0x4f,0xe9,0x5f,0xf8,0x98,0xbe,0xa4,0x9e,0xf3,0x93,0xdd,0xdb,0x2a,0x20,0x8d, - 0x04,0x20,0xc6,0x60,0x5c,0xdb,0xe5,0x36,0x73,0x2f,0x6e,0xef,0xac,0x8d,0x96,0x9d,0xa0,0x94,0xae,0x20,0x0c,0x25,0x05,0xee,0x0b,0x85,0x8a,0x29,0x6a,0x49,0x18,0x77,0x46,0x4f,0x20,0x8d, - 0x04,0x20,0xc6,0x63,0x6f,0xd1,0x45,0xa2,0xff,0x13,0xd5,0x6b,0x24,0xd8,0x00,0xb3,0x7f,0xb5,0x1e,0xa3,0xca,0xf6,0x76,0x89,0x28,0x41,0xd3,0x93,0x8f,0xe3,0x5d,0x01,0xef,0xe5,0x20,0x8d, - 0x04,0x20,0xc6,0x65,0xa0,0x8c,0xf6,0x3d,0xca,0x60,0x3b,0x2f,0x12,0x05,0xca,0xfb,0xd6,0xfd,0xac,0xbb,0xc6,0x3b,0xaf,0x2e,0xf3,0x64,0x91,0xfe,0xf7,0x02,0x1c,0x56,0x25,0x90,0x20,0x8d, - 0x04,0x20,0xce,0xb6,0xf2,0xa3,0x37,0xb3,0xc0,0x4d,0x48,0x29,0x27,0xf5,0xa4,0x12,0x55,0x1f,0xa2,0x2b,0xb6,0x60,0xc8,0x80,0xe2,0x14,0x01,0xcc,0xa8,0x35,0x0b,0x97,0xbb,0x26,0x20,0x8d, 0x04,0x20,0xce,0x88,0xac,0x71,0xfc,0x76,0x56,0xa8,0xc5,0x94,0x86,0x93,0x01,0x67,0xd6,0xd2,0xb5,0xa8,0x93,0xc7,0xbc,0x59,0xba,0x33,0x98,0x78,0x9a,0xcc,0xb1,0xf2,0x47,0x1f,0x20,0x8d, - 0x04,0x20,0xce,0x88,0xee,0x50,0x4a,0x1e,0xf0,0xc3,0x4e,0x49,0x44,0xc0,0x6f,0xe2,0x14,0x53,0x13,0x24,0xbe,0xd4,0x2e,0xc7,0xb6,0xbe,0x1c,0x74,0x94,0x40,0x4d,0xea,0x12,0x1b,0x20,0x8d, - 0x04,0x20,0xce,0x8c,0xdc,0x9c,0x1f,0x9c,0xd0,0x96,0x2c,0x9f,0xe8,0xeb,0x01,0xe4,0x04,0x86,0x77,0x7c,0x5f,0x29,0x8c,0x60,0x1c,0xc5,0x01,0xad,0x82,0xe6,0x1f,0xfc,0x49,0x39,0x20,0x8d, - 0x04,0x20,0xce,0x90,0x7b,0xb4,0x9f,0x5e,0x1c,0x3b,0x19,0x6a,0xb3,0xea,0x36,0x67,0x60,0xf6,0xf9,0xb6,0x49,0x11,0x8d,0x52,0xc0,0x17,0x4f,0xc4,0xe8,0xed,0xa7,0x12,0x00,0x62,0x20,0x8d, - 0x04,0x20,0xce,0x96,0x75,0xc8,0xf7,0x02,0xba,0xeb,0x55,0x10,0x86,0x40,0x24,0xff,0x68,0x71,0x67,0x06,0x56,0x1d,0x40,0xc1,0x66,0x44,0xd3,0xe2,0xb7,0xcf,0x86,0xd1,0xf6,0x28,0x20,0x8d, - 0x04,0x20,0xce,0x9a,0x94,0x2c,0xe9,0x5e,0xf7,0x87,0x50,0x93,0xec,0x42,0x32,0xb1,0xa2,0x00,0xdf,0x3f,0xcd,0xc7,0x98,0x9c,0xd5,0xcb,0x70,0x3b,0xeb,0x48,0x15,0x51,0x23,0xa6,0x20,0x8d, - 0x04,0x20,0xce,0x9a,0xe1,0x0f,0x87,0x04,0x27,0xae,0xfc,0x58,0x8f,0x8a,0x49,0x4d,0x03,0xf9,0x1a,0xe2,0x7f,0x50,0x7b,0x29,0xaf,0x8a,0x95,0xa9,0x1c,0xe6,0xf2,0x22,0x02,0xb8,0x20,0x8d, - 0x04,0x20,0xce,0xb0,0x9a,0xdc,0x35,0xdc,0x4a,0xf9,0x3b,0x82,0x4a,0xae,0x2e,0x23,0xfa,0x2f,0x7b,0x70,0xf4,0xa8,0x3c,0xce,0x21,0x86,0xa7,0xf0,0xdf,0xf3,0x1e,0xf9,0xd4,0x35,0x20,0x8d, - 0x04,0x20,0xce,0xf6,0x68,0xf8,0xad,0x46,0xf4,0xd5,0x1c,0xac,0x53,0xaa,0x20,0xd5,0xf4,0x57,0xe5,0xa0,0x4d,0xd0,0x28,0x69,0x91,0x9b,0x3a,0x4c,0xb2,0x7e,0xd0,0x1f,0xc8,0xe9,0x20,0x8d, - 0x04,0x20,0xce,0xfd,0xcd,0x7e,0x20,0x6c,0xd1,0x8e,0x21,0x4b,0x26,0x10,0x7b,0x16,0xc7,0xd1,0x81,0xb7,0xe2,0x10,0xcf,0xc6,0xe2,0x66,0x39,0x56,0x2b,0xdd,0x05,0x1b,0x63,0xc4,0x20,0x8d, - 0x04,0x20,0xce,0xc1,0x23,0x66,0x99,0x1d,0x4f,0x18,0x91,0x30,0x4b,0x54,0x6e,0xc0,0xa4,0xc3,0x64,0xfa,0x5b,0x39,0x8a,0xf7,0x28,0xfe,0x44,0x85,0xd7,0x65,0x20,0x8c,0x6c,0x5f,0x20,0x8d, - 0x04,0x20,0xce,0xce,0x39,0xbe,0xac,0x68,0x33,0xa4,0x66,0xad,0x5b,0x9f,0x96,0x14,0xc3,0x0e,0xa5,0x86,0xc9,0xcc,0xc9,0xb1,0xed,0x1f,0xf5,0x5d,0xeb,0x26,0xef,0x10,0x39,0xa8,0x20,0x8d, - 0x04,0x20,0xce,0xce,0x61,0x9d,0x3f,0xcd,0xe6,0x83,0xe8,0xca,0x4a,0xda,0x4b,0xf9,0xc2,0x14,0xf3,0x6d,0xcd,0xe3,0xf1,0x7a,0x47,0x06,0xd1,0x6c,0xe2,0x7b,0xcd,0x16,0xb7,0x94,0x20,0x8d, - 0x04,0x20,0xce,0xd2,0xbd,0x23,0x25,0xbd,0x8a,0xc8,0x34,0x21,0x88,0x05,0xb9,0xd2,0x53,0x6f,0x02,0xd3,0x61,0x89,0xd4,0xd0,0x0d,0x49,0xbf,0x6d,0x30,0x27,0x34,0x2c,0x4c,0x94,0x20,0x8d, - 0x04,0x20,0xce,0xd9,0xb0,0x7a,0xc8,0x47,0xb4,0x91,0x6f,0xe2,0xd1,0x6d,0xf3,0xd0,0x40,0xfb,0x29,0xc2,0x62,0xcd,0x94,0x90,0xd1,0xd4,0xed,0xd9,0xe2,0x7d,0xcf,0x98,0xe2,0xac,0x20,0x8d, - 0x04,0x20,0xce,0xdc,0x3d,0x6c,0xae,0x09,0xd5,0x5c,0x3e,0xe0,0x8b,0x49,0x0d,0x96,0x12,0x1c,0x95,0x24,0xcf,0x67,0x65,0x12,0xd5,0x81,0x16,0x0f,0xba,0x71,0xd8,0x1a,0x6f,0x6e,0x20,0x8d, - 0x04,0x20,0xcf,0x34,0xd7,0xf7,0x29,0x1e,0xe6,0x76,0x8f,0xbc,0x3f,0x5b,0xce,0xa0,0x38,0x6e,0x7b,0x50,0xec,0xab,0x09,0xb0,0xf9,0xf1,0x84,0xd0,0xb6,0x16,0xd5,0xb3,0x6f,0x23,0x20,0x8d, - 0x04,0x20,0xcf,0x07,0xf2,0xf0,0x75,0x85,0x27,0x9a,0xd6,0x0a,0x62,0x77,0xdc,0xb7,0x2f,0xc3,0xa3,0x17,0x40,0xdd,0xda,0x4e,0x12,0xcf,0x7c,0x36,0x15,0xa3,0xef,0x96,0xcb,0xa3,0x20,0x8d, 0x04,0x20,0xcf,0x0d,0x58,0x61,0x8c,0x4f,0x52,0xc3,0x6c,0x6d,0x03,0xbe,0xad,0xd4,0x5a,0xe7,0x5f,0x92,0x3e,0x02,0x89,0x2b,0x9c,0x1f,0x92,0xed,0xdb,0xd2,0x88,0x5e,0x03,0xc9,0x20,0x8d, - 0x04,0x20,0xcf,0x18,0xc7,0x85,0x3f,0x60,0xf4,0xb4,0xa7,0x4d,0xc8,0x55,0xd0,0xfa,0x53,0x1c,0x5c,0xc7,0xea,0x57,0x3e,0x24,0x32,0x5d,0x10,0xf2,0x93,0x07,0xe8,0xce,0xd6,0x0a,0x20,0x8d, - 0x04,0x20,0xcf,0x1f,0x8a,0x8e,0x8f,0x12,0x09,0x48,0x4f,0x35,0x39,0xf9,0xf9,0x05,0x00,0x38,0xf0,0x43,0x55,0xe6,0x9d,0x8c,0x56,0x2e,0xa5,0x94,0x59,0xcc,0x27,0xc6,0xeb,0x27,0x20,0x8d, - 0x04,0x20,0xcf,0x20,0x6a,0x81,0x26,0x56,0xe7,0x1f,0x01,0xcc,0x47,0xf2,0xa7,0xa1,0x0b,0xbf,0x6e,0x1f,0x4e,0xa0,0xad,0x1f,0x5b,0x73,0x52,0x32,0x4b,0xb0,0x96,0x11,0x35,0x95,0x20,0x8d, - 0x04,0x20,0xcf,0x22,0x68,0xca,0x83,0xce,0xec,0x9b,0xfe,0x98,0x51,0xb4,0xa6,0x08,0x03,0xb2,0x2e,0xa5,0xa0,0x31,0xe8,0x78,0xae,0xb6,0x8b,0xb4,0x5f,0x71,0x25,0x40,0x95,0x3c,0x20,0x8d, - 0x04,0x20,0xcf,0x25,0xe3,0x74,0x30,0x1b,0x1d,0xce,0x76,0xb4,0xd2,0x3d,0x31,0x33,0xbc,0xca,0x70,0xf2,0x9d,0x7d,0xa5,0x9b,0x78,0x26,0x1f,0xf7,0x02,0x1a,0x74,0xfb,0xf9,0x94,0x20,0x8d, - 0x04,0x20,0xcf,0x33,0x1d,0xd7,0x5b,0xd4,0x41,0x84,0xe3,0xe4,0xe5,0xa9,0x7b,0x93,0x3a,0x0a,0xf3,0xe7,0xf8,0x0f,0xc5,0x79,0x27,0x52,0xe9,0xcc,0xe0,0xda,0xed,0x95,0x06,0x26,0x20,0x8d, - 0x04,0x20,0xcf,0x74,0x1b,0xfb,0xdd,0xfb,0x2a,0x0d,0xe1,0x33,0x8d,0x26,0x93,0xdd,0xc9,0x50,0x6c,0xc8,0xb1,0xa3,0x56,0xe3,0xb6,0xbe,0x77,0x17,0x6f,0x0c,0xed,0xa3,0xf6,0x8b,0x20,0x8d, - 0x04,0x20,0xcf,0x48,0x26,0x9f,0xe2,0x8b,0xcc,0xee,0xf1,0xa5,0x5a,0xfd,0x00,0xd9,0x7c,0xc0,0x6a,0x50,0xc3,0x68,0xc8,0x33,0x21,0xd3,0x6f,0x7f,0xb3,0x05,0x01,0x9c,0xfb,0x69,0x20,0x8d, - 0x04,0x20,0xcf,0x6b,0xed,0xa3,0xeb,0xa9,0xd4,0x51,0xc0,0x44,0xbe,0xd0,0xe2,0x37,0x1e,0xd1,0x97,0x73,0xbe,0x6e,0xb4,0xe2,0x57,0x17,0xbc,0x80,0x57,0xde,0x75,0x8b,0x11,0xd5,0x20,0x8d, - 0x04,0x20,0xcf,0xb4,0xa1,0x8c,0xb4,0x9f,0xf8,0xee,0xb5,0x38,0x21,0xd4,0x35,0xa7,0x82,0x00,0x3d,0x83,0x75,0xd1,0xcf,0x57,0x96,0x80,0x42,0x78,0x56,0xe8,0x43,0x52,0x42,0x2c,0x20,0x8d, - 0x04,0x20,0xcf,0xb5,0x1e,0xea,0x04,0x33,0x0d,0x5e,0x3a,0x78,0x33,0x82,0x91,0xca,0x81,0x17,0x92,0x52,0x80,0x88,0xd6,0xce,0x4f,0x37,0xbd,0xd8,0x14,0x2e,0x59,0xa5,0xec,0x71,0x20,0x8d, - 0x04,0x20,0xcf,0xb6,0x3f,0xfc,0xc3,0xf8,0x23,0x32,0x28,0xa4,0x03,0x15,0x0c,0x09,0xa8,0xfc,0xf3,0x15,0x54,0x22,0xef,0x0b,0x08,0xff,0x7b,0xa9,0x28,0xe0,0x42,0xfc,0xea,0x6c,0x20,0x8d, - 0x04,0x20,0xcf,0xb6,0x57,0xa2,0x79,0x1d,0xb6,0xe9,0xfb,0x56,0x9d,0xe6,0x86,0x8c,0xfd,0xde,0xf9,0x40,0x4f,0x3a,0x2a,0xee,0x6f,0x45,0xcd,0xc6,0x3c,0x9b,0x5f,0x59,0x9a,0x65,0x20,0x8d, - 0x04,0x20,0xcf,0xb9,0xa1,0xf3,0xa0,0x05,0x08,0x78,0xeb,0x02,0x65,0x78,0x4b,0x57,0xd9,0x55,0x92,0xba,0xac,0xf6,0x2f,0x6c,0xba,0x12,0x98,0xee,0x1a,0xfa,0x72,0x0c,0x29,0x45,0x20,0x8d, - 0x04,0x20,0xcf,0xba,0xb0,0xde,0x95,0x77,0x6f,0xbf,0x56,0x95,0xec,0x4d,0x63,0x61,0xcf,0x5c,0x13,0x9c,0x89,0x16,0xa8,0x75,0x63,0xd5,0xdb,0x9a,0xcc,0x7c,0x9d,0xfe,0xca,0x13,0x20,0x8d, - 0x04,0x20,0xcf,0x8d,0x1e,0x8b,0xb8,0x8b,0xfb,0x22,0x42,0x56,0xfe,0xc3,0xa7,0xa9,0xbb,0x47,0x01,0x01,0xf5,0x03,0x66,0x4c,0x81,0xa4,0x47,0x4a,0x59,0xf2,0xe8,0xe3,0x31,0x54,0x20,0x8d, - 0x04,0x20,0xcf,0x9b,0xb3,0xff,0xb4,0xea,0x94,0x3e,0xdd,0x50,0x2d,0x83,0x00,0x48,0x7a,0x89,0x15,0x70,0x32,0x5b,0x4a,0x1b,0x18,0xc0,0x09,0xfb,0xf7,0xb8,0x0e,0xf0,0xf9,0x46,0x20,0x8d, - 0x04,0x20,0xcf,0x9b,0xd5,0x2b,0x00,0x0a,0xf4,0x7a,0x42,0x62,0x7e,0xf7,0xa6,0xfa,0xe1,0x77,0xd4,0xf4,0x2c,0x56,0xe0,0x7d,0xc3,0x3a,0xb9,0x9d,0xb7,0x2b,0x4f,0x34,0x59,0xa7,0x20,0x8d, - 0x04,0x20,0xcf,0x9b,0x0f,0x2d,0x4c,0x4b,0xb0,0x93,0xc1,0xfd,0x4e,0xe6,0x6d,0x18,0x49,0x87,0x09,0xb3,0x98,0x74,0x77,0xf9,0x46,0xb2,0x6c,0x6e,0x02,0x3f,0x83,0xff,0xf9,0xdf,0x20,0x8d, - 0x04,0x20,0xcf,0x9b,0x4a,0xdd,0xa9,0x40,0x89,0x5d,0xd7,0x9f,0x77,0x2b,0x74,0xd8,0x0a,0x2e,0x7c,0x6d,0xa6,0xb8,0x76,0xd7,0xc8,0x8e,0x5d,0x84,0x0a,0x97,0xce,0x08,0x27,0x62,0x20,0x8d, - 0x04,0x20,0xcf,0x9c,0xa4,0xdd,0x82,0x5d,0x85,0xde,0xbc,0x36,0x43,0xa1,0x7e,0xdb,0x14,0x07,0xe2,0x97,0x04,0x4c,0x0c,0xe6,0xf9,0x93,0xba,0xec,0xd7,0x3d,0x18,0x97,0x48,0x93,0x20,0x8d, - 0x04,0x20,0xcf,0xa0,0xc2,0xef,0x4c,0x58,0xff,0x48,0x25,0x97,0xf1,0xe2,0xe8,0x35,0x48,0x21,0x23,0x29,0xbf,0x75,0x59,0x37,0x4d,0x8d,0xde,0x70,0xee,0x83,0x6e,0x81,0x65,0x7b,0x20,0x8d, - 0x04,0x20,0xcf,0xa5,0xe9,0xf8,0x28,0xe2,0xd6,0xfa,0x38,0x7e,0x8b,0x40,0xa1,0x6f,0x9c,0xb3,0x76,0x7f,0x11,0x2f,0x29,0x13,0x78,0xa9,0x2e,0x3a,0x53,0x8d,0x73,0xd2,0x3d,0x8a,0x20,0x8d, + 0x04,0x20,0xcf,0x87,0xf5,0xaf,0x3f,0x60,0x20,0x66,0xb9,0xc0,0x0f,0x03,0xe9,0x38,0xc5,0xf9,0x25,0x90,0x19,0x7f,0x3a,0x0d,0x1a,0xaa,0x5a,0x26,0x15,0x67,0x19,0x05,0xb1,0xf6,0x20,0x8d, 0x04,0x20,0xcf,0xa4,0xe0,0x76,0x4f,0x53,0x51,0xdc,0x93,0xcf,0xd5,0xcd,0xe5,0xb4,0x87,0xa6,0xc7,0xf3,0xb6,0x0d,0xe8,0xc6,0x8c,0x6f,0x89,0x99,0x07,0x62,0x18,0xbc,0x96,0x20,0x20,0x8d, - 0x04,0x20,0xcf,0xa7,0xe2,0xde,0xc7,0x33,0x47,0x54,0x6f,0xd5,0x88,0x3c,0x3e,0x8e,0x80,0x8e,0x2f,0xa6,0x7f,0xb5,0xf0,0x3b,0x87,0x67,0x62,0x82,0x56,0x9e,0xed,0x4e,0xe5,0x99,0x20,0x8d, - 0x04,0x20,0xcf,0xa6,0xc0,0x16,0xb0,0xb1,0x75,0x21,0xf2,0x22,0x3b,0x40,0x53,0x72,0x91,0x15,0x0d,0xcb,0xbd,0x58,0x5d,0x97,0x2d,0x3a,0xd1,0xa6,0x10,0x50,0x0e,0x80,0x23,0x49,0x20,0x8d, - 0x04,0x20,0xcf,0xa9,0xc9,0x6e,0x99,0xf0,0x6e,0xa2,0x6e,0x78,0x40,0x70,0x21,0x04,0xdf,0xa0,0x2f,0x3e,0x08,0x3c,0x1d,0x08,0x3d,0x8a,0x9b,0x78,0x53,0x6f,0x16,0x30,0x17,0x5a,0x20,0x8d, - 0x04,0x20,0xcf,0xf5,0x11,0xec,0x11,0x50,0x23,0x1f,0x10,0x87,0xa0,0x8d,0xf8,0xc5,0x49,0x65,0x60,0xdc,0x8c,0x29,0x63,0xde,0x55,0x7f,0x22,0xae,0x47,0xf4,0xc2,0x35,0x44,0x8b,0x20,0x8d, - 0x04,0x20,0xcf,0xf9,0xdb,0x28,0x4b,0x5f,0xea,0xa5,0x46,0xff,0xc8,0x18,0x80,0xd4,0x38,0x82,0x66,0x27,0xef,0x1f,0xb0,0xf3,0xd5,0x0f,0x7b,0x32,0x13,0x72,0xe7,0xbc,0x15,0xf2,0x20,0x8d, - 0x04,0x20,0xcf,0xc8,0x1d,0x5d,0x48,0x41,0x92,0x32,0x83,0x1c,0x11,0xf8,0xfa,0x04,0x90,0xb8,0x74,0x9b,0x63,0x23,0x0f,0x4a,0xee,0xba,0xca,0x0c,0xc9,0x83,0x90,0xa4,0x57,0xfd,0x20,0x8d, 0x04,0x20,0xcf,0xcb,0xf5,0xc6,0xb4,0x7f,0xb7,0xab,0x28,0x39,0x43,0x6a,0x15,0x63,0x11,0x3b,0x0d,0x40,0x17,0x85,0xcc,0xfd,0x95,0x91,0x18,0x6a,0xb5,0x5a,0x56,0xc3,0xb4,0xfd,0x20,0x8d, - 0x04,0x20,0xcf,0xcd,0xb9,0xdf,0x6d,0xa0,0x98,0x3e,0xbb,0x35,0x97,0xec,0x68,0x71,0x1a,0x8a,0x11,0x42,0xdd,0x74,0x9d,0x75,0x49,0x3a,0xd1,0xdb,0xf8,0xb4,0x5c,0xa1,0xbf,0x78,0x20,0x8d, - 0x04,0x20,0xcf,0xcd,0xc4,0x11,0x4d,0xda,0x3e,0xd5,0xa1,0x0e,0xb2,0xe7,0xb2,0x2b,0xee,0xf5,0xd6,0x74,0x76,0x75,0xd1,0xdc,0x5c,0x08,0x02,0x4c,0x14,0xf2,0x39,0x09,0x31,0xd8,0x20,0x8d, - 0x04,0x20,0xcf,0xd3,0xa5,0x88,0xa9,0xe8,0x76,0x89,0x43,0x2d,0x90,0x79,0xc4,0x55,0x1e,0xf2,0xec,0xc4,0x0c,0x45,0x93,0xd9,0x51,0xc5,0x87,0x09,0x69,0x8a,0x07,0x47,0xdd,0x82,0x20,0x8d, - 0x04,0x20,0xcf,0xd2,0x10,0xd9,0x58,0xc8,0x3c,0x4d,0xfd,0x10,0x74,0xbd,0x4f,0xad,0xbb,0x69,0x06,0xe6,0x75,0x1b,0x18,0x9a,0xeb,0x0e,0x42,0x8f,0xec,0x54,0xea,0xf8,0x34,0x49,0x20,0x8d, 0x04,0x20,0xcf,0xd3,0x37,0x80,0xc7,0x67,0x1a,0x0e,0xbd,0xdd,0x7e,0xbe,0x5b,0x04,0x67,0xd0,0x21,0xbc,0xf2,0x2a,0x7d,0x8e,0x7c,0x91,0x8b,0x89,0xe4,0xe2,0x16,0x34,0xd6,0x7a,0x20,0x8d, - 0x04,0x20,0xcf,0xd9,0xf8,0xb3,0x27,0x72,0xfd,0x2b,0x41,0xaa,0xf2,0xf9,0x20,0x0e,0x29,0x35,0xec,0xd3,0x1a,0x7d,0xcd,0x8c,0xfd,0x26,0xfe,0x98,0x06,0x20,0x7f,0x8e,0xeb,0xe9,0x20,0x8d, - 0x04,0x20,0xcf,0xd8,0x2a,0x20,0xfd,0xad,0xbb,0x07,0x07,0xce,0xec,0x0d,0xaf,0xa4,0xee,0xcd,0x05,0x97,0xc2,0xfd,0x5b,0x32,0xbd,0x18,0xe5,0xbc,0x41,0xdd,0xcd,0xd5,0xd1,0xfb,0x20,0x8d, - 0x04,0x20,0xcf,0xe3,0x76,0x45,0x95,0x9c,0x82,0x68,0xc6,0xd6,0x3f,0x15,0xbf,0x85,0xea,0x57,0x87,0x3a,0x6c,0x10,0xf9,0x7a,0x3e,0x73,0x58,0x97,0xfa,0xd2,0x3f,0x1e,0x8e,0xa1,0x20,0x8d, - 0x04,0x20,0xcf,0xe9,0xbd,0x79,0x0e,0xb1,0x56,0xda,0xfa,0x75,0xc7,0xa8,0x8b,0x59,0x54,0x95,0xf9,0x50,0x4f,0xa6,0x18,0x2f,0x60,0x30,0x4f,0xf2,0x47,0xab,0x13,0x7d,0x41,0xfd,0x20,0x8d, - 0x04,0x20,0xc8,0x3c,0xad,0x53,0x53,0xd6,0x9c,0x71,0xc5,0xf0,0x0a,0x22,0x93,0xaf,0xfd,0x20,0x07,0x71,0x26,0xad,0x81,0x54,0xbe,0x07,0x24,0xc1,0x82,0xd5,0xa2,0x12,0x17,0x3a,0x20,0x8d, - 0x04,0x20,0xc8,0x03,0x7f,0xc8,0xe8,0xc8,0xca,0x23,0xc4,0xb3,0x3c,0x92,0x2a,0x63,0x0f,0x86,0x39,0xfd,0xb5,0x1a,0xd9,0x02,0x8e,0x00,0x83,0x75,0xb8,0x13,0x74,0x5c,0x9a,0xf8,0x20,0x8d, - 0x04,0x20,0xc8,0x05,0xe8,0x1c,0x30,0x08,0x7b,0x87,0x72,0x35,0x14,0x98,0x14,0x2d,0xfb,0xdb,0x86,0xac,0x96,0xd1,0x2c,0xec,0xc0,0x73,0x0e,0xe9,0xdd,0x1e,0x06,0x29,0xe0,0xf6,0x20,0x8d, - 0x04,0x20,0xc8,0x07,0xd1,0xab,0x0a,0x53,0x88,0xba,0x76,0x63,0x4f,0xd7,0xf6,0x47,0x5c,0x78,0xcb,0xe2,0x3a,0x5c,0x77,0xc4,0x19,0x75,0xb5,0xbf,0x82,0x23,0x77,0x9c,0xd9,0x21,0x20,0x8d, - 0x04,0x20,0xc8,0x0a,0x30,0x15,0x83,0xd1,0xfd,0x42,0x69,0xec,0xa2,0x75,0xd1,0x1c,0xec,0x54,0x00,0x3d,0xa4,0x62,0xbd,0xa6,0x02,0x4a,0x5a,0x73,0xee,0xa8,0xc5,0xce,0x7d,0x87,0x20,0x8d, - 0x04,0x20,0xc8,0x0c,0xa3,0x80,0xc3,0xcd,0x54,0x67,0xd1,0xdd,0xcb,0x4a,0xba,0xdc,0x50,0xb8,0x17,0xd9,0xd8,0x86,0xdd,0x64,0x07,0x01,0xcd,0x95,0x64,0xbf,0xc7,0xee,0x89,0xd7,0x20,0x8d, - 0x04,0x20,0xc8,0x0f,0x1a,0xa1,0xb4,0x15,0x2e,0xfb,0xd3,0xbe,0x3f,0x9a,0xa4,0x22,0xdf,0x15,0x69,0x3b,0xc6,0x80,0xf7,0x57,0xc4,0xe1,0xb5,0xb2,0xb3,0x3d,0x07,0x2c,0x25,0x2a,0x20,0x8d, - 0x04,0x20,0xc8,0x17,0x13,0xda,0x89,0xea,0x79,0xf9,0xb6,0x65,0x2a,0xff,0xfb,0xc4,0x64,0x3e,0x4b,0x68,0x7c,0x5f,0x1d,0x0e,0x08,0x71,0x36,0x6c,0x3b,0x51,0xcc,0x73,0x02,0x6c,0x20,0x8d, - 0x04,0x20,0xc8,0x2d,0xf3,0x35,0x78,0x24,0x22,0xb7,0x98,0x4c,0x93,0xf6,0x4f,0x6c,0x0d,0xa9,0x28,0x39,0x08,0xe7,0x41,0x40,0x02,0x66,0x9b,0xb1,0x03,0xbc,0xf9,0xe9,0x48,0xe7,0x20,0x8d, - 0x04,0x20,0xc8,0x30,0x5a,0x61,0x9e,0x4e,0xfa,0xcb,0xbe,0x23,0x93,0x35,0x7f,0xbe,0xb6,0x96,0xab,0x80,0x39,0x0d,0x93,0x98,0x30,0x9a,0x30,0x09,0x35,0xa8,0x88,0x5f,0xfa,0x7e,0x20,0x8d, - 0x04,0x20,0xc8,0x75,0xaf,0x49,0x5b,0x22,0xd3,0x71,0x08,0x12,0xb1,0x4c,0xea,0x53,0xcc,0x44,0xe9,0xcd,0xc8,0xba,0x18,0x1b,0xc2,0x93,0x06,0x8c,0x1a,0xba,0xc5,0xd3,0xf6,0x7d,0x20,0x8d, - 0x04,0x20,0xc8,0x75,0x04,0x5f,0x2c,0x91,0x26,0x77,0x58,0x7e,0x2c,0x1b,0x64,0x2a,0xaf,0xde,0x08,0x42,0x3b,0x79,0xa9,0xcc,0x96,0x43,0x58,0x0e,0xbf,0x32,0xc9,0x72,0x11,0x94,0x20,0x8d, - 0x04,0x20,0xc8,0x7d,0xaa,0x71,0xdd,0x86,0x65,0x3f,0xc7,0x29,0x04,0x3d,0x30,0x14,0xd9,0x76,0x02,0x8d,0x34,0x4e,0x30,0x92,0xfd,0xc8,0xbf,0xc8,0x66,0xef,0x87,0x57,0x62,0x05,0x20,0x8d, - 0x04,0x20,0xc8,0x44,0x8d,0x0b,0x4f,0x52,0xa9,0xf3,0xd8,0xde,0xe1,0x15,0xcc,0xf0,0x41,0xc3,0x7c,0xee,0x85,0xb9,0x7e,0x71,0x14,0x42,0xc9,0x12,0xb2,0x69,0x6f,0x97,0x65,0x3d,0x20,0x8d, - 0x04,0x20,0xc8,0x58,0x74,0x3a,0x30,0x5a,0xc6,0x45,0x99,0xa8,0xc1,0xec,0xe3,0x4a,0xcf,0xac,0x56,0x21,0xa6,0x17,0xb8,0x8a,0xcf,0x56,0x8b,0x23,0x62,0xfb,0x20,0x03,0xad,0x77,0x20,0x8d, - 0x04,0x20,0xc8,0x5a,0xea,0xd3,0xde,0x42,0x84,0x40,0x38,0x79,0x8a,0x9f,0x6b,0x5b,0x95,0x73,0xfc,0x8b,0x56,0x64,0x08,0x49,0x96,0xb4,0xce,0xd3,0x26,0x95,0x21,0x56,0x53,0x61,0x20,0x8d, - 0x04,0x20,0xc8,0x6c,0x18,0x5f,0x13,0x41,0xd5,0x5a,0x3c,0x5d,0xc9,0xc9,0x97,0x1f,0xee,0x40,0x4a,0x1f,0x85,0xcf,0x28,0xad,0xec,0x72,0x01,0x39,0xf4,0xaa,0x19,0xb2,0xb7,0xb3,0x20,0x8d, - 0x04,0x20,0xc8,0x6c,0xf3,0x53,0x99,0xd2,0xcb,0x49,0xbb,0xbe,0xf5,0x7c,0x3a,0x67,0x50,0xb7,0x54,0xac,0x55,0xd1,0xdf,0xe2,0xf4,0x1d,0x5a,0xe7,0x02,0x54,0xe6,0x08,0xa3,0x8e,0x20,0x8d, - 0x04,0x20,0xc8,0xb4,0x2e,0xf9,0x5f,0x38,0x87,0x4b,0xf6,0xd1,0x5b,0xd1,0x78,0xdf,0xcb,0x2d,0x27,0x85,0x94,0x0c,0x8f,0xbf,0xe9,0xd3,0x4d,0x8f,0x73,0xaa,0x97,0xa6,0xb3,0xb1,0x20,0x8d, - 0x04,0x20,0xc8,0xb8,0xbe,0x75,0x37,0xdc,0xee,0xb0,0x1b,0xe7,0x1d,0x1d,0x5e,0x4a,0x9d,0x52,0xfd,0xbd,0xcb,0x0a,0x05,0xbe,0x6a,0x21,0xc4,0x49,0xba,0xf8,0x6a,0x18,0xa1,0x24,0x20,0x8d, - 0x04,0x20,0xc8,0x85,0xcb,0x48,0x04,0x6b,0x46,0xac,0xc0,0x6f,0xe5,0xe4,0x5c,0xb7,0xc8,0x5c,0x86,0x7b,0x65,0xf0,0x44,0xad,0x46,0x0c,0x5a,0xd0,0xeb,0xd2,0x24,0x89,0x20,0xb6,0x20,0x8d, + 0x04,0x20,0xc8,0x53,0xb1,0x05,0x7e,0x9f,0xdc,0x9d,0x17,0xcd,0x24,0x17,0xf0,0x9d,0xf0,0x5b,0x10,0xc7,0xf9,0x05,0xeb,0xc3,0x96,0x0b,0x29,0x47,0xd7,0xba,0x67,0x07,0x7a,0x44,0x20,0x8d, 0x04,0x20,0xc8,0x87,0x5f,0xe7,0x75,0x24,0xe2,0xf2,0x3b,0xf2,0x75,0x30,0x82,0x7e,0x9b,0xae,0x31,0xeb,0x73,0x62,0xa0,0x29,0x30,0x38,0xcb,0x19,0xe5,0xc6,0xe8,0xa8,0x9e,0x27,0x20,0x8d, - 0x04,0x20,0xc8,0x89,0x94,0x14,0x1f,0x63,0x0d,0x5e,0x55,0xd4,0x5f,0x12,0x5e,0x58,0x30,0x64,0x75,0xc1,0xa4,0xd1,0x92,0xad,0x2c,0xaa,0x6a,0x9f,0x4e,0x83,0xe2,0xc1,0x5a,0xe6,0x20,0x8d, - 0x04,0x20,0xc8,0x90,0x5d,0x79,0x1c,0xc6,0x5f,0xdd,0xab,0x74,0x20,0xe5,0x6c,0x46,0x0a,0x1b,0x24,0xc5,0x15,0x6f,0x60,0x96,0xc0,0x48,0x6e,0xf1,0xc1,0x3e,0xfd,0xf0,0x4b,0xd9,0x20,0x8d, - 0x04,0x20,0xc8,0x9a,0xbe,0xd5,0xc9,0x17,0x41,0x42,0xe0,0x6c,0x94,0xab,0xcc,0x5c,0x8e,0x9e,0x49,0x07,0xd7,0x0e,0xbe,0x00,0x4e,0x29,0x8e,0x92,0xa7,0x8f,0xfd,0x3c,0x1d,0xf8,0x20,0x8d, - 0x04,0x20,0xc8,0xa6,0xdb,0x57,0xab,0x6e,0xf0,0xa9,0x8b,0x10,0x90,0x4c,0x82,0x6e,0x02,0x21,0x37,0xbb,0xf3,0x81,0xec,0x28,0x74,0x8e,0x1c,0xcd,0x92,0xf8,0xaf,0xfd,0x8e,0xe4,0x20,0x8d, - 0x04,0x20,0xc8,0xa8,0x68,0xc8,0xb8,0xb8,0x77,0x8e,0xd0,0x41,0x1b,0x46,0x82,0xd6,0x7d,0x42,0xdf,0xcf,0x83,0x5a,0xde,0xe5,0x5e,0x6a,0x38,0x2e,0x85,0x5c,0xb9,0xa2,0x89,0x9d,0x20,0x8d, 0x04,0x20,0xc8,0xad,0xeb,0xab,0x81,0x2b,0x57,0xcf,0x16,0xfb,0x62,0xa2,0xc5,0xb5,0x4d,0x0d,0x9a,0xf9,0x4a,0xf2,0x7f,0xce,0xb5,0xad,0x3b,0xe1,0x47,0x15,0x52,0x79,0x9c,0xbd,0x20,0x8d, - 0x04,0x20,0xc8,0xb1,0x46,0x21,0xf4,0x02,0x1d,0x36,0x74,0xa7,0x29,0x58,0x74,0x4f,0x60,0x4e,0x62,0x68,0x20,0xe7,0x40,0x4f,0xfd,0xae,0xa9,0x77,0x4e,0x39,0xf0,0x08,0x9d,0x28,0x20,0x8d, - 0x04,0x20,0xc8,0xf4,0xc3,0x22,0x44,0x9c,0xb5,0xb4,0x71,0x92,0x5d,0xd2,0xbf,0xf4,0xb1,0x74,0x13,0x83,0x4e,0x84,0xe2,0xda,0xe8,0x77,0xd0,0x56,0xdc,0x71,0xf2,0x02,0xbb,0xdc,0x20,0x8d, - 0x04,0x20,0xc8,0xf6,0x5b,0xb7,0xed,0xb2,0xd3,0xff,0x43,0x09,0x91,0x28,0x16,0x71,0xda,0x34,0xbf,0xb4,0xd7,0x46,0xd6,0x9f,0x7f,0x4f,0x5c,0xcf,0xdf,0xd7,0x11,0xc6,0x81,0x36,0x20,0x8d, - 0x04,0x20,0xc8,0xfe,0x88,0xe2,0x53,0x06,0xed,0x34,0x70,0x85,0x0a,0x61,0xb1,0xa3,0x49,0x2d,0x75,0xbf,0xb4,0xf6,0x74,0xe8,0xf4,0xee,0x33,0xa1,0x6b,0x50,0x57,0x84,0xed,0x19,0x20,0x8d, - 0x04,0x20,0xc8,0xff,0x48,0x7f,0xa3,0x58,0xa4,0x48,0x77,0x9e,0x5b,0x03,0x0c,0x30,0xfb,0xf8,0x9a,0x86,0xb9,0x40,0x4d,0x94,0x8b,0xbe,0xb4,0x7a,0x16,0xb0,0xfc,0xa6,0x7c,0x0c,0x20,0x8d, - 0x04,0x20,0xc8,0xd1,0xcf,0x03,0x34,0x4d,0xc4,0x98,0x03,0x56,0x6d,0x46,0x41,0x2c,0x7b,0x08,0xd4,0xf9,0x74,0x91,0x0b,0x86,0x2a,0xdb,0x4c,0x6f,0x35,0xc3,0x2b,0x41,0xc7,0x59,0x20,0x8d, - 0x04,0x20,0xc8,0xd9,0xdc,0xdd,0xd3,0xb0,0xe4,0xc0,0x6d,0x35,0x42,0x76,0x96,0x2d,0x44,0xed,0x98,0x15,0xdb,0x1f,0x80,0x34,0xa4,0x28,0xa2,0x9a,0xf2,0xb9,0x92,0xf7,0xf2,0xf7,0x20,0x8d, - 0x04,0x20,0xc8,0xdb,0xae,0x47,0x68,0x75,0x43,0x72,0xa9,0xfd,0x85,0xfa,0xd3,0x7e,0x28,0x0b,0x78,0x28,0x33,0x95,0xe9,0x23,0x2e,0x39,0x6d,0x0e,0x68,0x6c,0x3f,0x46,0x09,0xc7,0x20,0x8d, - 0x04,0x20,0xc8,0xdd,0x51,0xb4,0x8a,0x27,0xdd,0x79,0xdc,0x6d,0x21,0x3e,0x5e,0x6e,0xa2,0xa7,0x58,0x9c,0xb8,0x1d,0x67,0x02,0x4b,0xbe,0xe6,0xab,0x9e,0x0e,0xa8,0x17,0xc4,0x45,0x20,0x8d, - 0x04,0x20,0xc8,0xdd,0x5c,0x78,0xc2,0x4f,0x9b,0x16,0x5c,0x18,0x33,0x53,0x02,0xef,0x0c,0xe9,0xc2,0x3d,0xcb,0xe7,0xda,0x23,0x96,0xc8,0x31,0x4b,0x0c,0x3c,0x58,0x7a,0x8a,0x93,0x20,0x8d, 0x04,0x20,0xc8,0xdd,0x84,0xa9,0x75,0xef,0xfd,0x4d,0xdb,0x8f,0x05,0xf0,0x90,0xf1,0x2c,0x19,0xef,0xa4,0x0f,0xf7,0x74,0x14,0x3f,0xe5,0xbb,0x94,0x9e,0xe1,0x82,0x4c,0x60,0x32,0x20,0x8d, - 0x04,0x20,0xc8,0xe0,0xe6,0xfe,0x9d,0x71,0x50,0xde,0x9b,0x1c,0x88,0x98,0xa4,0x5c,0x5f,0xa7,0x35,0x7c,0x3e,0xca,0x5b,0x67,0x61,0x11,0xc7,0x79,0x15,0x34,0x49,0xca,0x92,0xa2,0x20,0x8d, - 0x04,0x20,0xc8,0xe1,0x72,0xe6,0x17,0x08,0x01,0xee,0xf1,0xb2,0x69,0x9a,0x08,0x0f,0x3b,0x49,0x64,0x52,0x6a,0x9c,0x3d,0xe5,0xcd,0x09,0xd5,0x08,0xa7,0xa1,0xba,0x9f,0xcf,0xd2,0x20,0x8d, - 0x04,0x20,0xc8,0xe6,0x23,0xa0,0xb2,0xe9,0xa0,0xb1,0xa1,0x31,0xfd,0x72,0x23,0x42,0x00,0x2c,0xd6,0x2c,0x0c,0xe0,0x9b,0x3b,0xf7,0x58,0x76,0xcc,0x4d,0x41,0xb6,0x5d,0xab,0xc6,0x20,0x8d, - 0x04,0x20,0xc8,0xf2,0xa1,0x45,0xae,0x14,0xe0,0x76,0xeb,0xc7,0x48,0x5a,0x67,0x89,0x7d,0xe3,0x59,0x57,0x64,0x2e,0x19,0x78,0x6b,0x17,0xe0,0x69,0x6e,0x98,0xd8,0xe9,0xb9,0xa9,0x20,0x8d, - 0x04,0x20,0xc9,0x13,0xf6,0x23,0x29,0x58,0x75,0xe8,0x10,0x4f,0x7e,0x6a,0x6c,0x4a,0xc4,0x8d,0x67,0xf7,0x57,0xc5,0xe5,0xfc,0x5b,0x45,0xd3,0xfb,0x83,0x50,0x07,0x5b,0xbc,0xab,0x20,0x8d, - 0x04,0x20,0xc9,0x13,0x80,0x4e,0xd8,0x03,0xe7,0x5a,0xd0,0x2f,0xf0,0x75,0xa1,0x3d,0xd6,0xd8,0x1b,0xcf,0x86,0x51,0xa9,0x3d,0xb5,0xfa,0x24,0x8a,0x96,0x36,0x52,0xd6,0x0e,0xfe,0x20,0x8d, - 0x04,0x20,0xc9,0x1f,0x01,0x8e,0xdc,0xc8,0x21,0x00,0x59,0x57,0xf8,0x20,0x4c,0xbe,0x16,0xc2,0xae,0xcb,0xdc,0x87,0xd3,0x9e,0xd5,0xee,0xed,0x86,0x91,0xe7,0xa0,0x19,0x15,0x70,0x20,0x8d, - 0x04,0x20,0xc9,0x24,0xed,0x0c,0x32,0x53,0xf6,0x2a,0x45,0xaf,0x35,0x0d,0xd6,0x27,0x15,0x3c,0xbe,0x8f,0x44,0x91,0x76,0xf2,0x18,0x3b,0xad,0xee,0xf9,0x61,0x0a,0x53,0x13,0x95,0x20,0x8d, - 0x04,0x20,0xc9,0x2e,0xd5,0x99,0xa5,0xba,0xc7,0x8b,0xf9,0x64,0x44,0x2b,0x83,0xd1,0x0c,0x89,0x6f,0x96,0xa4,0xa9,0x72,0x9d,0xa2,0x2b,0xd1,0x1c,0xe9,0xc1,0xd6,0xca,0xae,0x66,0x20,0x8d, - 0x04,0x20,0xc9,0x78,0x26,0x7c,0x26,0xaf,0x20,0xe5,0xac,0x49,0x12,0x7e,0xa7,0xdf,0x90,0x8c,0xe1,0x91,0x48,0x1b,0x87,0xe4,0x39,0x69,0x22,0xdb,0x2f,0x4e,0x74,0xd5,0x06,0x57,0x20,0x8d, - 0x04,0x20,0xc9,0x78,0xae,0x10,0xa3,0x78,0xad,0x22,0xe1,0xc1,0xcf,0x39,0xc1,0x98,0x65,0x6c,0x81,0xe9,0x8c,0x23,0xf0,0x1d,0x1f,0xbf,0x52,0xf3,0x1f,0x47,0x2f,0x6b,0x00,0xe5,0x20,0x8d, - 0x04,0x20,0xc9,0x7c,0xdb,0x2e,0x31,0x98,0xfd,0x0f,0xee,0x55,0x12,0x18,0x62,0xbf,0xbc,0x7a,0x1a,0xde,0x78,0xe1,0x14,0x51,0x06,0xc2,0x12,0x44,0xf3,0xb2,0x85,0x01,0xcb,0x14,0x20,0x8d, - 0x04,0x20,0xc9,0x7d,0x30,0xb0,0xe2,0x3b,0x32,0xee,0x79,0x6c,0x3d,0xfd,0x5a,0x6e,0x4c,0x4a,0x77,0x8e,0x1d,0x29,0x8d,0x78,0xb6,0xd9,0xe0,0xdd,0x21,0xf0,0xd6,0x69,0x15,0x80,0x20,0x8d, - 0x04,0x20,0xc9,0x4f,0x7e,0xb4,0x91,0x82,0x89,0x16,0x6d,0x25,0x74,0x39,0xff,0x6e,0xab,0x60,0x31,0xc7,0xa0,0xa8,0x9f,0x41,0xe0,0x79,0x33,0x12,0x6e,0xfa,0x7e,0x7c,0x30,0x16,0x20,0x8d, - 0x04,0x20,0xc9,0x5d,0xfd,0x54,0x1b,0x8b,0x50,0xeb,0x84,0xe7,0xe2,0xa9,0x33,0xf0,0x8f,0x85,0xa1,0x0a,0x13,0xfc,0x01,0x0e,0xb7,0x36,0xa3,0x26,0xe2,0x4f,0x32,0xa7,0xcf,0x29,0x20,0x8d, - 0x04,0x20,0xc9,0x5c,0xc4,0x02,0x5b,0xa2,0x7f,0x6f,0x48,0x08,0xdc,0xf1,0xb1,0x3a,0xe7,0x68,0x7d,0x57,0x2c,0x74,0x18,0x49,0x85,0x8c,0xd8,0x20,0xef,0x07,0x79,0x45,0x17,0xe2,0x20,0x8d, - 0x04,0x20,0xc9,0xb5,0x89,0x2d,0x56,0x00,0x4d,0x41,0x29,0x50,0x03,0x71,0x7b,0x05,0xa2,0x8c,0xdd,0x91,0x68,0xa9,0x45,0x65,0x82,0x4a,0x22,0x1e,0xbf,0x7b,0xa9,0xd6,0x50,0x45,0x20,0x8d, - 0x04,0x20,0xc9,0xbe,0xe0,0xdc,0xe1,0xe0,0xb8,0x9d,0x8c,0xd9,0x37,0x3f,0x92,0x94,0x24,0x98,0x97,0x5d,0x49,0xdc,0x2b,0xb1,0x49,0x8e,0xe8,0xc9,0x5a,0x41,0x9c,0x6a,0x3a,0x72,0x20,0x8d, - 0x04,0x20,0xc9,0x81,0x40,0x85,0x9c,0x3f,0xe0,0x25,0x4f,0x8f,0x34,0xdf,0xdc,0x82,0xd1,0x11,0x7c,0x00,0x64,0x38,0xd6,0x55,0xf0,0x11,0xdd,0xbc,0xa0,0xf3,0x5a,0x42,0xd6,0x22,0x20,0x8d, - 0x04,0x20,0xc9,0x88,0x67,0xdc,0x31,0xfe,0x77,0xc3,0x51,0xe4,0x6a,0x03,0xc9,0xd2,0xd8,0xb6,0x15,0xc6,0xac,0x95,0x77,0x46,0xa2,0x9b,0x69,0x9f,0x85,0xa4,0xdb,0x5b,0x59,0x1b,0x20,0x8d, - 0x04,0x20,0xc9,0x93,0x19,0xbb,0x7a,0x32,0x00,0xdc,0x3f,0xc8,0xe1,0x85,0xfd,0xb5,0x68,0x5b,0x86,0x88,0x61,0xda,0x97,0x46,0xa8,0xf4,0x95,0xfe,0xf1,0x0e,0x42,0xa2,0x4d,0xd5,0x20,0x8d, - 0x04,0x20,0xc9,0x9f,0xb2,0xec,0x6c,0xb0,0x5b,0x1f,0xeb,0xbf,0x8b,0xa9,0x75,0x18,0x63,0x42,0x63,0xbe,0x28,0x8e,0x0e,0x63,0x35,0x74,0xca,0x66,0x86,0x62,0x86,0xda,0x0e,0x16,0x20,0x8d, - 0x04,0x20,0xc9,0xa2,0xf9,0x1c,0x63,0x22,0x12,0xc1,0xbf,0x7c,0xb9,0x71,0x6d,0x2b,0x3a,0xd2,0xc1,0xc4,0xdc,0xd6,0x11,0x39,0xa7,0xd1,0xe9,0x7e,0xc2,0xef,0x5e,0x62,0x3c,0x9d,0x20,0x8d, - 0x04,0x20,0xc9,0xaa,0xa5,0xb5,0xb9,0xd0,0x2b,0x01,0x37,0x08,0x29,0x6d,0xf9,0xfa,0x8c,0x0e,0xd1,0x2e,0x4c,0xb3,0x3b,0x55,0x90,0x9d,0xb8,0x2c,0x7f,0xe9,0x26,0x76,0xa7,0x69,0x20,0x8d, - 0x04,0x20,0xc9,0xac,0x25,0x94,0x28,0xd7,0x65,0xc9,0x83,0xa7,0x2a,0x2d,0x85,0x85,0xc4,0x44,0xe6,0x8f,0x72,0xf9,0x70,0x1b,0xd0,0x12,0xd4,0x82,0x18,0xfe,0xa7,0xbd,0x6e,0x09,0x20,0x8d, - 0x04,0x20,0xc9,0xae,0x6e,0x0f,0x89,0x41,0x68,0x83,0x99,0xd9,0x80,0x57,0x19,0xed,0x49,0x54,0x4f,0xdc,0x9c,0x31,0xe5,0x30,0x8a,0xce,0x39,0x2e,0x94,0x76,0x86,0x61,0x27,0x33,0x20,0x8d, - 0x04,0x20,0xc9,0xc0,0x1b,0xb9,0x61,0x24,0x62,0xa9,0xb4,0xc0,0xd1,0x11,0x7a,0x9c,0x9e,0xab,0x00,0xeb,0xba,0x91,0xda,0xa6,0x3f,0x24,0xc9,0x86,0xc8,0xcc,0xa8,0xd3,0x3c,0x98,0x20,0x8d, - 0x04,0x20,0xc9,0xc0,0xf6,0xbe,0xef,0x56,0xd6,0xc8,0x96,0x4c,0x3a,0xe9,0x89,0xce,0x6e,0x19,0x1d,0x26,0x20,0x9f,0xc0,0x03,0x8b,0x03,0x60,0x05,0xd9,0x35,0x44,0x87,0xd2,0xd8,0x20,0x8d, - 0x04,0x20,0xc9,0xc6,0x3e,0x6a,0x67,0xde,0xdf,0x5f,0x41,0xa5,0x47,0xeb,0xbb,0x6c,0xc3,0x1e,0x37,0x35,0x9a,0x9e,0x7a,0x5d,0xa0,0x9c,0xfd,0x26,0x69,0x89,0xd2,0x77,0x3a,0x2a,0x20,0x8d, - 0x04,0x20,0xc9,0xc8,0x0f,0xbe,0xa7,0xa6,0x6d,0xc1,0x4c,0x9f,0x7a,0x87,0xfa,0x79,0x76,0x4e,0x11,0x01,0x66,0xe8,0xfd,0x8d,0x5c,0x9c,0xae,0xac,0xd2,0x3f,0xc2,0xc3,0x16,0xb8,0x20,0x8d, - 0x04,0x20,0xc9,0xcc,0x3a,0x9d,0xa7,0xee,0x70,0xc0,0xda,0x2c,0x1e,0xa2,0x54,0xb4,0x4f,0x04,0x43,0x72,0xa3,0x11,0x04,0x0f,0xc4,0x31,0x5e,0x52,0xf7,0x35,0x2e,0x66,0x10,0x97,0x20,0x8d, - 0x04,0x20,0xc9,0xce,0xaa,0xf6,0x9f,0x7d,0xe9,0x4d,0xfb,0x1f,0xae,0x69,0xeb,0x2c,0x29,0x78,0xf7,0x62,0xce,0xe5,0xa0,0x07,0x29,0x4f,0x68,0x2c,0xb7,0x0d,0x6c,0x98,0x1b,0x00,0x20,0x8d, - 0x04,0x20,0xc9,0xcf,0x7b,0xaf,0x3b,0xb5,0x46,0x04,0xf2,0x42,0x19,0x26,0xe5,0x2a,0x06,0x96,0x9a,0x36,0x0e,0xb8,0x2d,0xa1,0xc8,0x5a,0x2d,0xda,0xf6,0x7a,0xe9,0x05,0x9a,0xcd,0x20,0x8d, - 0x04,0x20,0xc9,0xe3,0x95,0x4b,0xe6,0x50,0xeb,0x82,0x17,0xd2,0xd0,0x1c,0x6b,0xde,0x96,0xfa,0x20,0x72,0x22,0xec,0x88,0xf2,0x65,0x41,0xd3,0x7d,0x57,0xd0,0xa7,0x3c,0xac,0x3b,0x20,0x8d, - 0x04,0x20,0xc9,0xec,0xc9,0x04,0x1f,0x87,0xaa,0xde,0x60,0xa8,0xf6,0xdf,0xc9,0x8b,0x63,0x70,0x64,0x08,0xc9,0xdc,0xde,0xb5,0x86,0xaf,0xae,0x29,0x8c,0x90,0xe1,0x0e,0xc9,0x0b,0x20,0x8d, - 0x04,0x20,0xc9,0xf2,0xfa,0x30,0x3c,0x44,0xcc,0x3b,0xe3,0xbb,0x11,0xe0,0xeb,0x4e,0x9c,0xdc,0x69,0xad,0x80,0xdb,0x2e,0xff,0x1f,0xff,0x03,0x4c,0xb7,0x3e,0xbb,0xe1,0x73,0x94,0x20,0x8d, - 0x04,0x20,0xca,0x3f,0xf1,0x5c,0x16,0x9a,0x9b,0x05,0x25,0x0e,0x1f,0x22,0x72,0xfc,0xd2,0xa1,0x8e,0x1a,0xd7,0x59,0xf1,0x3e,0xc3,0x75,0x40,0xbf,0x3d,0xda,0x0b,0x95,0x99,0xb8,0x20,0x8d, 0x04,0x20,0xca,0x14,0x4e,0xcb,0xf7,0x98,0x8c,0xff,0x16,0x21,0x49,0xb2,0x93,0x8b,0x3e,0x34,0xaa,0x3d,0xbc,0xc7,0x52,0xf4,0x94,0x37,0x72,0x18,0x25,0x12,0x2b,0x75,0xc7,0xd7,0x20,0x8d, - 0x04,0x20,0xca,0x1f,0xbf,0xe2,0x44,0x2b,0x04,0x16,0xe2,0x15,0x9f,0x12,0x80,0x1b,0xc3,0x4e,0xcf,0xce,0xa0,0x9f,0x3f,0x7c,0x76,0x5b,0xea,0x99,0xc8,0xe9,0xaa,0x80,0x32,0x1e,0x20,0x8d, - 0x04,0x20,0xca,0x1f,0x93,0x0e,0x3a,0x67,0x8c,0xc4,0x96,0x82,0xa3,0xff,0x77,0x92,0x33,0x75,0x67,0xfe,0x78,0xbd,0xf9,0xe2,0x60,0xfd,0x69,0xf3,0x39,0x1b,0x91,0xa8,0x23,0x3d,0x20,0x8d, - 0x04,0x20,0xca,0x21,0x44,0x57,0xa3,0xd9,0xc6,0x89,0x87,0x51,0xd4,0x19,0x3f,0x9d,0xbf,0x53,0x5d,0x21,0x89,0xca,0xb9,0x36,0xa3,0xa7,0x6a,0x33,0x75,0xdd,0xaf,0xc2,0xc3,0x57,0x20,0x8d, - 0x04,0x20,0xca,0x30,0xff,0x6a,0x9c,0xb9,0x65,0x45,0xa5,0xbd,0x01,0x38,0xdf,0xa4,0x80,0xfd,0x8a,0x3f,0x54,0xb4,0x9a,0x89,0x3d,0x13,0xfb,0x0e,0x62,0x77,0xca,0x6e,0xcc,0xbb,0x20,0x8d, - 0x04,0x20,0xca,0x7b,0xd5,0x1d,0x86,0x91,0x0e,0xcd,0x70,0x85,0x3f,0x1a,0xcc,0x13,0xee,0x03,0xb7,0x4d,0xaf,0x93,0x4d,0x15,0xd2,0x0c,0xc7,0x26,0x36,0xc9,0xe9,0x0f,0x79,0x65,0x20,0x8d, - 0x04,0x20,0xca,0x7e,0x92,0xfd,0xdc,0x0e,0xe1,0x99,0x8d,0xd1,0x4e,0xa5,0x37,0x26,0xbc,0xa4,0xbe,0xbc,0xc2,0x5b,0xf9,0x43,0x40,0xc1,0xf0,0x86,0xad,0x4e,0x0e,0xe8,0xd8,0xae,0x20,0x8d, - 0x04,0x20,0xca,0x46,0x5d,0x7e,0xdb,0xac,0xf9,0x17,0xe0,0x3e,0xa4,0x81,0xb8,0xf7,0x08,0xe7,0x7b,0x2a,0xe0,0x07,0x07,0x21,0x39,0x16,0xd5,0xc4,0x58,0x5d,0x9d,0x99,0xe9,0xc4,0x20,0x8d, - 0x04,0x20,0xca,0x4c,0xdb,0xa0,0xfc,0xec,0x73,0xb5,0x01,0x66,0xbd,0x4f,0x82,0x07,0x00,0xa8,0x9a,0xe3,0xb1,0xc0,0xd8,0x44,0xd5,0xf4,0x56,0x53,0x21,0xd7,0xb0,0x38,0xc3,0xc1,0x20,0x8d, - 0x04,0x20,0xca,0x6f,0xd8,0xb0,0x0a,0x1e,0x5d,0x16,0x06,0xd9,0x5e,0xbf,0x6e,0x5c,0x54,0x11,0x0f,0x64,0x02,0x7b,0x1b,0x5a,0x27,0x40,0x68,0xb1,0x24,0x16,0x07,0xe3,0x37,0x0a,0x20,0x8d, 0x04,0x20,0xca,0x71,0xf1,0xf6,0x7e,0x8d,0xd6,0x91,0x7b,0x8f,0xac,0xc1,0xb3,0xc1,0x1e,0xc5,0xf2,0x59,0x35,0x17,0x98,0x64,0xb0,0x14,0x0c,0x75,0xd0,0x8b,0x79,0xf3,0x13,0x2b,0x20,0x8d, - 0x04,0x20,0xca,0xb6,0x23,0x22,0x57,0x7e,0xe9,0x72,0x56,0x97,0x60,0x72,0x16,0x43,0x07,0xaa,0x8e,0x4c,0xc9,0xe4,0xc0,0xdd,0xa0,0xb0,0xf4,0xfe,0x83,0xe6,0x5b,0x4a,0x5f,0xab,0x20,0x8d, - 0x04,0x20,0xca,0x85,0xa5,0xa0,0x7a,0xe7,0x81,0xd4,0xc7,0x43,0x7d,0xe7,0x56,0x4e,0x9a,0x99,0x51,0x69,0xf4,0x61,0x8e,0x37,0x7c,0x06,0x9a,0xd0,0x7d,0xaa,0x9a,0x82,0x77,0x41,0x20,0x8d, 0x04,0x20,0xca,0x91,0x20,0xaf,0x6f,0xaf,0xc7,0x2c,0xee,0x59,0x18,0x2d,0x34,0x72,0x3f,0x61,0xe2,0x79,0x4a,0x17,0x2e,0xe8,0xe7,0xa3,0x75,0x8a,0x03,0xd1,0xbe,0x7e,0xa6,0xa9,0x20,0x8d, - 0x04,0x20,0xca,0x92,0xda,0x50,0x8d,0x41,0xb2,0x79,0x78,0x7d,0xc7,0xb4,0x91,0x4f,0x93,0x44,0x41,0xe2,0xe5,0x09,0x85,0xf4,0xad,0xe3,0x32,0x1c,0xb1,0x45,0xd2,0x7e,0xc5,0x9f,0x20,0x8d, - 0x04,0x20,0xca,0x92,0xe2,0x57,0xbb,0xb7,0x09,0xde,0x7f,0x2e,0x9e,0xfa,0xe6,0xbd,0x88,0x4f,0x0a,0x8a,0x04,0x9c,0x03,0x98,0xdc,0x4a,0x73,0x84,0xeb,0xdf,0xfb,0x23,0x8f,0xec,0x20,0x8d, - 0x04,0x20,0xca,0x97,0xa2,0xc9,0x08,0x95,0x36,0x2c,0x1c,0xf2,0xa0,0x3f,0x05,0xc7,0xa0,0x29,0xf1,0x56,0x14,0xfc,0x83,0x00,0xf3,0x50,0x28,0x76,0x0e,0xe2,0x3e,0x03,0x0f,0x3c,0x20,0x8d, - 0x04,0x20,0xca,0x97,0xfb,0xee,0x9f,0xdf,0xbb,0x94,0xf9,0xcf,0x41,0xbb,0xb1,0xde,0x73,0xc7,0xc5,0x3b,0x69,0x09,0x40,0xec,0x0e,0x2c,0x23,0x09,0xc5,0x5d,0xd9,0x4b,0x1e,0xb4,0x20,0x8d, - 0x04,0x20,0xca,0x9b,0x07,0x51,0x5e,0xcf,0xcd,0xf3,0xf7,0x1f,0x8b,0x30,0x28,0x07,0xd2,0x36,0x70,0xac,0x2c,0x21,0x2b,0xea,0x5e,0x90,0xac,0xca,0x03,0x6b,0x6f,0xff,0x43,0x10,0x20,0x8d, - 0x04,0x20,0xca,0xa1,0xc2,0x98,0x42,0xe0,0x6e,0xa9,0x06,0x48,0xff,0x1e,0x9b,0x24,0xa1,0xc7,0x66,0x3b,0x37,0x5e,0xc1,0xd2,0xd6,0x12,0xd8,0xd4,0x31,0xe0,0x6d,0x7d,0x7f,0x82,0x20,0x8d, - 0x04,0x20,0xca,0xa3,0xef,0x5d,0x51,0xa9,0x04,0x6a,0x79,0x2a,0xc0,0x1b,0xe6,0xde,0xb3,0x21,0x70,0xd2,0xe9,0x8f,0x92,0xe5,0xd1,0x4a,0xa5,0xf2,0xe7,0xe5,0xce,0x15,0x74,0x85,0x20,0x8d, - 0x04,0x20,0xca,0xae,0x4d,0x15,0xac,0xe4,0xe4,0xc0,0xd3,0x81,0x19,0x89,0xf4,0x7d,0x3a,0x11,0x24,0x58,0xc3,0xae,0xcb,0x4b,0x97,0x04,0xbc,0x65,0xa6,0x44,0x84,0xe4,0x6b,0xff,0x20,0x8d, - 0x04,0x20,0xca,0xb2,0x9e,0x75,0x8e,0xba,0x4e,0x9a,0xc7,0x30,0xb1,0x0f,0xd3,0x6d,0x18,0xa0,0x86,0x1d,0x40,0x10,0x0e,0x3f,0x51,0xcd,0x8b,0x80,0x6b,0x76,0x33,0xb4,0xde,0xfe,0x20,0x8d, - 0x04,0x20,0xca,0xb2,0x9e,0x50,0xf5,0xab,0xc1,0x5f,0x10,0x9f,0x1a,0x54,0x54,0xea,0x84,0x67,0xa7,0x89,0x59,0x1f,0x40,0xf3,0x47,0xa9,0xd9,0x93,0xc2,0x68,0xe9,0x45,0xac,0x55,0x20,0x8d, - 0x04,0x20,0xca,0xf5,0xf1,0x51,0x9b,0x32,0xf1,0xf6,0x94,0xf6,0x5f,0xe8,0xb6,0xb8,0x3e,0x7e,0x10,0x23,0xbe,0xe6,0x5b,0x65,0x2e,0x14,0xb0,0xae,0xe6,0x48,0xaa,0x14,0x39,0x76,0x20,0x8d, - 0x04,0x20,0xca,0xf6,0x3b,0xf1,0xb2,0xb2,0x49,0xf5,0xf5,0xfa,0x29,0xab,0x87,0xd4,0x9d,0xb5,0x0c,0x58,0x4c,0x51,0xa6,0xa8,0x3e,0xf6,0x0e,0xff,0xe7,0x01,0xbf,0x41,0x9b,0x3c,0x20,0x8d, - 0x04,0x20,0xca,0xf8,0x69,0xfa,0x80,0x28,0x2c,0xde,0x77,0x51,0x5c,0x03,0xcb,0x69,0x94,0x4d,0x27,0xd9,0xa4,0x4d,0x87,0x00,0x71,0xc7,0xd4,0x10,0xf0,0x4a,0x68,0xd3,0xca,0xe4,0x20,0x8d, - 0x04,0x20,0xca,0xfb,0x57,0x42,0xa6,0xc1,0x7e,0x32,0x19,0x6f,0xb8,0x19,0x9f,0x1d,0xe6,0xe0,0x50,0x48,0x95,0xa6,0x84,0x98,0xca,0x7f,0x56,0x79,0x29,0x3f,0xcd,0xc9,0x07,0x3f,0x20,0x8d, - 0x04,0x20,0xca,0xd0,0x09,0xf0,0xb1,0xb9,0x28,0x88,0xdf,0x6d,0x0a,0x12,0x25,0xa6,0xa6,0x8f,0x6c,0x46,0x05,0x02,0x36,0xbc,0x51,0xbc,0xc3,0x07,0x1e,0xd7,0xcb,0x8e,0x35,0x00,0x20,0x8d, - 0x04,0x20,0xca,0xd1,0x8e,0xbb,0x94,0x81,0x9f,0x04,0xe9,0xa1,0x36,0x00,0x38,0x35,0x6e,0x63,0x53,0x36,0x0d,0x76,0x75,0xc5,0x41,0xd2,0xc2,0x28,0x2b,0x99,0x1a,0x89,0xe6,0x78,0x20,0x8d, - 0x04,0x20,0xca,0xd5,0x68,0x62,0x6f,0xb8,0x4e,0xa3,0x72,0x8c,0xb3,0xe0,0x8c,0x37,0x3e,0x6a,0x08,0x5c,0xc1,0x21,0x45,0xb3,0x1c,0x1b,0x59,0x7d,0xac,0xca,0xb2,0xde,0x7b,0x25,0x20,0x8d, - 0x04,0x20,0xca,0xdf,0x99,0x8a,0x04,0xc7,0x1d,0x21,0xed,0xcc,0x9b,0xe4,0xcf,0xb1,0x02,0x89,0xfc,0x98,0xde,0x90,0xc9,0x08,0x46,0x8d,0xed,0x32,0xb5,0xd4,0x60,0xa7,0x59,0x10,0x20,0x8d, - 0x04,0x20,0xca,0xef,0xa4,0xaa,0x95,0xd2,0x29,0x92,0x95,0xdb,0xe9,0xc5,0xaf,0x72,0x2d,0xab,0x90,0xcc,0x88,0x55,0x9a,0xd6,0x91,0x85,0x94,0x9f,0x09,0x2f,0xfa,0x04,0xeb,0xdb,0x20,0x8d, - 0x04,0x20,0xca,0xf2,0x73,0x74,0xe8,0x7e,0x3e,0xd1,0x72,0x8b,0x90,0x1f,0x13,0x45,0xdd,0xd9,0x7d,0xb6,0x25,0x3f,0x49,0x3e,0xce,0xdd,0xf3,0x32,0x95,0x24,0x04,0xd5,0x08,0xbd,0x20,0x8d, - 0x04,0x20,0xcb,0x34,0x9d,0x2b,0x4d,0x5f,0xdf,0x43,0x68,0x0c,0x00,0xd2,0xa8,0x88,0xd2,0xeb,0x98,0x36,0xdc,0x53,0xc2,0xfe,0x1f,0x29,0x8b,0xc5,0xa4,0xf3,0x88,0xab,0xf0,0xb5,0x20,0x8d, - 0x04,0x20,0xcb,0x0a,0xc1,0xb3,0x2b,0x96,0x31,0xf7,0x58,0x9e,0xab,0xcd,0x43,0x54,0x70,0xf7,0xb9,0x54,0x9d,0x74,0x85,0x22,0x0d,0xc9,0x49,0x5b,0x3c,0x5c,0xbc,0xd0,0x27,0xa8,0x20,0x8d, - 0x04,0x20,0xcb,0x0a,0xc6,0x37,0xfa,0x19,0xba,0x94,0xa9,0xd5,0xc7,0x13,0x3e,0xf8,0x5e,0x0c,0xcd,0xf7,0x99,0xff,0xb3,0x08,0x7e,0xf3,0xf9,0x5d,0x41,0x5b,0x31,0x61,0x88,0x64,0x20,0x8d, - 0x04,0x20,0xcb,0x12,0xd1,0x46,0x36,0x9d,0x11,0xcf,0xf9,0xb8,0x6f,0xa5,0x00,0xbf,0xdf,0x0d,0x4c,0x33,0xba,0x6b,0x5c,0x37,0xba,0xe6,0xd8,0x30,0x25,0x46,0x57,0xc3,0xd5,0x25,0x20,0x8d, - 0x04,0x20,0xcb,0x19,0x31,0x8e,0x24,0xb6,0x98,0x99,0x98,0xf2,0xfe,0x52,0x8c,0x23,0x44,0x22,0xd9,0x89,0x4b,0xec,0x46,0x13,0xa0,0x5f,0x36,0x29,0x9a,0xca,0xe6,0x67,0xbf,0xde,0x20,0x8d, - 0x04,0x20,0xcb,0x1b,0xb4,0xe2,0xbd,0x06,0xa2,0xe1,0xea,0x83,0x6c,0x49,0x83,0x23,0xd4,0x03,0x79,0x98,0x76,0x8b,0xe3,0x0e,0x4b,0x60,0xb8,0x89,0x7e,0x0d,0xd2,0x38,0xfe,0x83,0x20,0x8d, - 0x04,0x20,0xcb,0x21,0x5a,0xe8,0x43,0xba,0x53,0xba,0x84,0x4b,0x87,0xd7,0xe8,0x94,0x6c,0x49,0x0c,0xc4,0x5e,0xca,0xbc,0x9b,0x9c,0x8f,0xd0,0x26,0x6c,0xfd,0xea,0xb7,0x54,0x74,0x20,0x8d, - 0x04,0x20,0xcb,0x27,0xf7,0xc8,0xd3,0x6b,0x61,0x75,0x7a,0x68,0x09,0xeb,0x65,0x0c,0xb4,0x3c,0xcd,0x34,0x82,0x79,0xf0,0x5e,0xec,0x61,0x7c,0x7c,0xe9,0x5d,0xd3,0xca,0x76,0x83,0x20,0x8d, - 0x04,0x20,0xcb,0x26,0x3f,0xe8,0x3c,0x6c,0x81,0xad,0x38,0x44,0xce,0x8e,0x14,0xca,0xf7,0x88,0xcb,0x4b,0xdf,0x06,0x39,0xb7,0x94,0xce,0x09,0x70,0x7b,0x23,0x35,0x2f,0xa4,0xa6,0x20,0x8d, - 0x04,0x20,0xcb,0x29,0x43,0xda,0xe7,0x70,0x3c,0x7e,0xed,0x28,0x4b,0xc3,0xe6,0x0b,0x22,0xac,0xee,0x7b,0x7b,0x38,0x4e,0x18,0xce,0xec,0x76,0xcc,0x82,0xc5,0x0b,0x6a,0x55,0x7b,0x20,0x8d, - 0x04,0x20,0xcb,0x2b,0x14,0x1a,0x80,0x99,0xe4,0x06,0xc2,0x8e,0x2d,0xd8,0xbf,0xa8,0xc2,0x18,0x39,0x35,0x20,0xec,0xec,0x14,0x41,0xfc,0x1e,0x6c,0xc3,0x05,0x7e,0x2c,0xcf,0xe0,0x20,0x8d, - 0x04,0x20,0xcb,0x2b,0x14,0x4d,0x64,0xb8,0xd8,0x60,0x4c,0xb0,0x4a,0xc9,0x75,0xfe,0xd2,0xbe,0xd6,0xc2,0xff,0x1b,0x85,0xc9,0xa5,0x40,0x84,0x89,0x83,0xf6,0xcd,0x45,0xa7,0x1a,0x20,0x8d, - 0x04,0x20,0xcb,0x30,0x0a,0xd3,0x19,0xff,0xf8,0x2d,0x15,0xdb,0x20,0x7b,0xdc,0x39,0x48,0xab,0xe3,0xf8,0x16,0xe3,0x7a,0x71,0xa9,0xf6,0xcf,0x26,0x0d,0x46,0x9e,0x8b,0x12,0xbf,0x20,0x8d, - 0x04,0x20,0xcb,0x32,0x9b,0xf3,0x58,0xba,0xde,0x47,0x8c,0xd8,0x06,0xf9,0x1a,0xd8,0x3b,0xb0,0xb4,0xf2,0x18,0xd3,0xa4,0x50,0x41,0xb1,0xbc,0x91,0x52,0xb9,0x9b,0x1e,0x32,0x67,0x20,0x8d, - 0x04,0x20,0xcb,0x76,0x64,0xa9,0xf0,0x50,0x12,0x0a,0xff,0xca,0x01,0x19,0xa2,0x49,0xf0,0x9e,0x83,0x6f,0x18,0xc5,0xab,0x1b,0xca,0x6c,0xcc,0x53,0x9a,0x39,0x7d,0xf0,0x1f,0x4e,0x20,0x8d, - 0x04,0x20,0xcb,0x76,0xc4,0xea,0x66,0x35,0x9e,0x1c,0xe5,0x55,0x9c,0x9d,0x55,0x44,0x23,0x91,0xc3,0x2a,0x80,0x5f,0x6f,0xbf,0xe3,0x85,0x1f,0xf4,0x7f,0xa1,0x93,0x41,0xe1,0x94,0x20,0x8d, - 0x04,0x20,0xcb,0x7a,0xfa,0x44,0xf7,0xdc,0x5a,0x85,0x29,0x52,0xec,0xef,0xc9,0x09,0xa9,0x59,0xc9,0x6b,0x2d,0x7b,0xa6,0x45,0x2e,0x3c,0xc3,0x26,0xe0,0x48,0x02,0xce,0x2e,0xd2,0x20,0x8d, - 0x04,0x20,0xcb,0x40,0x82,0x1e,0xbb,0x84,0x66,0xb7,0x5c,0x68,0xec,0x54,0x19,0x70,0x90,0x7b,0x29,0x52,0x03,0x34,0x2c,0xdc,0x1d,0xca,0x19,0xb6,0xe6,0x0e,0xbf,0x00,0x55,0x2c,0x20,0x8d, - 0x04,0x20,0xcb,0x43,0x5e,0x0a,0x8f,0x57,0xe3,0x11,0xab,0x91,0x82,0x3d,0x76,0x88,0x2e,0xa1,0xe4,0x2b,0xb6,0x03,0x58,0x6f,0x35,0xcd,0xff,0xef,0xb8,0x89,0x16,0xbd,0xac,0xc3,0x20,0x8d, - 0x04,0x20,0xcb,0x45,0xcb,0x9e,0xd8,0xb2,0x60,0x44,0xb9,0x0e,0x03,0xf7,0x29,0x5e,0xb3,0x90,0xd0,0xb9,0x0b,0xc8,0xeb,0xbb,0x2d,0x45,0xaf,0xd1,0x04,0xcb,0xc0,0x9e,0xb9,0x34,0x20,0x8d, - 0x04,0x20,0xcb,0x48,0x0e,0xb9,0x7f,0x81,0x9a,0x84,0x66,0xbb,0x71,0xb4,0x62,0x88,0x37,0xb6,0xac,0x8e,0x40,0xea,0xf8,0xca,0xa1,0xae,0x7f,0x08,0x6e,0xfc,0x74,0x05,0x5a,0xd3,0x20,0x8d, - 0x04,0x20,0xcb,0x4d,0x73,0x28,0x66,0x54,0x1e,0x5c,0x11,0xe0,0xe8,0xab,0x75,0x82,0xf5,0x5e,0x17,0x4c,0x8e,0x38,0x3e,0x59,0x54,0x02,0x3c,0x72,0x72,0x01,0xd2,0xf6,0xdf,0xce,0x20,0x8d, - 0x04,0x20,0xcb,0x51,0xf5,0x21,0xc0,0x11,0xa5,0x8e,0x9c,0x10,0x41,0x66,0xd2,0x5e,0x3f,0xe4,0xab,0xf8,0xe6,0xa6,0xc7,0x5d,0xe5,0xb3,0x3e,0x1e,0x35,0xea,0xd6,0xc6,0xea,0xca,0x20,0x8d, - 0x04,0x20,0xcb,0x57,0x56,0x31,0x3c,0x1d,0x5e,0x9a,0x73,0xca,0x08,0x7c,0xc7,0x07,0x8a,0xa1,0x70,0x5e,0x83,0x90,0x45,0x71,0x83,0x31,0x29,0xdf,0x95,0x86,0x04,0x00,0xe3,0x72,0x20,0x8d, - 0x04,0x20,0xcb,0x58,0x60,0xa3,0xd0,0x5d,0xad,0x61,0xad,0x19,0x4d,0xe4,0x2f,0x12,0x89,0x69,0x6c,0x6c,0x4e,0x85,0xa7,0x8d,0x47,0x7b,0xe1,0xef,0x01,0x5e,0x63,0xc8,0x6d,0x8d,0x20,0x8d, - 0x04,0x20,0xcb,0x59,0x67,0x03,0x23,0x50,0x8a,0x57,0xc4,0x08,0x5f,0x8f,0xc7,0xf1,0xcf,0xc7,0xd1,0xcc,0xc1,0xcc,0x3b,0xc7,0x72,0x75,0x7d,0x68,0xbc,0x44,0xc0,0x06,0xac,0xf8,0x20,0x8d, - 0x04,0x20,0xcb,0x67,0xa4,0x87,0xcd,0x45,0x52,0x65,0xf3,0xf2,0xd1,0x86,0x23,0x00,0x5b,0x61,0x23,0x04,0x96,0x1d,0x3e,0x9b,0xeb,0xf9,0x81,0x49,0x0d,0x7f,0x16,0x8c,0x9a,0xf4,0x20,0x8d, - 0x04,0x20,0xcb,0x6a,0xa8,0x53,0x7f,0xf2,0x08,0xda,0x7b,0x57,0xe9,0xdf,0x19,0x4d,0xbb,0xf2,0x4b,0x0b,0xba,0x4f,0x13,0x4a,0x77,0x8b,0x6a,0x87,0x61,0x4b,0x08,0x7e,0xe6,0xfc,0x20,0x8d, - 0x04,0x20,0xcb,0x6c,0x45,0x48,0xe3,0xe3,0xa5,0xd0,0x69,0xba,0xd6,0xaf,0x15,0xac,0xc9,0xa6,0x2b,0x2b,0x7c,0xf2,0x0e,0xb1,0xe0,0xc7,0xef,0x55,0x92,0x09,0xe2,0xca,0xea,0xc9,0x20,0x8d, - 0x04,0x20,0xcb,0x6e,0xab,0xe0,0x7d,0xf7,0x24,0x52,0xcc,0xc9,0x90,0xa4,0xc4,0x6c,0x1f,0xda,0x64,0x0c,0xde,0xc7,0x93,0x48,0x8b,0xec,0x26,0x9b,0xb9,0x2a,0x61,0x37,0xdf,0x7d,0x20,0x8d, - 0x04,0x20,0xcb,0xb8,0x51,0x66,0xdc,0x1c,0x4c,0x20,0xca,0x8c,0x99,0x98,0x83,0x25,0x48,0x93,0xb8,0xc4,0x67,0x7c,0x5c,0xc1,0x40,0x24,0x00,0xb4,0x19,0x07,0x03,0xce,0xbb,0x33,0x20,0x8d, - 0x04,0x20,0xcb,0xba,0x90,0x4a,0xb9,0xec,0x1d,0xf7,0xa8,0xd1,0x33,0x79,0x1e,0x76,0x76,0x1a,0x05,0xcc,0x81,0x44,0xf6,0x5e,0x92,0x91,0x89,0xf5,0xf4,0x87,0x5c,0x56,0xac,0xbf,0x20,0x8d, - 0x04,0x20,0xcb,0x82,0x9d,0x7c,0x24,0x63,0xf1,0x79,0x20,0xc3,0xa8,0x2c,0x2f,0x95,0xc8,0xae,0x31,0x42,0x2b,0xfb,0x39,0x18,0x47,0xff,0x25,0xd4,0xc0,0x97,0x17,0xbc,0xdf,0x76,0x20,0x8d, - 0x04,0x20,0xcb,0x86,0x92,0xb0,0x86,0x89,0x2a,0xc4,0x85,0xef,0x86,0xa7,0xcf,0x21,0x74,0x8d,0x08,0x50,0x98,0xfb,0x0f,0x3d,0x30,0xc5,0x7a,0x97,0x60,0xa7,0xc6,0xa1,0x24,0xd5,0x20,0x8d, - 0x04,0x20,0xcb,0x8b,0x22,0x2e,0x6f,0x7e,0xb6,0xdd,0x5c,0x3e,0x2c,0x98,0x53,0x2a,0xc6,0x81,0x8d,0x63,0xc4,0x8b,0xbb,0x27,0xfc,0xc3,0xf3,0x70,0x33,0x80,0x98,0x87,0x0c,0xbe,0x20,0x8d, - 0x04,0x20,0xcb,0x8f,0x70,0x65,0x4e,0x60,0xa3,0xd3,0x1a,0x0b,0x4e,0x88,0x3a,0x6b,0x79,0x97,0xae,0x80,0x63,0xf6,0x2c,0xa3,0x7a,0x12,0x71,0x6e,0x95,0xa9,0x74,0xd6,0x3d,0x8e,0x20,0x8d, - 0x04,0x20,0xcb,0x94,0xc3,0x62,0x5b,0x34,0x8d,0x2e,0xb9,0x15,0x48,0xa0,0xfd,0xdd,0x0a,0x46,0xba,0x82,0x5c,0x99,0xc6,0xf6,0x45,0x66,0x91,0x04,0xc7,0x9d,0xa7,0xb4,0x6c,0x1f,0x20,0x8d, - 0x04,0x20,0xcb,0xa4,0x9a,0x89,0x67,0x86,0x6c,0xa5,0xb1,0x7c,0xd9,0xeb,0x21,0xb2,0x8f,0x32,0xc0,0x94,0xf5,0x65,0x18,0x7a,0x7e,0x96,0x26,0xc3,0x3e,0x79,0x41,0xda,0xec,0x6d,0x20,0x8d, - 0x04,0x20,0xcb,0xa4,0xaf,0x16,0xfa,0x06,0xd9,0x75,0x14,0x04,0x06,0x32,0x84,0x51,0x19,0x86,0xf1,0xb4,0xec,0x19,0xcb,0xf9,0x85,0xdb,0x07,0xff,0xad,0x0d,0x4a,0x13,0x01,0x1b,0x20,0x8d, - 0x04,0x20,0xcb,0xaa,0xcf,0x59,0x40,0x9c,0xf2,0xcb,0x8b,0xfd,0xe8,0x8d,0x08,0x0f,0x92,0xbd,0x0c,0xdd,0xa4,0x17,0xb7,0x38,0x8c,0xad,0x9c,0xc1,0x5e,0xe9,0xea,0x82,0x29,0x20,0x20,0x8d, - 0x04,0x20,0xcb,0xac,0x2f,0xc5,0x4b,0x38,0xfd,0x73,0xa4,0x9f,0xd7,0x2e,0xe6,0x28,0xb3,0xb2,0x19,0x44,0x1c,0x02,0xb0,0x9b,0x75,0x4f,0xf5,0x38,0x52,0xfa,0xbd,0x43,0x01,0xea,0x20,0x8d, - 0x04,0x20,0xcb,0xf7,0x57,0xa9,0xe2,0x28,0xef,0xd5,0xde,0xad,0xa1,0x16,0xb8,0x00,0xbd,0x80,0xea,0x7a,0x71,0x74,0x2f,0x33,0x02,0xdf,0xb7,0x4b,0xb4,0x33,0x13,0xe2,0x84,0xae,0x20,0x8d, - 0x04,0x20,0xcb,0xcc,0xe0,0xbd,0x5a,0x4e,0xa5,0x40,0x50,0xf4,0xc9,0x58,0x7e,0x21,0x19,0xde,0x35,0x93,0xa7,0x77,0xa8,0x76,0x6d,0x4f,0x80,0xff,0xfb,0x3f,0xea,0x53,0x9e,0xd8,0x20,0x8d, - 0x04,0x20,0xcb,0xcd,0x80,0xb4,0x20,0xb9,0x6b,0x94,0x92,0x92,0xfc,0x1a,0x0e,0x77,0x22,0x3d,0xc6,0xa2,0x29,0x2f,0x57,0x6c,0x40,0x8d,0x44,0x84,0xee,0x5b,0x08,0xcb,0x33,0x8c,0x20,0x8d, - 0x04,0x20,0xcb,0xce,0x90,0xb1,0x7b,0x2c,0x26,0x12,0x67,0xdb,0x0a,0x6a,0x3e,0x4b,0xbd,0xd6,0x05,0xab,0x90,0x28,0x98,0x06,0xa7,0xdb,0x49,0x73,0x75,0x05,0x04,0x0f,0x0a,0x17,0x20,0x8d, - 0x04,0x20,0xcb,0xda,0xe7,0x6e,0x0e,0x88,0xeb,0xcb,0xa7,0xa7,0x4e,0x1a,0xa9,0x4a,0x9e,0xb1,0x04,0x7a,0xd1,0xfe,0x9b,0xbe,0xf0,0x32,0x26,0x0a,0x38,0xb4,0xb0,0xb4,0x32,0x71,0x20,0x8d, - 0x04,0x20,0xcb,0xde,0xc3,0xa7,0xfe,0x07,0x87,0x84,0x88,0xfd,0x84,0xe8,0x17,0x4a,0xe2,0xc5,0x67,0x64,0xb4,0x3e,0xcb,0x47,0x22,0xe2,0xd7,0x12,0x3e,0x3c,0x6e,0xa2,0xf2,0xc2,0x20,0x8d, - 0x04,0x20,0xcb,0xe1,0xa6,0xe4,0x4d,0x58,0x24,0xcc,0x6e,0x2c,0xb4,0xd8,0x0c,0x04,0x15,0xf4,0xff,0x72,0xc6,0xae,0x8c,0x20,0x3b,0x36,0x6d,0x09,0x83,0x78,0x51,0x38,0xc6,0xc6,0x20,0x8d, - 0x04,0x20,0xcb,0xe1,0x57,0x6b,0xa1,0xbd,0x38,0xdd,0x53,0x6c,0x3e,0x9e,0x3c,0x82,0xff,0xb3,0x1f,0x24,0x4c,0x7b,0x84,0xa5,0x93,0x5b,0x58,0x26,0xd8,0xf2,0x8d,0xe9,0x09,0xbb,0x20,0x8d, + 0x04,0x20,0xca,0xc5,0x01,0xc3,0x21,0x34,0x38,0x33,0x82,0x4f,0x2f,0x87,0xe2,0x1d,0x47,0xca,0x6f,0xda,0xd8,0x7f,0xd2,0x1d,0x27,0xde,0xe1,0x1b,0x82,0x90,0x5d,0x1c,0x23,0xbc,0x20,0x8d, + 0x04,0x20,0xcb,0x01,0x28,0xb6,0x1d,0x34,0x2d,0x53,0x7f,0x15,0xf6,0xa7,0x2f,0x3f,0x16,0x6f,0x5e,0x84,0xb5,0xc7,0x31,0x60,0x17,0x79,0x38,0x9a,0x28,0x85,0x40,0x74,0x2b,0xfd,0x20,0x8d, + 0x04,0x20,0xcb,0x8c,0x8c,0x77,0x81,0x24,0x66,0x1c,0x1c,0x52,0xed,0x70,0x4f,0xdd,0x32,0x7d,0x2d,0x5c,0x18,0xce,0x61,0x0e,0x2f,0x37,0x53,0x0a,0xad,0x61,0xe7,0x0f,0xd9,0xed,0x20,0x8d, 0x04,0x20,0xcb,0xef,0xa9,0xc3,0x5f,0xc5,0x51,0x6c,0x85,0xe2,0xe3,0x70,0x92,0xc2,0x6b,0x3a,0x0c,0xe0,0x75,0x5f,0x15,0x97,0xef,0xf9,0xa5,0x9f,0xc2,0xa0,0x25,0xde,0x4c,0x35,0x20,0x8d, - 0x04,0x20,0xcc,0x17,0x6c,0xe4,0xb9,0x1b,0x80,0x23,0x34,0xd3,0x93,0x5c,0x56,0x62,0x04,0x98,0x0d,0xe7,0x73,0x85,0xec,0x7f,0xa7,0x3d,0x3f,0xde,0xf1,0xcd,0xf0,0x3f,0x6b,0xda,0x20,0x8d, - 0x04,0x20,0xcc,0x21,0xc3,0x68,0x88,0x50,0x8a,0x65,0xcb,0xdc,0x29,0x65,0x39,0x61,0x65,0x0c,0x22,0x59,0x4d,0x9e,0x6e,0x9d,0x3a,0xc6,0x41,0x9d,0x6a,0x97,0xc2,0xc6,0xc4,0x06,0x20,0x8d, - 0x04,0x20,0xcc,0x22,0x9e,0x14,0xe7,0x7f,0x19,0x0e,0x90,0xfd,0xbb,0xe7,0x91,0x5d,0x39,0x78,0x09,0xbf,0x86,0x2a,0x1b,0x77,0x57,0x67,0x7a,0x84,0x9c,0x75,0xf9,0xae,0x42,0x70,0x20,0x8d, - 0x04,0x20,0xcc,0x23,0x60,0x1f,0xc3,0x6e,0xe7,0xd2,0xd1,0x3f,0x71,0xd7,0x85,0x03,0x5f,0xce,0x5c,0xf1,0xd0,0xf7,0xc7,0x2d,0x85,0x34,0xb1,0x9c,0x1f,0x7e,0x4b,0x0a,0x20,0x89,0x20,0x8d, - 0x04,0x20,0xcc,0x27,0x8a,0xc7,0xe7,0xd7,0xff,0x7e,0xc6,0xe8,0x6f,0xa2,0x79,0x46,0x41,0x3d,0x84,0x59,0x63,0x08,0x81,0x8c,0x77,0xab,0xc9,0x58,0x49,0x62,0x27,0x55,0xdc,0xdb,0x20,0x8d, - 0x04,0x20,0xcc,0x2b,0xd6,0x91,0xf8,0x8d,0x89,0x95,0x61,0x9a,0x08,0x3b,0x2d,0x4a,0x4a,0x62,0x35,0x01,0x2b,0x5a,0x93,0x6d,0xa8,0xe0,0xc4,0x51,0x39,0xd0,0xdc,0xda,0x77,0x2a,0x20,0x8d, - 0x04,0x20,0xcc,0x2a,0x16,0xc2,0xd6,0x3c,0xdd,0x4b,0xea,0x57,0x40,0x9a,0x6d,0x05,0x65,0x43,0xac,0xae,0xb2,0xb3,0xc7,0xc5,0xdb,0xb6,0x52,0xbd,0xa6,0xb9,0x27,0x20,0x59,0xcd,0x20,0x8d, - 0x04,0x20,0xcc,0x75,0xad,0x0b,0x78,0x0d,0x21,0x76,0xf8,0x1e,0x7a,0x30,0x3a,0x95,0xd2,0xe6,0x52,0xd0,0x29,0x65,0x31,0xfc,0xa7,0x15,0x94,0x4b,0x1c,0xb7,0xa1,0xf1,0x2d,0xb9,0x20,0x8d, - 0x04,0x20,0xcc,0x7c,0x52,0xa2,0x57,0xbb,0xb8,0x62,0x2d,0x8a,0x76,0x03,0xf4,0x64,0xac,0xf9,0x0e,0x98,0x86,0x01,0x6e,0x68,0x6a,0x5b,0x7c,0x9b,0xb7,0xc0,0xc0,0xf7,0x21,0x21,0x20,0x8d, - 0x04,0x20,0xcc,0x7f,0x28,0x09,0x68,0x65,0x79,0xe4,0x8d,0xac,0x61,0x01,0x98,0x44,0xe5,0x59,0xd1,0x05,0x1c,0xf1,0xcf,0x51,0xb2,0x0f,0xf8,0xae,0x28,0x4f,0x6e,0x56,0x56,0xe0,0x20,0x8d, - 0x04,0x20,0xcc,0x62,0x58,0xf6,0x51,0xed,0xa2,0x61,0xcf,0xd1,0x6f,0x38,0x2b,0xb5,0xd3,0x5d,0x6c,0x4f,0x89,0x7e,0xfc,0x4d,0x29,0x5b,0xa3,0xb4,0x81,0x7e,0x68,0x95,0x72,0x86,0x20,0x8d, - 0x04,0x20,0xcc,0x62,0x73,0x4b,0xba,0x2c,0xd7,0x85,0xc8,0xf4,0xb3,0xfa,0x4d,0x50,0x92,0x34,0x1b,0x61,0x4f,0xe7,0xf0,0xa0,0x7c,0xb8,0xa3,0x1d,0x2c,0xe4,0x72,0x59,0xdc,0x8e,0x20,0x8d, - 0x04,0x20,0xcc,0x67,0xb8,0x9b,0x8f,0x05,0xd8,0xed,0x72,0x82,0x1f,0x7c,0x42,0x1d,0x7f,0x03,0xd0,0xd1,0x9c,0x34,0x0c,0x36,0x44,0xee,0x1d,0x69,0xe3,0xe4,0x7f,0x49,0xae,0x89,0x20,0x8d, - 0x04,0x20,0xcc,0x6b,0x24,0xa6,0x21,0xda,0xcd,0x56,0x10,0xb3,0xce,0xaa,0x54,0xd4,0x1c,0x7a,0xfd,0xb3,0xcd,0x95,0xec,0x31,0x54,0x43,0xf9,0x3b,0x4a,0xc5,0xab,0x9a,0x25,0x63,0x20,0x8d, - 0x04,0x20,0xcc,0x71,0xa8,0xc1,0x62,0x81,0x7a,0xfe,0x93,0x9e,0xb0,0xbc,0xd6,0x4c,0x41,0x9f,0x6a,0x3e,0x75,0x85,0xe1,0xf0,0x5e,0x36,0xeb,0x83,0x8c,0x25,0x39,0xa8,0xa1,0x46,0x20,0x8d, - 0x04,0x20,0xcc,0xb9,0xf0,0xfb,0xcf,0x5a,0x5f,0x9e,0x00,0xee,0x63,0xc0,0xd1,0x22,0xbf,0xdd,0xe7,0x99,0xb5,0xb9,0x55,0xf9,0x64,0xa9,0x73,0xf1,0xcf,0xc1,0xc6,0x46,0x27,0x19,0x20,0x8d, - 0x04,0x20,0xcc,0x80,0xbb,0x52,0x64,0x29,0xfc,0xcf,0x5f,0xd8,0xb8,0x84,0x13,0xd1,0x79,0x8e,0x74,0x16,0x3b,0xe3,0xcd,0x34,0x63,0x53,0x87,0xbb,0xfb,0x9a,0xee,0xf7,0xd2,0x7d,0x20,0x8d, - 0x04,0x20,0xcc,0x83,0x92,0x92,0x24,0xcb,0x1b,0x8b,0x9d,0xea,0x9d,0xe6,0x21,0x37,0x57,0xbd,0x0c,0x66,0x0f,0x23,0x6c,0x72,0x0f,0xbe,0x09,0x5b,0x6c,0x97,0x44,0xd7,0xef,0xf1,0x20,0x8d, - 0x04,0x20,0xcc,0x8d,0x37,0x63,0x1a,0x95,0x48,0x73,0x94,0x20,0xdf,0x3a,0x3b,0xec,0x60,0xcb,0xff,0x32,0x8d,0x0e,0xf3,0xb7,0xcc,0xdd,0x62,0x36,0x17,0x0f,0x3d,0x1e,0xf9,0x93,0x20,0x8d, - 0x04,0x20,0xcc,0x91,0xde,0xdf,0x4d,0xaa,0x45,0xc7,0x42,0x2f,0xce,0x5c,0xf5,0x34,0x94,0x50,0x7a,0x5a,0x0d,0xac,0xe1,0x3c,0x38,0x81,0xdc,0xbf,0xf6,0xb2,0xf3,0x32,0x39,0xc5,0x20,0x8d, - 0x04,0x20,0xcc,0x90,0xfb,0x49,0x2f,0x67,0x0b,0xb7,0xfa,0x84,0x16,0x4f,0xf5,0xc0,0x88,0xec,0x5f,0xb1,0x52,0x4b,0xf4,0xf8,0x3f,0x35,0xb3,0x6d,0xaf,0x0f,0xe8,0xee,0x8a,0x3a,0x20,0x8d, - 0x04,0x20,0xcc,0x91,0x20,0x0e,0x20,0xfa,0x57,0x77,0xf5,0xa7,0x20,0xb5,0x59,0x26,0xd2,0x7d,0x6a,0xd5,0x79,0x24,0x62,0x6e,0xaf,0xe5,0xbf,0x04,0x70,0xf5,0xf8,0x4c,0xf0,0xf1,0x20,0x8d, - 0x04,0x20,0xcc,0xa3,0xcd,0xde,0x09,0xf3,0x65,0x18,0x1f,0xd0,0x35,0xcc,0x70,0x0c,0x53,0x5c,0xed,0x89,0xb4,0x16,0xe6,0x58,0xba,0xdf,0xc4,0xbc,0x30,0x19,0xea,0x03,0x9f,0xf4,0x20,0x8d, - 0x04,0x20,0xcc,0xae,0x62,0x15,0xea,0x71,0x52,0x2d,0xb6,0x68,0xe4,0x29,0x25,0x6d,0xe3,0x80,0x8a,0x86,0xa9,0x69,0x02,0x57,0x61,0x07,0x42,0x21,0x35,0x31,0xd2,0xeb,0x9d,0xc2,0x20,0x8d, - 0x04,0x20,0xcc,0xb3,0x42,0xc6,0x59,0x7d,0x88,0x07,0x62,0x54,0x0b,0xc6,0xd8,0x3c,0x11,0x66,0x1d,0x34,0xb4,0x95,0xf3,0x4e,0x71,0x34,0x89,0x3a,0x52,0x59,0xd3,0xb2,0x0f,0x7a,0x20,0x8d, - 0x04,0x20,0xcc,0xfc,0x65,0x39,0xfb,0x6f,0x80,0x63,0x46,0xf4,0x13,0x41,0x07,0xf3,0x11,0x49,0x29,0xe3,0xce,0xd5,0xa6,0x34,0xdc,0x37,0x75,0x00,0xd2,0x98,0xb8,0x76,0xb9,0x4e,0x20,0x8d, - 0x04,0x20,0xcc,0xfc,0x7a,0xe7,0x0e,0x02,0xf2,0xce,0x03,0xbf,0xf0,0xe2,0xdf,0xe0,0xb5,0x19,0x26,0x3a,0xe6,0xd6,0x75,0x2a,0x5c,0xf3,0x7d,0xb6,0x62,0x5e,0xbc,0x4d,0xbc,0x2e,0x20,0x8d, - 0x04,0x20,0xcc,0xfd,0x5f,0x92,0x07,0xfd,0x6a,0xbb,0x63,0xaa,0x4e,0x42,0x32,0x99,0x56,0xdc,0xb0,0x9d,0xb5,0xa7,0x12,0xb0,0x63,0xaf,0x26,0x65,0xac,0x51,0x0a,0xf5,0xc1,0x69,0x20,0x8d, 0x04,0x20,0xcc,0xc4,0xc5,0xc6,0x53,0x1a,0x9f,0xf1,0x38,0xe4,0x23,0x96,0xfb,0x27,0xfd,0x33,0xf6,0x86,0x64,0xc8,0xb6,0xbd,0x76,0xb9,0x14,0x14,0x29,0x63,0xde,0xe2,0x71,0x40,0x20,0x8d, - 0x04,0x20,0xcc,0xce,0xc2,0x63,0x94,0x23,0xa9,0x32,0xfe,0x1b,0xf3,0x6c,0x6a,0x26,0xf4,0xf9,0xe1,0xff,0x4b,0xa8,0x28,0x66,0x06,0xd7,0x24,0xe3,0x2f,0x0d,0x4b,0x57,0x86,0x84,0x20,0x8d, - 0x04,0x20,0xcc,0xd9,0x69,0x61,0xdb,0xee,0x54,0xe3,0x3c,0xb3,0xa2,0x59,0xa7,0x7d,0xc8,0x59,0xe8,0x24,0xdc,0x9b,0xb7,0x82,0x90,0x1a,0x40,0x45,0xa6,0x1d,0x06,0x9e,0xd5,0x4c,0x20,0x8d, - 0x04,0x20,0xcc,0xdd,0x4e,0x62,0x75,0x35,0x5e,0x20,0x29,0x20,0x49,0x34,0x2f,0x2f,0xa9,0xee,0xe3,0x71,0x5c,0x92,0xfc,0x0e,0xa2,0x46,0x59,0x47,0x0e,0x02,0x96,0xe5,0x7a,0x76,0x20,0x8d, - 0x04,0x20,0xcc,0xed,0x1c,0x29,0x67,0x13,0x4a,0xe2,0x09,0x5c,0x83,0x67,0x3d,0x01,0x13,0x72,0x16,0x89,0xe8,0x4c,0x64,0x74,0x62,0x62,0x0e,0xf0,0x92,0x2e,0x36,0xd1,0xfa,0x56,0x20,0x8d, - 0x04,0x20,0xcd,0x36,0x45,0x1f,0x75,0x9c,0x12,0x56,0xde,0x09,0x82,0xd8,0xd8,0x6d,0x21,0x82,0xcd,0xac,0xd1,0x9c,0x21,0xcc,0x88,0xe7,0xa2,0x31,0xac,0x4d,0x4c,0xe9,0x61,0x95,0x20,0x8d, - 0x04,0x20,0xcd,0x37,0x83,0xfd,0x95,0x85,0xb7,0xcd,0x13,0xf0,0x9f,0x40,0xcb,0x4e,0xc4,0xd0,0x66,0x9a,0x05,0x1e,0x9f,0xfa,0xaf,0xd8,0xc2,0x7c,0xb0,0xe4,0x0a,0x4d,0x79,0x82,0x20,0x8d, - 0x04,0x20,0xcd,0x3f,0xe2,0x08,0x20,0x3e,0x05,0xe7,0x15,0x28,0x45,0x26,0xd0,0x79,0x98,0xbb,0x0a,0x31,0x4a,0x87,0x14,0x4f,0x33,0x3d,0x05,0x0d,0xb7,0x52,0xbb,0xed,0x48,0xf8,0x20,0x8d, - 0x04,0x20,0xcd,0x00,0xe9,0xd2,0x75,0xd3,0x4c,0x12,0xf5,0xd3,0xea,0xab,0x9f,0xf6,0x84,0x38,0x4f,0xd2,0x69,0x3f,0xd7,0x8a,0x65,0x9e,0x16,0xfb,0x98,0xad,0x87,0xf7,0x68,0x01,0x20,0x8d, - 0x04,0x20,0xcd,0x02,0xc4,0x66,0x6c,0x69,0x71,0xaa,0xc1,0xd6,0x83,0x1f,0x8c,0x86,0x13,0x2e,0x81,0xcd,0xa4,0xc0,0xcc,0x89,0x7f,0x65,0x77,0x72,0x8e,0x56,0x37,0x2c,0x46,0xe2,0x20,0x8d, - 0x04,0x20,0xcd,0x05,0xf9,0x38,0x37,0xf4,0xe6,0x9f,0xae,0x56,0x56,0xf5,0x10,0x12,0xe0,0x91,0x43,0x71,0x75,0x43,0xf0,0x36,0xbf,0x4c,0x7b,0xec,0xa3,0x0c,0xa9,0x3b,0x23,0x25,0x20,0x8d, - 0x04,0x20,0xcd,0x1a,0xc6,0xc7,0xe2,0xcc,0x6f,0x52,0xa4,0xd7,0x9d,0x55,0x65,0x7b,0x28,0x9a,0x3a,0xa9,0x2a,0xfc,0x2a,0x36,0x9e,0x0f,0x20,0x39,0xc6,0xb4,0x96,0x50,0x9e,0x7f,0x20,0x8d, - 0x04,0x20,0xcd,0x1c,0xc5,0xed,0x9b,0x48,0xd4,0xe3,0xf4,0x23,0x8d,0x8a,0x41,0x34,0x96,0xe9,0x78,0xc8,0xac,0x56,0x3b,0x0e,0xa6,0xf3,0xbe,0x84,0x81,0xfd,0x09,0xfa,0xff,0x1e,0x20,0x8d, - 0x04,0x20,0xcd,0x27,0x81,0xfd,0xf9,0x56,0x08,0x91,0x4e,0x28,0xc4,0x74,0xb8,0x2e,0x24,0xbe,0xc1,0x15,0x51,0xad,0x9c,0x86,0x97,0x6d,0x46,0xb6,0xa0,0x9e,0xd3,0x65,0x4f,0x69,0x20,0x8d, - 0x04,0x20,0xcd,0x32,0x35,0xfd,0xad,0x49,0xf1,0xe4,0x37,0x10,0xb4,0x85,0xd4,0x7c,0xa0,0x26,0x9b,0x12,0x19,0x9f,0xb3,0x71,0x19,0xb9,0x60,0xb9,0xd1,0xe7,0x22,0x85,0xc0,0xbe,0x20,0x8d, - 0x04,0x20,0xcd,0x74,0xda,0x48,0x97,0x08,0xa2,0xd1,0x06,0x93,0x58,0x9f,0x12,0x56,0xc7,0xa8,0x67,0x05,0xe2,0x28,0xdc,0xa6,0x9b,0x30,0xcb,0xd6,0xef,0xf2,0x8e,0x0a,0x60,0x09,0x20,0x8d, - 0x04,0x20,0xcd,0x7d,0xb3,0x91,0xc0,0xfa,0x65,0x3b,0x1e,0x1b,0xb1,0xb4,0xd4,0x05,0x0f,0xdf,0x83,0x6e,0x20,0x43,0xfa,0x5e,0x71,0x0b,0x1b,0x5a,0x36,0xda,0x4f,0xe6,0x7e,0x8c,0x20,0x8d, - 0x04,0x20,0xcd,0x42,0x7c,0x0a,0x83,0x79,0x97,0x11,0xa3,0x72,0x57,0xf0,0x8b,0x93,0xdc,0x22,0x9b,0x81,0xdb,0x39,0x44,0x85,0xc6,0xfa,0xec,0xbd,0x8e,0x1f,0xdf,0x18,0xc9,0x2a,0x20,0x8d, - 0x04,0x20,0xcd,0x4d,0x49,0xdb,0x54,0xfc,0xe9,0xc1,0xdf,0xf3,0xd7,0x56,0x43,0x1c,0x6f,0xf2,0x7a,0xde,0x72,0x9c,0xf7,0x18,0xc7,0x61,0xe0,0x2d,0xa5,0x30,0x61,0xfe,0x31,0x80,0x20,0x8d, - 0x04,0x20,0xcd,0x52,0xde,0xa6,0x42,0x6f,0xd2,0xd1,0x42,0x52,0xe7,0x28,0x7e,0xec,0xd5,0x47,0x83,0xc2,0x60,0x49,0x83,0xf9,0xa9,0xf9,0xf5,0xe7,0x83,0x28,0xfc,0xc8,0x69,0x3a,0x20,0x8d, - 0x04,0x20,0xcd,0x59,0x72,0xe3,0xb9,0xfb,0x6e,0x45,0x34,0xcb,0xab,0xc2,0x7f,0xc6,0xa4,0x73,0xde,0xac,0x56,0xb9,0xab,0x5f,0x6b,0xb9,0xba,0x51,0x94,0x47,0x80,0xad,0x87,0x10,0x20,0x8d, - 0x04,0x20,0xcd,0x5e,0x26,0x7c,0x84,0x61,0x6a,0xb5,0x2c,0xd0,0x43,0xb6,0x53,0x64,0x56,0x06,0xab,0x45,0x1b,0x6d,0xf8,0x80,0xea,0xf5,0x13,0x42,0xb7,0xe5,0x0e,0x80,0xf3,0x2a,0x20,0x8d, - 0x04,0x20,0xcd,0x72,0x88,0x95,0x5b,0x3f,0x0e,0xae,0xe9,0x3c,0xa6,0xbb,0xcc,0x69,0xaf,0xf5,0x49,0xab,0xce,0x63,0xd3,0x68,0x64,0x08,0x52,0x85,0xb4,0xb4,0x22,0xdf,0x04,0x18,0x20,0x8d, - 0x04,0x20,0xcd,0xb8,0xe5,0x99,0xf7,0xa2,0x53,0xe4,0x60,0x6a,0x61,0xe9,0x70,0xdf,0x7f,0x0f,0x75,0x2c,0x2f,0xa1,0x67,0x88,0xc0,0xe0,0x81,0x24,0xb1,0x22,0x3f,0x48,0x33,0x5f,0x20,0x8d, - 0x04,0x20,0xcd,0x82,0xd7,0x54,0xcf,0x77,0x21,0x74,0x0f,0x0b,0xa0,0x5e,0x38,0x9e,0xec,0xdf,0x27,0xad,0xa2,0xc0,0x6a,0x01,0x62,0xc8,0xe8,0x84,0x50,0xb9,0xce,0xd0,0x4b,0x5a,0x20,0x8d, - 0x04,0x20,0xcd,0x83,0x03,0x1f,0xab,0x27,0xf6,0x0a,0x44,0xac,0x0d,0x8b,0xd4,0x55,0x21,0xfe,0x04,0x46,0x59,0xa9,0x44,0x34,0x96,0xc3,0x92,0x86,0x7c,0x47,0xaf,0xf1,0x1c,0xc7,0x20,0x8d, - 0x04,0x20,0xcd,0x88,0x8c,0x73,0x8d,0x34,0x54,0x5c,0x9d,0xa0,0x74,0x1d,0x5d,0x95,0xcf,0xb4,0x07,0xba,0x1e,0xd2,0x23,0x79,0x5f,0x48,0x78,0x2e,0xf0,0xd6,0x1d,0x6f,0xa2,0xe9,0x20,0x8d, - 0x04,0x20,0xcd,0x8d,0xa1,0x56,0xaa,0x66,0xff,0x4d,0x1d,0x02,0xb0,0x52,0x09,0x43,0x23,0x80,0xce,0x20,0xae,0xd5,0x9e,0x65,0x45,0xb3,0x3c,0x53,0xc2,0x40,0x97,0xff,0x49,0xc8,0x20,0x8d, - 0x04,0x20,0xcd,0xa2,0xfd,0x28,0x3a,0x13,0xaa,0x18,0xc7,0x77,0x1e,0x74,0xfb,0xc7,0xc6,0x37,0x9a,0x36,0x9d,0xe2,0x31,0x6a,0x95,0x26,0x3c,0xd9,0x28,0x36,0xaf,0xa0,0x95,0xae,0x20,0x8d, - 0x04,0x20,0xcd,0xa4,0x07,0x96,0x32,0xbe,0x64,0xe6,0x49,0xd3,0xc7,0xbb,0xa4,0xa0,0xb6,0x42,0x3b,0xe9,0x4f,0xc5,0x37,0xc3,0x2d,0x0a,0x31,0xf0,0x5d,0x52,0x1f,0xae,0xf3,0x5e,0x20,0x8d, - 0x04,0x20,0xcd,0xa6,0x95,0x5f,0xa1,0x5e,0x65,0xc4,0x78,0x9f,0x3d,0x8a,0x42,0x28,0x56,0xa1,0x46,0xbd,0x2c,0x20,0xe2,0x7d,0xdd,0x73,0x73,0xaa,0x80,0x91,0x92,0x3d,0x43,0x86,0x20,0x8d, - 0x04,0x20,0xcd,0xa9,0xb2,0x3f,0x79,0x82,0x91,0xed,0x07,0xeb,0x1a,0x43,0x2b,0xab,0x83,0x67,0x22,0xb7,0xbd,0x57,0x7e,0x73,0x02,0xda,0x45,0xaa,0x9c,0x83,0xdd,0x73,0x66,0xf1,0x20,0x8d, - 0x04,0x20,0xcd,0xac,0xf0,0x95,0xf8,0x64,0xb2,0x26,0x2a,0xcb,0x2b,0xb3,0x95,0xeb,0xcc,0xf7,0xa3,0xe6,0xfe,0xf9,0x33,0x6d,0xe0,0xcb,0x8d,0x2e,0xdf,0x87,0xc0,0xfb,0xf6,0x01,0x20,0x8d, - 0x04,0x20,0xcd,0xf7,0xf2,0xdb,0xa1,0xe1,0x01,0x39,0xec,0x64,0x50,0x08,0x5a,0x37,0x6b,0x6f,0xbe,0x03,0x3e,0x7f,0x74,0x1c,0x12,0x00,0x55,0xc4,0x38,0xa2,0x52,0x21,0x4e,0xbc,0x20,0x8d, - 0x04,0x20,0xcd,0xc1,0x44,0x8d,0xf2,0xe8,0x89,0xeb,0x55,0x5e,0xc2,0x82,0x58,0x53,0x06,0x98,0x56,0x8e,0x10,0x55,0x7b,0x94,0x9f,0xbb,0x05,0xba,0x60,0x84,0x39,0xad,0xdd,0x36,0x20,0x8d, - 0x04,0x20,0xcd,0xc3,0x0d,0xab,0xe7,0xb4,0xac,0xed,0x17,0x7f,0xe0,0x0f,0x26,0x2c,0xca,0x78,0xd3,0xf4,0xd3,0xef,0xc6,0x0d,0x48,0xaa,0xb9,0x80,0x1c,0x7d,0xf6,0xac,0xba,0xc8,0x20,0x8d, - 0x04,0x20,0xcd,0xc5,0xa0,0xe6,0x90,0x1a,0x90,0xf7,0xde,0x67,0xb8,0x4d,0xf6,0xfc,0x9b,0x5e,0x5a,0x11,0x36,0xff,0xce,0x11,0x35,0x9e,0xd5,0x4d,0x24,0x1b,0x47,0xb5,0xde,0x9d,0x20,0x8d, - 0x04,0x20,0xcd,0xc4,0xdc,0xad,0xda,0x22,0x0c,0x54,0x1b,0xde,0xad,0xf1,0x7e,0x6f,0x2d,0x67,0xbc,0x0e,0xa3,0x88,0x25,0x10,0xe9,0x60,0x46,0x18,0xcd,0x91,0x94,0xbc,0xa9,0xdb,0x20,0x8d, - 0x04,0x20,0xcd,0xd5,0xc0,0xc2,0x24,0x19,0x37,0x36,0xac,0x3f,0xc3,0x12,0xb9,0x3b,0x14,0x78,0xb7,0xf8,0xea,0xb0,0x27,0xb9,0xf7,0x4e,0x3b,0x68,0xb3,0x06,0x18,0xa4,0x76,0x11,0x20,0x8d, - 0x04,0x20,0xcd,0xe0,0x37,0xd3,0x86,0x65,0x5b,0xda,0xe7,0x4a,0x1a,0xc7,0xe1,0x6a,0x56,0x80,0xf2,0xa6,0xd8,0xfa,0x16,0x6d,0x2b,0x77,0xb5,0xbe,0xf5,0xb7,0x46,0xb3,0x57,0x81,0x20,0x8d, - 0x04,0x20,0xcd,0xe0,0x4f,0x10,0xb0,0xe3,0x87,0x91,0xe9,0x95,0xc1,0x0c,0xb8,0x4d,0xda,0x11,0x4c,0x60,0x19,0xc8,0x11,0x85,0x55,0xd4,0x40,0xe3,0x2f,0x81,0x1b,0x9f,0x49,0x11,0x20,0x8d, - 0x04,0x20,0xcd,0xf2,0x5c,0xef,0x3c,0x68,0x43,0xfa,0x6d,0x05,0x15,0x74,0xfe,0xdc,0x8d,0xcb,0xc2,0xdc,0xd2,0x84,0xc9,0x16,0x10,0xa4,0x45,0x8b,0x28,0xfb,0xce,0x18,0x71,0xff,0x20,0x8d, - 0x04,0x20,0xcd,0xf3,0x03,0x96,0xc8,0xd9,0x86,0x72,0x52,0xec,0xc8,0x0c,0xfe,0x02,0xdc,0x02,0xa5,0xe1,0x21,0x1a,0x5a,0xd6,0x90,0x3c,0x55,0x81,0xe7,0x08,0xdd,0x6a,0x95,0xc6,0x20,0x8d, - 0x04,0x20,0xce,0x38,0x92,0x48,0xed,0x7d,0xf6,0x8d,0xd9,0x22,0x84,0x43,0xaf,0xc0,0x44,0x07,0x20,0x49,0xbc,0x99,0xf7,0x6c,0xf7,0x08,0x13,0xec,0xa0,0xd1,0x67,0x5c,0xb9,0x1d,0x20,0x8d, - 0x04,0x20,0xce,0x04,0x23,0x57,0x2e,0x51,0x1e,0xe6,0x93,0x7e,0xa2,0xe9,0xfe,0x2f,0xbc,0x00,0xf8,0x39,0xc2,0xbf,0x06,0x82,0x9c,0x8a,0xae,0x7a,0x7d,0x13,0x76,0xe7,0x08,0xbe,0x20,0x8d, - 0x04,0x20,0xce,0x07,0x94,0x38,0xe0,0x08,0x29,0x6c,0x04,0xe1,0x82,0x88,0x66,0xf0,0x7d,0x8f,0x35,0xdf,0x85,0x85,0x02,0x1b,0xbf,0x14,0x13,0x15,0xc6,0x14,0xe9,0xb6,0xee,0x5c,0x20,0x8d, - 0x04,0x20,0xce,0x09,0x32,0xa8,0x0d,0xba,0x04,0x57,0xfa,0x73,0xec,0xc8,0x65,0x5d,0x6a,0x76,0x7b,0x15,0xe9,0x1b,0xcc,0x85,0xe3,0xe3,0x10,0x46,0x40,0x7c,0x58,0x2a,0x99,0x32,0x20,0x8d, - 0x04,0x20,0xce,0x12,0x57,0x51,0x1b,0x3c,0x5f,0x2b,0x6c,0xae,0xe3,0xad,0x78,0xe6,0x62,0x59,0x4b,0x03,0xc7,0x5e,0xb0,0xc8,0x34,0x66,0xb9,0xed,0xea,0xb3,0x52,0x26,0x45,0xd1,0x20,0x8d, - 0x04,0x20,0xce,0x15,0x4e,0x05,0x5e,0x78,0xd0,0x55,0x83,0x5e,0x3e,0x18,0xf4,0x1b,0x13,0x5d,0xa5,0x7e,0x1e,0x60,0x48,0x9b,0xcd,0x9c,0xee,0x08,0xc3,0x1a,0xf2,0x65,0x72,0x6b,0x20,0x8d, - 0x04,0x20,0xce,0x17,0xc5,0x14,0x89,0x96,0xe7,0xca,0x90,0xb2,0xad,0x21,0x18,0x39,0xe1,0x75,0xe2,0xcc,0xce,0x94,0x6f,0xb4,0x94,0x09,0x5c,0xa1,0xf7,0x67,0xd3,0x8c,0xb7,0xc6,0x20,0x8d, - 0x04,0x20,0xce,0x1e,0x75,0x35,0x71,0xe3,0x8d,0x15,0x35,0x3d,0x9f,0xb9,0x0c,0x03,0x5c,0xf2,0x86,0x00,0x48,0xc8,0x8b,0x78,0x82,0x44,0x55,0x24,0x8c,0x68,0x3d,0x79,0xcd,0xe4,0x20,0x8d, - 0x04,0x20,0xce,0x22,0xe1,0xd1,0x91,0x35,0x4c,0xf4,0x34,0xf8,0x30,0x51,0xd6,0x39,0x6f,0x09,0xd7,0xe6,0x8c,0xb2,0xda,0xed,0x39,0xf7,0xaf,0xa3,0x07,0xeb,0x63,0xaa,0xfb,0x43,0x20,0x8d, - 0x04,0x20,0xce,0x2a,0x6a,0x31,0x5d,0x78,0x80,0xd3,0xf3,0x2a,0xde,0x7f,0xa3,0x2c,0x85,0xb9,0x82,0x3e,0x0d,0xf8,0x3c,0x83,0x9a,0xc1,0x72,0x7e,0x8d,0x27,0x82,0xdb,0xfa,0xe2,0x20,0x8d, - 0x04,0x20,0xce,0x30,0x42,0xaf,0xb4,0x6b,0x6d,0xf5,0xb6,0x29,0x59,0x8b,0x8a,0xb7,0x13,0xb7,0x11,0x8e,0x37,0x82,0xc7,0x42,0x19,0x69,0xb4,0x1a,0x4f,0xfb,0x3f,0xef,0x95,0x48,0x20,0x8d, - 0x04,0x20,0xce,0x5a,0xd3,0x42,0xc2,0x7f,0x8d,0xde,0xd9,0x49,0x37,0x75,0x1c,0x91,0xc6,0x56,0xca,0x21,0xbd,0xcf,0xc2,0xf7,0x97,0xc4,0xfa,0x2e,0x75,0xef,0x37,0x0a,0xaf,0x25,0x20,0x8d, - 0x04,0x20,0xce,0x5b,0x31,0x95,0xe2,0x0e,0xe4,0xf2,0xf5,0xe1,0xd9,0xb4,0x61,0x66,0xda,0x6a,0x58,0x7b,0x59,0x52,0x35,0xe7,0xb9,0xd8,0x39,0x49,0xc2,0x04,0x49,0x07,0x37,0xcf,0x20,0x8d, - 0x04,0x20,0xce,0x64,0x8f,0x86,0x34,0x2d,0xb0,0xb0,0xf7,0x56,0xd8,0x44,0x18,0x55,0xfd,0x4d,0xfd,0x58,0xa0,0x27,0xf1,0x88,0x88,0x17,0x1d,0x49,0xee,0xf4,0x1e,0x09,0x48,0x1d,0x20,0x8d, - 0x04,0x20,0xce,0x66,0x7c,0xfb,0x9c,0x38,0xd3,0x76,0xec,0x7d,0xe5,0xe2,0x52,0x7e,0x4d,0x6d,0x30,0x79,0x5f,0x42,0x35,0x31,0xc5,0x40,0x3e,0x1b,0xc5,0xda,0x7c,0x14,0x6f,0x56,0x20,0x8d, - 0x04,0x20,0xce,0x68,0x87,0xa5,0xc6,0x11,0x6b,0x2f,0xd3,0x05,0x39,0x4c,0x49,0x10,0xee,0x6f,0xaa,0x82,0x18,0xc0,0xdc,0x85,0xe1,0x7b,0x5e,0xeb,0x75,0xbe,0xbe,0x0c,0x55,0xb1,0x20,0x8d, - 0x04,0x20,0xce,0x68,0xbd,0x5e,0xb8,0x3c,0x2a,0x04,0xb4,0x7e,0xc9,0x65,0xa1,0xe5,0x69,0x73,0xdf,0x7e,0xae,0x4f,0xd5,0xe7,0xc8,0x00,0x7f,0xd7,0x7c,0xa7,0xde,0x35,0xdd,0xb3,0x20,0x8d, - 0x04,0x20,0xce,0x6f,0xc8,0xeb,0x11,0x55,0xe8,0xbd,0x28,0xda,0x72,0x5c,0x44,0x26,0xc2,0x26,0xe4,0xa5,0xaf,0x96,0x0a,0x94,0x9b,0x76,0xef,0x8c,0xa6,0xdd,0x3b,0x57,0xb7,0x9b,0x20,0x8d, - 0x04,0x20,0xce,0x70,0xfd,0x6a,0xfe,0x8e,0x33,0x84,0x37,0x9b,0x7a,0xe6,0xaa,0x3f,0xc9,0x52,0x3b,0x86,0x85,0xc7,0xf0,0xac,0xfa,0x0a,0x42,0xbf,0x41,0xb6,0x0f,0x53,0x73,0xa0,0x20,0x8d, - 0x04,0x20,0xce,0x73,0x9c,0xe7,0x39,0xe8,0x65,0xa8,0x35,0xc8,0x4d,0xd6,0x7b,0x8f,0x68,0x0d,0xd0,0xf0,0x24,0x92,0x33,0xe3,0x05,0xc6,0xf3,0x79,0x43,0x83,0x5b,0x99,0x10,0x0b,0x20,0x8d, - 0x06,0x10,0xfc,0x32,0x17,0xea,0xe4,0x15,0xc3,0xbf,0x98,0x08,0x14,0x9d,0xb5,0xa2,0xc9,0xaa,0x20,0x8d, - 0x06,0x10,0xfc,0xc7,0xbe,0x49,0xcc,0xd1,0xdc,0x91,0x31,0x25,0xf0,0xda,0x45,0x7d,0x08,0xce,0x20,0x8d, - 0x06,0x10,0xfc,0xdc,0x73,0xae,0xb1,0xa9,0x1b,0xf8,0xd4,0xc2,0x08,0x11,0xa4,0xc7,0xc3,0x4e,0x20,0x8d, + 0x04,0x20,0xcd,0xfb,0x39,0x81,0x98,0xab,0xb9,0x5c,0xee,0xfe,0xf7,0x89,0x00,0x13,0x3b,0xd7,0xc3,0x4c,0x7e,0x7a,0x65,0xd7,0xe9,0x95,0x15,0x08,0xb9,0xe1,0x0c,0xf1,0x9a,0xa3,0x20,0x8d, }; static const uint8_t chainparams_seed_test[] = { - 0x05,0x20,0xd6,0x21,0xcb,0x8a,0xd9,0xa8,0x74,0xa9,0xe0,0x48,0xea,0xde,0xc0,0xea,0x1b,0x6a,0xfd,0x08,0x62,0xc1,0xfb,0x62,0x5f,0x15,0x42,0x99,0xce,0x0f,0xaf,0x73,0x59,0x35,0x00,0x00, - 0x05,0x20,0xe1,0xbb,0x4a,0x85,0x55,0x47,0x4b,0x5c,0x0d,0x13,0x22,0xab,0x90,0x25,0x63,0x9e,0x4d,0x48,0xba,0x30,0x4d,0x1f,0x4b,0x4d,0x98,0x64,0x52,0xb7,0x43,0xc2,0x4b,0x3b,0x00,0x00, - 0x05,0x20,0x2e,0xed,0xf9,0x38,0x8f,0x96,0x3e,0x98,0x58,0xbf,0x1a,0xdd,0xc8,0xbb,0x50,0x56,0x00,0xf3,0x69,0x71,0x0e,0x86,0xa5,0x56,0xc5,0xb5,0x30,0xc3,0x02,0x15,0x5a,0x60,0x00,0x00, - 0x05,0x20,0x6c,0x7e,0xd7,0x65,0x61,0xef,0x2f,0x5d,0xbb,0x26,0xe2,0xa5,0x51,0x47,0x6e,0x2e,0x4b,0x62,0x92,0x83,0xd3,0x7f,0x74,0x27,0x16,0xac,0xf5,0xa4,0x5f,0x20,0x5f,0xe0,0x00,0x00, - 0x05,0x20,0x77,0x93,0xb0,0xef,0x61,0xae,0xbd,0x59,0x9d,0xd0,0xca,0x71,0xb3,0xfc,0x1b,0x84,0xa9,0x00,0xcc,0x24,0xdd,0x16,0x04,0xb1,0x39,0x92,0xf9,0xba,0x82,0x18,0x41,0x31,0x00,0x00, - 0x05,0x20,0x70,0xa0,0x87,0x84,0x37,0xbf,0x1e,0x07,0x3c,0xca,0x50,0x5a,0x9d,0x6f,0x88,0x27,0xdc,0xfc,0xc6,0x62,0x07,0x4d,0x34,0x5a,0x3e,0x70,0xc1,0xb3,0xef,0x51,0xc9,0xa4,0x00,0x00, - 0x05,0x20,0x8e,0xb2,0x37,0xa8,0x52,0x59,0x7e,0x4e,0x4f,0x45,0x61,0x97,0x4e,0x76,0xe7,0x2d,0xbb,0x93,0x51,0xf3,0x38,0xcf,0xd7,0x88,0x96,0x1b,0xbc,0x90,0x26,0x8c,0xa9,0x06,0x00,0x00, - 0x05,0x20,0xb9,0x85,0x34,0xf2,0x44,0x76,0xdc,0x59,0x4d,0x18,0x63,0xb0,0x4a,0x66,0x1f,0xe0,0x6a,0x31,0xc4,0x31,0xf2,0x66,0x80,0x78,0x91,0x70,0xd6,0x5e,0xd4,0x1b,0x16,0x7a,0x00,0x00, - 0x05,0x20,0xc7,0x49,0xe0,0x43,0x3c,0x4a,0x92,0x97,0x11,0x0f,0x75,0xed,0x48,0xe4,0x5a,0x4c,0x4b,0x5f,0x21,0x75,0x28,0x47,0x06,0x26,0x0a,0xef,0xf8,0xc0,0x04,0x1d,0xa0,0x22,0x00,0x00, - 0x05,0x20,0xc1,0x36,0x04,0xd7,0x53,0x33,0xe1,0xf4,0xd6,0xb9,0xcb,0x7b,0x6b,0x86,0x6c,0x1e,0xe7,0x72,0x57,0x60,0xbc,0x86,0xb0,0x74,0x2a,0x7b,0x82,0x44,0x58,0x42,0xc2,0x53,0x00,0x00, + 0x06,0x10,0xfc,0xcb,0x02,0x48,0x11,0xa6,0x10,0x42,0x0b,0xca,0x12,0x18,0xf7,0xce,0x7d,0x3d,0x47,0x9d, + 0x01,0x04,0x02,0x57,0x48,0xeb,0x47,0x9d, + 0x01,0x04,0x03,0xfd,0xa3,0x0e,0x47,0x9d, + 0x01,0x04,0x05,0xb6,0x04,0x6a,0x47,0x9d, + 0x01,0x04,0x05,0xbc,0x77,0xc4,0x47,0x9d, + 0x01,0x04,0x05,0xbd,0xaf,0x5c,0x47,0x9d, + 0x01,0x04,0x05,0xfc,0x15,0xe8,0x47,0x9d, + 0x01,0x04,0x05,0xff,0x61,0x5b,0x47,0x9d, + 0x01,0x04,0x05,0xff,0x63,0x82,0x47,0x9d, + 0x01,0x04,0x08,0xde,0xe4,0xd9,0x47,0x9d, + 0x01,0x04,0x12,0x8f,0x6c,0xd5,0x47,0x9d, + 0x01,0x04,0x17,0x5d,0x59,0xc7,0x47,0x9d, + 0x01,0x04,0x17,0x5e,0x60,0x86,0x47,0x9d, + 0x01,0x04,0x17,0x89,0x39,0x64,0x47,0x9d, + 0x01,0x04,0x1f,0xdc,0x63,0x41,0x47,0x9d, + 0x01,0x04,0x23,0xc0,0xbf,0xe5,0x47,0x9d, + 0x01,0x04,0x23,0xc8,0xc9,0x4f,0x47,0x9d, + 0x01,0x04,0x23,0xe9,0x98,0xdb,0x47,0x9d, + 0x01,0x04,0x25,0x1b,0x3a,0x86,0x47,0x9d, + 0x01,0x04,0x25,0x1b,0x74,0x57,0x47,0x9d, + 0x01,0x04,0x28,0x76,0xe4,0xbb,0x47,0x9d, + 0x01,0x04,0x2b,0xf7,0xb8,0x32,0x47,0x9d, + 0x01,0x04,0x2d,0x4d,0x19,0x0e,0x47,0x9d, + 0x01,0x04,0x2d,0x81,0xb6,0x3b,0x47,0x9d, + 0x01,0x04,0x2f,0xfe,0x7f,0xfc,0x47,0x9d, + 0x01,0x04,0x33,0x4d,0x2a,0xea,0x47,0x9d, + 0x01,0x04,0x33,0x4f,0x52,0x4b,0x47,0x9d, + 0x01,0x04,0x33,0xfa,0x4b,0x30,0x47,0x9d, + 0x01,0x04,0x34,0xae,0xbb,0x11,0x47,0x9d, + 0x01,0x04,0x3e,0x48,0x1b,0xd4,0x47,0x9d, + 0x01,0x04,0x3e,0xa8,0x41,0x2a,0x47,0x9d, + 0x01,0x04,0x3e,0xd2,0xcf,0x3f,0x47,0x9d, + 0x01,0x04,0x3e,0xd2,0xde,0x49,0x47,0x9d, + 0x01,0x04,0x41,0x6c,0x27,0xab,0x47,0x9d, + 0x01,0x04,0x42,0x55,0x91,0x86,0x47,0x9d, + 0x01,0x04,0x42,0x87,0x1d,0xf3,0x47,0x9d, + 0x01,0x04,0x42,0xb7,0x00,0xcd,0x47,0x9d, + 0x01,0x04,0x43,0x04,0x52,0x09,0x47,0x9d, + 0x01,0x04,0x44,0xc5,0xcb,0xb5,0x47,0x9d, + 0x01,0x04,0x45,0x3b,0x12,0x17,0x47,0x9d, + 0x01,0x04,0x45,0x3d,0x20,0xf2,0x47,0x9d, + 0x01,0x04,0x45,0xc5,0xb9,0x6a,0x47,0x9d, + 0x01,0x04,0x47,0x08,0x1d,0x0c,0x47,0x9d, + 0x01,0x04,0x47,0x0d,0x5c,0x3e,0x47,0x9d, + 0x01,0x04,0x47,0xab,0x7b,0xa1,0x47,0x9d, + 0x01,0x04,0x48,0x2e,0x81,0x32,0x47,0x9d, + 0x01,0x04,0x49,0x16,0x09,0xe7,0x47,0x9d, + 0x01,0x04,0x49,0x35,0x2a,0x69,0x47,0x9d, + 0x01,0x04,0x4a,0xd5,0xaf,0x63,0x47,0x9d, + 0x01,0x04,0x4d,0xa3,0xdd,0xab,0x47,0x9d, + 0x01,0x04,0x4f,0xc0,0x27,0x69,0x47,0x9d, + 0x01,0x04,0x50,0x4f,0x04,0xf9,0x47,0x9d, + 0x01,0x04,0x50,0x5d,0xb3,0xfc,0x47,0x9d, + 0x01,0x04,0x50,0xf1,0xc2,0x93,0x47,0x9d, + 0x01,0x04,0x51,0x11,0x66,0x88,0x47,0x9d, + 0x01,0x04,0x53,0xe7,0xf0,0x03,0x47,0x9d, + 0x01,0x04,0x54,0x18,0x4d,0xbf,0x47,0x9d, + 0x01,0x04,0x54,0x9b,0x71,0xb1,0x47,0x9d, + 0x01,0x04,0x54,0xf7,0xa4,0x67,0x47,0x9d, + 0x01,0x04,0x55,0xcb,0x35,0x59,0x47,0x9d, + 0x01,0x04,0x55,0xcb,0x35,0x95,0x47,0x9d, + 0x01,0x04,0x55,0xd0,0x45,0x0c,0x47,0x9d, + 0x01,0x04,0x55,0xd0,0x45,0x0d,0x47,0x9d, + 0x01,0x04,0x58,0x50,0x94,0xd7,0x47,0x9d, + 0x01,0x04,0x59,0x75,0x13,0xbf,0x47,0x9d, + 0x01,0x04,0x59,0x99,0xa1,0x10,0x47,0x9d, + 0x01,0x04,0x59,0x9b,0xef,0x6b,0x47,0x9d, + 0x01,0x04,0x5b,0x7b,0xb6,0xa4,0x47,0x9d, + 0x01,0x04,0x5b,0x94,0x8d,0xd2,0x47,0x9d, + 0x01,0x04,0x65,0x64,0x8b,0xf9,0x47,0x9d, + 0x01,0x04,0x68,0xed,0x83,0x8a,0x47,0x9d, + 0x01,0x04,0x6d,0xe9,0x6d,0x1a,0x47,0x9d, + 0x01,0x04,0x7a,0xd0,0x75,0xc5,0x47,0x9d, + 0x01,0x04,0x7c,0xec,0x10,0x5b,0x47,0x9d, + 0x01,0x04,0x81,0xe2,0xc6,0xd3,0x47,0x9d, + 0x01,0x04,0x81,0xe2,0xc6,0xf6,0x47,0x9d, + 0x01,0x04,0x83,0xbc,0x28,0x2f,0x47,0x9d, + 0x01,0x04,0x84,0xe2,0x3d,0xd7,0x47,0x9d, + 0x01,0x04,0x87,0x54,0x88,0x9d,0x47,0x9d, + 0x01,0x04,0x89,0xb8,0x02,0x7c,0x47,0x9d, + 0x01,0x04,0x8a,0x02,0x64,0x72,0x47,0x9d, + 0x01,0x04,0x8d,0x62,0xdb,0x8e,0x47,0x9d, + 0x01,0x04,0x8d,0x62,0xdb,0xc7,0x47,0x9d, + 0x01,0x04,0x95,0x32,0x65,0x1b,0x47,0x9d, + 0x01,0x04,0x95,0x9a,0xb0,0x2f,0x47,0x9d, + 0x01,0x04,0x98,0x35,0x11,0x35,0x47,0x9d, + 0x01,0x04,0x98,0x35,0x12,0x6d,0x47,0x9d, + 0x01,0x04,0x9e,0xb2,0xe4,0x29,0x47,0x9d, + 0x01,0x04,0xa0,0x50,0x0b,0x42,0x47,0x9d, + 0x01,0x04,0xa2,0x00,0xd0,0x5a,0x47,0x9d, + 0x01,0x04,0xa2,0xf4,0x50,0xda,0x47,0x9d, + 0x01,0x04,0xa4,0x5c,0x8c,0x15,0x47,0x9d, + 0x01,0x04,0xa9,0x9b,0x2d,0xb4,0x47,0x9d, + 0x01,0x04,0xa9,0x9b,0xab,0xfc,0x47,0x9d, + 0x01,0x04,0xac,0xac,0x3e,0x56,0x47,0x9d, + 0x01,0x04,0xaf,0xd1,0xe4,0x8d,0x47,0x9d, + 0x01,0x04,0xb0,0x6c,0xc1,0x61,0x47,0x9d, + 0x01,0x04,0xb2,0x15,0x76,0x52,0x47,0x9d, + 0x01,0x04,0xb2,0x15,0x76,0x60,0x47,0x9d, + 0x01,0x04,0xb2,0x3f,0x57,0xa3,0x47,0x9d, + 0x01,0x04,0xb8,0x4a,0xf0,0x9d,0x47,0x9d, + 0x01,0x04,0xb9,0x1c,0x60,0x10,0x47,0x9d, + 0x01,0x04,0xb9,0x46,0x2b,0xc0,0x47,0x9d, + 0x01,0x04,0xb9,0x6b,0x44,0x87,0x47,0x9d, + 0x01,0x04,0xb9,0x84,0xb1,0x68,0x47,0x9d, + 0x01,0x04,0xb9,0xba,0xd0,0x7c,0x47,0x9d, + 0x01,0x04,0xb9,0xbe,0x18,0x48,0x47,0x9d, + 0x01,0x04,0xb9,0xd1,0xdf,0xc3,0x47,0x9d, + 0x01,0x04,0xb9,0xd2,0x7d,0x21,0x47,0x9d, + 0x01,0x04,0xb9,0xe8,0x46,0xe2,0x47,0x9d, + 0x01,0x04,0xba,0x9a,0xcf,0xe4,0x47,0x9d, + 0x01,0x04,0xbc,0x75,0x84,0x52,0x47,0x9d, + 0x01,0x04,0xbc,0xd5,0x5a,0x95,0x47,0x9d, + 0x01,0x04,0xbc,0xf6,0xa8,0x90,0x47,0x9d, + 0x01,0x04,0xc0,0xc6,0x51,0xf3,0x47,0x9d, + 0x01,0x04,0xc1,0xc6,0x22,0x18,0x47,0x9d, + 0x01,0x04,0xc2,0x5f,0x42,0x81,0x47,0x9d, + 0x01,0x04,0xc2,0x6e,0xa9,0x85,0x47,0x9d, + 0x01,0x04,0xc2,0xe9,0x5b,0x99,0x47,0x9d, + 0x01,0x04,0xc3,0x7b,0xf4,0x79,0x47,0x9d, + 0x01,0x04,0xc3,0xb3,0xe6,0xb4,0x47,0x9d, + 0x01,0x04,0xc6,0x3a,0x66,0x12,0x47,0x9d, + 0x01,0x04,0xcb,0x84,0x5e,0xc4,0x47,0x9d, + 0x01,0x04,0xcd,0xd1,0x77,0x96,0x47,0x9d, + 0x01,0x04,0xce,0xcc,0x68,0x07,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x19,0xf0,0x44,0x00,0x63,0xc7,0x54,0x00,0x04,0xff,0xfe,0xcc,0xfc,0x1e,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x03,0x03,0x2d,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x03,0x03,0x87,0xb9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x06,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x70,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x06,0x02,0x2d,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x07,0x00,0x54,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x08,0x00,0x1d,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x41,0xd0,0x08,0x00,0x3d,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x05,0x04,0xe5,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x07,0x06,0xf2,0x16,0x71,0x5a,0x1c,0x24,0x33,0xb5,0x17,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x07,0x06,0xf2,0x2e,0x58,0xb9,0xff,0xfe,0x18,0xe0,0x93,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x07,0x06,0xf2,0x4d,0xfe,0xd8,0xfe,0x3d,0xc7,0x06,0x3f,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x07,0x06,0xf2,0x6a,0x34,0xc6,0x1d,0x97,0xb1,0xc9,0x8c,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x06,0x38,0xa0,0x00,0x41,0x40,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x47,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x07,0x28,0x10,0x00,0x04,0x02,0x54,0x6e,0x98,0xff,0xfe,0x16,0x68,0xc6,0x47,0x9d, + 0x02,0x10,0x20,0x01,0x0b,0xc8,0x12,0x01,0x04,0x09,0x16,0x18,0x77,0xff,0xfe,0x5f,0x0b,0x12,0x47,0x9d, + 0x02,0x10,0x24,0x01,0xc0,0x80,0x10,0x00,0x4c,0xb2,0x3e,0xec,0xef,0xff,0xfe,0xb9,0x86,0x04,0x47,0x9d, + 0x02,0x10,0x24,0x01,0xd0,0x02,0x39,0x02,0x07,0x00,0x87,0x08,0x37,0xc4,0xe2,0x31,0xd3,0xd8,0x47,0x9d, + 0x02,0x10,0x24,0x02,0x1f,0x00,0x81,0x01,0x07,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x5b,0x4c,0xf3,0x47,0x9d, + 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x9e,0x7f,0x03,0x47,0x9d, + 0x02,0x10,0x26,0x01,0x06,0x03,0x53,0x00,0x83,0xb7,0x00,0x00,0x00,0xff,0xfe,0x00,0x42,0x0a,0x47,0x9d, + 0x02,0x10,0x26,0x04,0x13,0x80,0x45,0x31,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x47,0x9d, + 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x65,0xc0,0x01,0x47,0x9d, + 0x02,0x10,0x26,0x05,0xa1,0x43,0x21,0x62,0x70,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x26,0x07,0x53,0x00,0x02,0x03,0x54,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x26,0x07,0x53,0x00,0x00,0x60,0x85,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x26,0x20,0x00,0x6e,0xa0,0x00,0x00,0x01,0x00,0x43,0x00,0x43,0x00,0x43,0x00,0x43,0x47,0x9d, + 0x02,0x10,0x28,0x04,0x04,0x31,0xe0,0x38,0xcd,0x01,0xaa,0xa1,0x59,0xff,0xfe,0x0d,0x44,0xb8,0x47,0x9d, + 0x02,0x10,0x28,0x06,0x02,0xf0,0x90,0xa0,0x45,0xfe,0xdd,0x25,0xf6,0xdf,0x47,0x41,0x4a,0x3f,0x47,0x9d, + 0x02,0x10,0x2a,0x00,0x12,0x98,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0x42,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x73,0x23,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x90,0x40,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x31,0x1e,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x42,0x4c,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x1a,0x97,0xe8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x1a,0x9a,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x2a,0x2d,0xdd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x30,0x70,0x26,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x30,0x71,0x21,0x9d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x04,0xf9,0x30,0x80,0x35,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9d, + 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x03,0xb3,0x14,0x20,0x7c,0xa0,0x3a,0x9a,0x5c,0xc3,0xb6,0x44,0x47,0x9d, + 0x02,0x10,0x2a,0x02,0x47,0x80,0x00,0x10,0x40,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x2a,0x02,0xc2,0x02,0x21,0x89,0x37,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x20,0x75,0x33,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x2a,0x02,0xc2,0x06,0x21,0x96,0x07,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x2a,0x05,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x9d, + 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x2a,0x00,0x00,0x00,0x00,0x95,0x32,0x65,0x1b,0x47,0x9d, + 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x02,0x22,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x02,0x49,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x04,0x16,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9d, + 0x02,0x10,0x2a,0x05,0xd0,0x1c,0x03,0x92,0xc9,0x00,0x78,0xea,0xba,0x95,0x33,0x4c,0x1d,0x7c,0x47,0x9d, + 0x04,0x20,0xd2,0xe4,0xd1,0x40,0x65,0x5d,0x95,0xaf,0xe8,0x67,0xc0,0xe3,0x72,0xfd,0x0a,0x2e,0x35,0xb7,0xbd,0xac,0x67,0x78,0x36,0xe1,0xb8,0xba,0x30,0xcf,0x2e,0x05,0xdd,0x9d,0x47,0x9d, + 0x04,0x20,0xdf,0x8b,0x65,0x4c,0x4a,0x31,0x81,0x15,0x09,0x61,0x7d,0x34,0xfa,0x32,0x43,0x78,0x95,0xcf,0x00,0xe4,0xf0,0xac,0xf7,0x64,0x7a,0x33,0x3d,0x0f,0xa8,0xc3,0x82,0xd2,0x47,0x9d, + 0x04,0x20,0xdc,0x57,0x12,0xdc,0x09,0xe4,0x9e,0x7c,0x90,0x6e,0xcc,0xb5,0xf8,0x44,0x85,0xa5,0xbd,0x4d,0xd7,0x42,0x85,0x34,0x29,0x86,0x21,0xa9,0xe4,0x2d,0xd9,0xbb,0xe2,0x09,0x47,0x9d, + 0x04,0x20,0xdc,0xc0,0xef,0x59,0xb8,0x1a,0x0f,0x28,0x34,0x69,0xb7,0x5f,0x00,0xa9,0xda,0xec,0x6e,0xad,0x6e,0xc1,0xee,0xcd,0x3c,0x57,0xf5,0x60,0x58,0x2d,0x27,0xf5,0xb7,0xf8,0x47,0x9d, + 0x04,0x20,0xe7,0x24,0x61,0x57,0xa3,0xab,0xde,0xb9,0xef,0x44,0x6a,0xda,0x41,0x8f,0x0b,0xe1,0x87,0xcc,0xee,0x61,0x26,0x57,0xa9,0x08,0x83,0xb0,0x84,0xd1,0xe3,0x31,0x8b,0xfc,0x47,0x9d, + 0x04,0x20,0xe5,0xb6,0x5d,0x32,0xe4,0xe1,0x66,0xe1,0xb8,0x44,0x8b,0x24,0x0c,0xcb,0x70,0x5b,0xdd,0xbf,0xa0,0xca,0x19,0x9a,0x4f,0x28,0x1a,0x7f,0xac,0xd6,0xc4,0xd6,0x7e,0x61,0x47,0x9d, + 0x04,0x20,0xf7,0xd7,0xe5,0xe9,0x5f,0x64,0x02,0xbd,0x06,0x78,0xab,0xba,0x7e,0xad,0x48,0xda,0xae,0x28,0x98,0x34,0x6a,0xd5,0xf0,0xc4,0x4b,0x76,0x00,0xe0,0x16,0x61,0x97,0x58,0x47,0x9d, + 0x04,0x20,0xf3,0x3e,0xa3,0xaa,0x75,0x22,0x18,0x2d,0xf7,0x09,0xa4,0x8c,0x47,0xc5,0xa3,0xb7,0x36,0x68,0xa4,0x97,0x97,0x42,0xf8,0xd2,0xca,0x71,0x82,0x7e,0xad,0xd5,0xaf,0x3e,0x47,0x9d, + 0x04,0x20,0xf4,0x5b,0x07,0xc2,0x02,0x7a,0xd7,0x03,0xa5,0xc0,0xe1,0xad,0x19,0xc3,0xb8,0x47,0x8a,0x31,0x1f,0xd4,0x86,0x40,0xf1,0x90,0x9a,0x34,0x3d,0xf3,0x5c,0xd2,0x5f,0xf7,0x47,0x9d, 0x04,0x20,0xfb,0xcf,0xf6,0x44,0x5a,0xe4,0xc9,0xdf,0xb2,0xaf,0x78,0x12,0x55,0x15,0x3c,0x62,0xbf,0x9a,0x67,0x93,0x25,0x15,0x86,0x4f,0x76,0x33,0xc6,0xfb,0x7a,0xaf,0x68,0xc8,0x47,0x9d, + 0x04,0x20,0xfb,0xdd,0x00,0x25,0x7e,0x95,0x73,0xca,0xc7,0x60,0x82,0x3f,0x51,0xcc,0x11,0xd4,0xfb,0xe1,0x44,0x31,0x9a,0x7d,0x84,0x7f,0xb8,0x1c,0x67,0xb4,0x18,0xf8,0xbf,0xe1,0x47,0x9d, + 0x04,0x20,0xfe,0x57,0x08,0xa0,0xe1,0xe8,0xdd,0xd2,0x04,0x2c,0x4d,0x8d,0x27,0xdd,0x06,0x81,0x46,0xc5,0x16,0x4b,0x54,0x26,0x6d,0x34,0xc3,0x17,0xb0,0xf9,0x51,0xb9,0x0f,0x10,0x47,0x9d, + 0x04,0x20,0x00,0xd2,0xd9,0x5d,0x15,0x5c,0x83,0xd6,0x70,0x9c,0x09,0x66,0x7a,0xd4,0x42,0x49,0x6b,0xfc,0xa9,0xf8,0x4e,0x08,0x1a,0x82,0x6b,0x3e,0x21,0x81,0x61,0x43,0xfa,0x02,0x47,0x9d, + 0x04,0x20,0x00,0xe5,0x30,0x05,0x39,0xf9,0x05,0xac,0x6d,0x33,0xe5,0xb4,0x3a,0xd1,0x8c,0x75,0xb3,0x5f,0x9b,0xcc,0xd1,0x76,0xa0,0x24,0x84,0x49,0x4b,0x40,0x67,0xee,0x4d,0x93,0x47,0x9d, + 0x04,0x20,0x01,0x25,0x8f,0x4c,0xb4,0x28,0x06,0xaa,0x4f,0xc5,0x5d,0x34,0x19,0x40,0xcd,0xb6,0xb9,0xad,0x52,0x3a,0xc3,0x52,0x05,0x9a,0x97,0x5e,0x69,0x9a,0x2a,0x66,0xde,0x48,0x47,0x9d, + 0x04,0x20,0x02,0x16,0x80,0xee,0x0a,0xe0,0x62,0x7e,0x67,0x4d,0xab,0x18,0x01,0xb9,0x1e,0x30,0x65,0x6f,0x95,0x07,0x2d,0xe7,0x1f,0xc5,0xac,0xe6,0x7a,0x3f,0x40,0x52,0x7c,0x7e,0x47,0x9d, + 0x04,0x20,0x06,0x2f,0xbe,0xc7,0x4c,0x3d,0xb0,0x31,0x67,0x2e,0x85,0x3e,0x1f,0x0d,0x7b,0x95,0x1f,0xc7,0x1e,0x7f,0xe4,0x8c,0xd5,0xc5,0x2a,0xbe,0x03,0x93,0xe8,0xec,0x2b,0x40,0x47,0x9d, + 0x04,0x20,0x09,0x15,0xee,0xe9,0x65,0x97,0xd8,0x92,0x73,0xd9,0x05,0x0e,0x5b,0xcc,0x67,0xd6,0x5c,0x72,0x69,0x2f,0x0c,0x98,0xb3,0xd1,0x74,0x95,0x32,0x07,0x6b,0xf4,0xb3,0xec,0x47,0x9d, 0x04,0x20,0x0a,0xb2,0xef,0xb1,0xf7,0xa0,0x23,0xf8,0x9e,0x41,0x45,0x86,0x0b,0xc0,0x58,0x62,0x2e,0x08,0x88,0x23,0x60,0x77,0x21,0x82,0x13,0xaf,0xb0,0x1d,0x4a,0xb0,0x9c,0xf3,0x47,0x9d, + 0x04,0x20,0x0d,0xb1,0x41,0xd5,0x7b,0x41,0x77,0x1f,0x92,0x44,0xd0,0x81,0x86,0x15,0xa1,0xbc,0x33,0x31,0x6d,0x86,0x8e,0x91,0xd3,0xd2,0x29,0x9c,0xd6,0x00,0x9d,0x7b,0x19,0x4d,0x47,0x9d, + 0x04,0x20,0x0e,0x5b,0xed,0xae,0x4c,0x95,0x2b,0x95,0x9b,0x94,0x80,0x07,0x8c,0x2e,0xe0,0x31,0x86,0x28,0xe5,0x41,0xef,0x99,0x4b,0x68,0x3c,0xd9,0x67,0xd8,0x2b,0x0d,0xae,0x4a,0x47,0x9d, + 0x04,0x20,0x17,0xf3,0x18,0x6b,0x10,0x9f,0xa3,0x36,0xf4,0x77,0x50,0xb2,0xfe,0x86,0xbe,0xd2,0xb4,0x96,0x8a,0xbb,0x64,0x84,0xe7,0x6b,0x82,0xd7,0x22,0xb4,0x85,0xeb,0x8e,0x87,0x47,0x9d, + 0x04,0x20,0x14,0x0f,0x49,0xe8,0x64,0x04,0xbd,0x20,0x54,0xee,0x7e,0xb1,0x42,0x7e,0xa4,0x0d,0x3f,0xf2,0x8f,0x64,0x43,0x6f,0xbf,0x4d,0x66,0xbc,0x7e,0x10,0xfa,0xab,0x21,0x76,0x47,0x9d, + 0x04,0x20,0x15,0x7b,0x9d,0xa3,0x22,0xa7,0xca,0xc9,0x87,0x1c,0x3e,0x12,0xb4,0x3c,0xef,0xf0,0x4f,0xa0,0x6f,0x2c,0x66,0xbf,0x32,0x91,0xa3,0xc0,0xa9,0xbe,0x4e,0xda,0x9a,0x81,0x47,0x9d, + 0x04,0x20,0x16,0x17,0xf2,0x51,0x2a,0xba,0xf7,0x2d,0x88,0x34,0x3b,0x1d,0x43,0xaa,0xf3,0xe0,0x86,0x57,0xad,0xe1,0x38,0x35,0x9f,0x27,0xa0,0x18,0x04,0x30,0x43,0x51,0x4a,0x74,0x47,0x9d, 0x04,0x20,0x1f,0xb7,0x52,0xf3,0xb3,0x07,0x04,0x78,0x92,0xcd,0x8d,0x31,0x5c,0x3d,0x9f,0xc0,0x4b,0x79,0xd2,0x7b,0xd7,0xc5,0x19,0xc3,0xd0,0x2e,0x23,0x51,0x5a,0xfc,0xdf,0x22,0x47,0x9d, - 0x04,0x20,0x21,0x60,0x5b,0x7a,0xa9,0x87,0xcc,0xf3,0x60,0xee,0x95,0x37,0x02,0xeb,0x87,0x94,0x8f,0x77,0x84,0xe0,0xc7,0x35,0xe1,0x0a,0x46,0xcf,0x78,0xa2,0x63,0x82,0xad,0xa8,0x47,0x9d, + 0x04,0x20,0x18,0xe5,0x79,0x6f,0x23,0x54,0x9f,0x05,0x0a,0x59,0x65,0xff,0xc8,0xaa,0xdf,0x34,0x12,0x67,0xe7,0x54,0x28,0x79,0x08,0x1f,0x83,0xcf,0x50,0x0c,0x49,0xc4,0xd9,0x6b,0x47,0x9d, + 0x04,0x20,0x1d,0x29,0x61,0x95,0xab,0x8d,0x06,0xe6,0xd8,0xc3,0xad,0x41,0x41,0xed,0x1d,0xd6,0x47,0x73,0x68,0x29,0x26,0x3e,0x96,0x66,0x4a,0x30,0x81,0x44,0x60,0x89,0xc1,0x4b,0x47,0x9d, + 0x04,0x20,0x1d,0x83,0xcf,0x89,0x90,0x06,0xa6,0x97,0xb2,0xa9,0x01,0x01,0x1f,0x98,0x62,0x04,0x65,0xa5,0x93,0x3e,0x6a,0x08,0x53,0xa3,0x90,0x2e,0xb5,0x02,0x1e,0x78,0x98,0x3d,0x47,0x9d, + 0x04,0x20,0x26,0xbe,0xd0,0xa5,0x4e,0xa6,0x98,0xa8,0x51,0xd8,0x9a,0x50,0xbd,0x7c,0xdd,0x3e,0xf9,0x65,0x19,0x33,0x8d,0xa8,0xf6,0xed,0x94,0x16,0x85,0xa0,0xff,0xc3,0x28,0xd5,0x47,0x9d, + 0x04,0x20,0x27,0xe6,0xa8,0x97,0xbc,0x69,0xb7,0x0e,0xd4,0x4d,0xe9,0x9b,0xff,0xe6,0xc9,0xb3,0x3f,0xc5,0xa8,0xa0,0xaf,0x19,0x61,0xd2,0xfb,0x7d,0x5c,0xdf,0x62,0xb0,0x36,0xe6,0x47,0x9d, + 0x04,0x20,0x21,0x2b,0xba,0xd0,0xfd,0xe8,0xf0,0xc3,0xb7,0x79,0xe2,0xd8,0x70,0x44,0xc2,0xc6,0xaf,0x96,0x79,0x7c,0xc6,0x07,0xd0,0xf0,0x26,0x2c,0xa7,0x7d,0x48,0xbf,0xeb,0x25,0x47,0x9d, + 0x04,0x20,0x26,0x12,0x03,0xc4,0xc9,0xfc,0x00,0x3c,0x89,0xd3,0x03,0x6e,0x50,0x9e,0x47,0x92,0x59,0xfc,0x27,0x6f,0xf4,0xe5,0x24,0x51,0xe8,0xa0,0x7e,0xae,0xcb,0xbd,0x6d,0xc5,0x47,0x9d, + 0x04,0x20,0x2f,0x81,0x64,0x09,0xc1,0xcc,0x77,0x7e,0x17,0x3b,0x1b,0x6e,0x18,0xb8,0x11,0x0d,0x16,0x48,0x6b,0xc9,0xca,0xe6,0xd5,0xfa,0xca,0x6a,0x9e,0x7d,0x2e,0x97,0x8d,0x2c,0x47,0x9d, + 0x04,0x20,0x28,0x50,0xc2,0x49,0xb8,0x3e,0x68,0x10,0xe6,0x02,0xdd,0x01,0x42,0xe5,0x41,0xc1,0x58,0xd5,0x5e,0xb8,0x7b,0xae,0x0a,0x90,0x14,0x0f,0xe3,0x97,0xe4,0xfa,0x2b,0xaf,0x47,0x9d, + 0x04,0x20,0x2a,0x45,0x1e,0xf4,0xc6,0xdd,0x6b,0xf8,0x21,0x5e,0xe4,0xae,0xd4,0x1c,0xe4,0xa5,0x54,0x5c,0x4d,0xf5,0xcb,0x3a,0x96,0x1b,0x3d,0xe8,0x9f,0xee,0x6b,0xf8,0xae,0x13,0x47,0x9d, + 0x04,0x20,0x2b,0xf3,0x81,0x30,0x59,0xe0,0xe2,0x7e,0x78,0xa7,0x11,0x46,0xa3,0x20,0x2d,0x7f,0xe0,0x64,0x39,0xdb,0xa3,0xe1,0x4b,0xe1,0x36,0x57,0xb2,0x43,0x22,0x21,0x10,0xf9,0x47,0x9d, + 0x04,0x20,0x2c,0x17,0x2f,0x8a,0xb4,0x67,0xd6,0xf0,0x58,0x03,0xfb,0x7b,0x98,0xd5,0x91,0x85,0xa2,0x3f,0xfa,0x14,0x17,0x63,0xf7,0x85,0x6d,0x18,0x1c,0x3d,0xda,0x09,0x5b,0xcb,0x47,0x9d, + 0x04,0x20,0x2d,0xa5,0x68,0x4f,0x51,0x08,0xc3,0x29,0xdf,0xaa,0xc8,0x38,0x60,0xfc,0x0e,0x56,0xcc,0x4c,0x83,0x25,0x34,0xdc,0xa0,0x0e,0x04,0x45,0x8c,0xa3,0x0d,0x56,0xb0,0xd8,0x47,0x9d, + 0x04,0x20,0x2d,0xfe,0x48,0xd9,0x8a,0xa1,0xd3,0xf7,0xe8,0x88,0xa2,0x24,0x9b,0x1b,0x66,0xd8,0x36,0x0b,0x7a,0x86,0x59,0x1e,0x0e,0x7c,0xd6,0x17,0xfc,0x35,0xc6,0xcf,0x16,0xda,0x47,0x9d, + 0x04,0x20,0x31,0xe0,0x18,0x3f,0x63,0x44,0x70,0x0f,0x92,0x4f,0x6a,0x76,0xcd,0xa8,0xfe,0x61,0xc0,0xb8,0x5d,0x35,0xff,0x59,0x4a,0x33,0x92,0x25,0x14,0xe7,0x90,0x73,0xb6,0x25,0x47,0x9d, + 0x04,0x20,0x33,0xea,0x10,0x8e,0x55,0xf7,0xf7,0x92,0x9b,0x4c,0x78,0x73,0x72,0x5d,0xac,0xae,0xdd,0x00,0x28,0xd0,0x73,0xb1,0x5c,0x66,0x2b,0x3d,0x3c,0xca,0x0b,0x0b,0x2b,0x83,0x47,0x9d, + 0x04,0x20,0x34,0x51,0xa4,0xf2,0x74,0x1d,0x5d,0x70,0x67,0x5e,0x48,0x72,0xc6,0xf1,0x4b,0x73,0xbb,0x9f,0xc2,0x48,0xdd,0x4a,0x8d,0x8b,0xae,0x57,0x67,0x46,0xb3,0x78,0xcb,0x0a,0x47,0x9d, + 0x04,0x20,0x34,0xad,0xe9,0x37,0x5f,0x85,0x2c,0x5f,0x53,0x72,0xb1,0xa2,0x0f,0x3b,0xeb,0x8b,0xfb,0x00,0x53,0xca,0x9e,0xf0,0xca,0x61,0xd7,0x32,0xa6,0x7f,0x59,0xb3,0xcb,0x34,0x47,0x9d, 0x04,0x20,0x36,0x3c,0xd4,0x1f,0x8f,0x63,0xfa,0x49,0x62,0xb5,0x69,0xd6,0x9f,0x42,0xaa,0xfe,0x54,0x14,0xd1,0xd2,0xb2,0xae,0x52,0xe1,0x08,0x7e,0xc6,0x15,0x56,0x45,0xbd,0xb3,0x47,0x9d, - 0x04,0x20,0x3d,0x90,0xfc,0xa1,0xd3,0x12,0xee,0x6d,0xac,0x83,0x6f,0x70,0x9e,0xa7,0xcd,0xf3,0xd5,0x13,0x35,0x8b,0x54,0x9d,0x9c,0xae,0x33,0x5b,0x56,0xf3,0x52,0xa8,0xbb,0xaf,0x47,0x9d, + 0x04,0x20,0x3f,0x2f,0x1f,0xe1,0xd5,0xc6,0xd4,0x68,0xb8,0xe3,0x58,0x7b,0x95,0xa6,0x78,0xb1,0x08,0xbc,0x0a,0x65,0x31,0x7b,0x0d,0x71,0xab,0x3e,0x1d,0x70,0xb1,0x2c,0x0a,0xfe,0x47,0x9d, + 0x04,0x20,0x3f,0x31,0x49,0x19,0x69,0x88,0x10,0x50,0x35,0x09,0xe3,0xee,0xab,0x72,0x0a,0x97,0x10,0x85,0xc0,0x30,0xdf,0x40,0x19,0x23,0x5c,0x12,0x1b,0x4a,0xd3,0x0c,0xef,0x8c,0x47,0x9d, + 0x04,0x20,0x38,0x41,0xb6,0x3c,0xf7,0x3b,0xe9,0x8e,0x5f,0xa6,0x4c,0x31,0x0f,0x70,0x36,0x9a,0xf2,0xb2,0xd2,0x42,0xb8,0xbe,0xde,0xac,0xfc,0x57,0x1c,0x8b,0x44,0xc2,0xcf,0x68,0x47,0x9d, + 0x04,0x20,0x3a,0x75,0x3b,0xae,0xe0,0x48,0xd6,0x7f,0xa6,0x45,0xb4,0x2f,0x37,0xec,0x4b,0x9a,0xdf,0x39,0x47,0x7b,0x14,0xd2,0xa0,0xdc,0xe1,0xc8,0x70,0x88,0xa9,0x82,0x79,0x4f,0x47,0x9d, + 0x04,0x20,0x3b,0x26,0x16,0xe1,0x8e,0xa0,0x10,0xc3,0xb6,0xe0,0xcd,0x13,0x6f,0xa3,0xa1,0xf9,0xe0,0x34,0x5e,0x2b,0x40,0x47,0x86,0xee,0x63,0xe0,0x47,0x6e,0x49,0x3f,0x90,0x5a,0x47,0x9d, + 0x04,0x20,0x3c,0xd4,0x88,0x02,0x0e,0x82,0xfe,0xf4,0xca,0x64,0x6b,0x2d,0xea,0xf0,0x2b,0x67,0x97,0xdf,0x8f,0xc7,0x5f,0x98,0x4b,0x5d,0x4c,0x2a,0x37,0x0a,0x31,0xd9,0x2a,0xef,0x47,0x9d, + 0x04,0x20,0x3d,0x42,0xc6,0x66,0xb0,0x8b,0xcc,0xf9,0x6a,0xfd,0xa7,0x10,0xfe,0x2a,0x45,0xd9,0x3a,0xcd,0x15,0xa4,0x00,0xbf,0xde,0x1a,0x6d,0x3a,0x5b,0xa8,0xc8,0x95,0x6a,0x3c,0x47,0x9d, + 0x04,0x20,0x3d,0x67,0x7c,0x32,0xa3,0x0f,0x7b,0x4f,0xac,0xe3,0xb7,0xbf,0xfe,0x81,0x50,0xc7,0x3c,0x86,0xd1,0xab,0xdd,0x28,0xfd,0x7c,0xcd,0x95,0xd9,0xa0,0xc1,0x95,0xef,0x6c,0x47,0x9d, + 0x04,0x20,0x47,0x4a,0x97,0xfc,0xc6,0xbf,0xb5,0x95,0x95,0x48,0x0e,0x5b,0xf9,0x78,0xcb,0x7a,0x5f,0xb3,0xeb,0x0f,0x2b,0x99,0xb5,0xb2,0x08,0xba,0x0d,0xf8,0x04,0x66,0x22,0x77,0x47,0x9d, 0x04,0x20,0x47,0x4c,0xf3,0xdb,0x43,0xd6,0xb9,0x36,0xa2,0x0a,0x49,0x03,0x71,0xdb,0x3d,0xc1,0x82,0x17,0x74,0xc2,0xa4,0x8e,0xec,0x12,0xb5,0xfd,0xfe,0xee,0x77,0x81,0xf4,0x17,0x47,0x9d, + 0x04,0x20,0x41,0xc0,0xb3,0x33,0x67,0x97,0x78,0x7f,0x82,0x1b,0xf9,0xc3,0x1c,0x02,0xe2,0x1a,0xdd,0x66,0x2d,0x92,0xef,0x11,0xc1,0x67,0xc7,0x80,0x73,0xc6,0xea,0x09,0x4a,0x2d,0x47,0x9d, 0x04,0x20,0x43,0xc3,0x99,0x69,0x61,0x27,0xd6,0x00,0xea,0xe0,0x42,0xaa,0xa1,0xaa,0xd7,0x40,0x1b,0xe9,0xed,0xa0,0x50,0x1c,0xb9,0xd8,0x32,0x3b,0xc9,0x50,0xcb,0x23,0xab,0xb1,0x47,0x9d, + 0x04,0x20,0x46,0x25,0x7d,0x0d,0x7c,0x9b,0xdc,0x94,0x09,0x67,0xde,0x91,0x83,0x91,0x7e,0xcf,0xcf,0xad,0x7c,0x5f,0x77,0xc3,0x4c,0xab,0xb6,0xa4,0x2d,0xe8,0x1e,0x98,0x9d,0x65,0x47,0x9d, + 0x04,0x20,0x48,0x4d,0x52,0x7f,0x28,0xe5,0x6f,0xd5,0xff,0xdd,0xe2,0x0f,0xc6,0xe6,0x93,0x93,0xe9,0xbf,0x0e,0xb2,0xf7,0xae,0xb2,0x18,0x48,0xa4,0x74,0x27,0xe1,0x9c,0x30,0xd2,0x47,0x9d, 0x04,0x20,0x4a,0x4b,0x4c,0x27,0xea,0x89,0xb2,0xa6,0x3e,0xf5,0x6e,0xc3,0xa4,0xe8,0xf6,0x5e,0x54,0xcc,0x93,0x64,0xce,0x36,0x82,0xd9,0x5f,0x1b,0x65,0x6b,0x02,0xc6,0x66,0x60,0x47,0x9d, 0x04,0x20,0x4b,0x5e,0x72,0xcc,0x87,0x51,0x65,0x3b,0x05,0x4e,0xdf,0x10,0x3b,0xad,0xee,0xe9,0x47,0x6f,0x2e,0x2e,0x62,0x98,0x4a,0x2a,0xe7,0xdd,0xc4,0xb9,0x9d,0x72,0x99,0x0e,0x47,0x9d, - 0x04,0x20,0x4c,0x4e,0xfb,0x40,0x07,0x4c,0x53,0xfe,0x9a,0x61,0xf9,0xa7,0xad,0x92,0xa4,0xf7,0x6f,0xf0,0x84,0x16,0xc7,0xd3,0xc2,0x0c,0xec,0x30,0x5d,0xd6,0xa7,0x4c,0x50,0x08,0x47,0x9d, + 0x04,0x20,0x4b,0xe8,0x93,0x30,0x51,0xd1,0x66,0xa5,0xde,0x31,0xfd,0x2d,0x73,0xed,0x26,0xe6,0xe9,0x00,0x4f,0x12,0xfd,0x8c,0xe9,0x14,0x2f,0x28,0x6f,0xd9,0xde,0xda,0x6e,0x7f,0x47,0x9d, + 0x04,0x20,0x4c,0x85,0xc2,0xc6,0xb5,0x6a,0xf4,0x3d,0x84,0xf9,0xc3,0x8b,0x21,0x7f,0x57,0x7e,0x66,0x66,0x6b,0x6d,0x5f,0x0a,0xd0,0xf0,0x76,0x56,0x65,0x78,0xf8,0xa7,0x42,0x75,0x47,0x9d, 0x04,0x20,0x4d,0x1b,0xe3,0x0d,0x81,0x30,0x25,0x1e,0xfc,0x27,0x8f,0x33,0x2d,0x8c,0xa7,0x17,0x9f,0x97,0x82,0xda,0xfb,0x60,0x1e,0x0c,0x03,0x08,0x11,0xfc,0x44,0x30,0xef,0x73,0x47,0x9d, - 0x04,0x20,0x77,0x75,0x8f,0x94,0x03,0x9d,0x03,0x1e,0x4e,0x90,0x3a,0x2f,0xec,0x32,0x28,0x6e,0xe1,0x96,0xfe,0x81,0x3f,0x66,0x4b,0x52,0x84,0x3d,0xbb,0x6b,0x88,0x2d,0x2a,0x7d,0x47,0x9d, - 0x04,0x20,0x8a,0x0c,0x56,0x6d,0x2e,0x41,0x7a,0xb9,0x2f,0xe1,0xfe,0x23,0xe1,0xf8,0x55,0x18,0xe8,0xa0,0x5b,0x0a,0x67,0xd4,0x63,0x53,0x25,0xb2,0x3c,0x37,0xac,0x4a,0xc6,0x7d,0x47,0x9d, - 0x04,0x20,0x9f,0x87,0xe2,0x3c,0x3d,0x10,0x82,0xee,0x13,0xde,0x40,0x00,0xda,0x2a,0x20,0xbb,0xd2,0xc8,0x22,0x12,0xcf,0x9e,0xe4,0xf6,0x95,0xbd,0x34,0xeb,0x35,0xa7,0x11,0xa9,0x47,0x9d, - 0x04,0x20,0x99,0x25,0x3d,0x55,0xd9,0x5d,0xcb,0x96,0xb0,0xb8,0xbe,0x55,0x45,0x97,0x6b,0xf4,0x09,0xe1,0xcd,0x1d,0x3c,0x0a,0x99,0x5c,0x11,0xea,0xd8,0xbe,0x74,0x49,0x6e,0x09,0x47,0x9d, - 0x04,0x20,0xa5,0xe6,0xc9,0xb1,0xea,0x28,0x2e,0x2f,0x64,0x57,0x05,0xcd,0x81,0xc6,0x8a,0xc0,0xfa,0x91,0xc4,0x4f,0xd3,0x3a,0xea,0x05,0xe8,0x62,0x13,0x8e,0x72,0x2d,0x4d,0x31,0x47,0x9d, + 0x04,0x20,0x50,0x18,0x06,0x9d,0xdd,0x12,0xc4,0xf6,0xf5,0x7b,0x90,0xbc,0x83,0xee,0xa1,0xe4,0x94,0xc2,0x9c,0xd7,0xb6,0xcf,0xa6,0x1a,0x5f,0x27,0x50,0x32,0x93,0x34,0xe8,0xed,0x47,0x9d, + 0x04,0x20,0x51,0x13,0x8c,0xce,0x71,0x26,0x07,0xf6,0xa7,0x52,0xbd,0xf5,0xd6,0xab,0x90,0xb1,0xaf,0x3a,0x43,0x01,0xc2,0xef,0x48,0x45,0x31,0x71,0x3a,0xc0,0x9d,0x71,0xee,0xf4,0x47,0x9d, + 0x04,0x20,0x53,0x54,0xa8,0x06,0xe7,0x1a,0x27,0xcb,0xa1,0x6a,0x90,0x7b,0x89,0x6e,0x0d,0x85,0x7d,0xb9,0x80,0xfd,0xa5,0x69,0xb6,0xe9,0x0c,0xa7,0x03,0x81,0x21,0xf4,0xdf,0x78,0x47,0x9d, + 0x04,0x20,0x53,0xe5,0x8f,0x84,0x30,0xba,0x1d,0x35,0x77,0xa0,0x00,0x93,0x3d,0x1d,0x00,0x4f,0x8f,0xd7,0xdd,0x29,0xac,0x83,0xed,0x9c,0xce,0x97,0x01,0x82,0xe6,0xd1,0x63,0x65,0x47,0x9d, + 0x04,0x20,0x55,0x93,0x75,0x82,0x96,0x4c,0xc8,0x24,0x96,0x48,0xb3,0x9e,0x15,0xf5,0xf5,0x6f,0x5b,0xec,0xf6,0x39,0xff,0xa8,0xaf,0x3a,0x4c,0x5d,0x22,0x3d,0xd3,0x14,0xc3,0x05,0x47,0x9d, + 0x04,0x20,0x66,0xbe,0x71,0xeb,0xed,0xf8,0xd8,0xdc,0x18,0x63,0x6b,0xfa,0x16,0x97,0xd5,0x5f,0x68,0xa9,0x7f,0xe9,0x8c,0x35,0x43,0xce,0xf7,0xa9,0x89,0x61,0x2f,0x29,0xb4,0x91,0x47,0x9d, + 0x04,0x20,0x66,0xf7,0x96,0x76,0x13,0xc9,0x80,0x5f,0x74,0x07,0x05,0xc2,0xe6,0x7f,0xb9,0x71,0x0f,0x8c,0xc7,0x6b,0x0c,0x0b,0xa7,0x06,0x6f,0xce,0x72,0x92,0x06,0xbf,0xc0,0xff,0x47,0x9d, + 0x04,0x20,0x62,0x65,0xe7,0x8d,0xa3,0xe9,0xf9,0x81,0x32,0x46,0x8d,0x2d,0x6e,0x0a,0x32,0x24,0xa1,0x91,0xdb,0x65,0x23,0x06,0x86,0xc9,0x1e,0x71,0x8e,0xc4,0xac,0x7f,0x5b,0xb0,0x47,0x9d, + 0x04,0x20,0x6e,0xb6,0x06,0xdb,0x99,0x0f,0xcb,0xb7,0x82,0x2e,0x00,0xbd,0xaf,0x38,0x5a,0x94,0x31,0xbc,0x37,0xaa,0x49,0x5e,0x28,0x54,0x3b,0x5d,0x47,0x8b,0xfc,0x79,0xcb,0xdd,0x47,0x9d, + 0x04,0x20,0x6f,0x09,0xe2,0xbf,0xd7,0x76,0x1d,0xa3,0x2e,0x40,0x2a,0x6c,0x10,0x43,0x76,0x44,0x4e,0xb1,0xbd,0x36,0xe3,0x24,0xa6,0xf5,0x79,0x53,0x38,0xee,0xac,0xe7,0xeb,0x7a,0x47,0x9d, + 0x04,0x20,0x6b,0xb1,0x9b,0x4d,0xe5,0x86,0x03,0x83,0x91,0x91,0x65,0xf2,0x3f,0xb4,0xbc,0x42,0xfa,0xc3,0xc9,0xcb,0xa3,0xdf,0xfb,0xcd,0x91,0x4b,0xa4,0x09,0xfe,0x03,0x64,0x39,0x47,0x9d, + 0x04,0x20,0x72,0xdb,0xfc,0x04,0x48,0xee,0xec,0xae,0x1b,0xad,0xe6,0x9a,0x87,0xe1,0x17,0xae,0x13,0x70,0xae,0x83,0x90,0x62,0x59,0x30,0xed,0x44,0x43,0xe9,0xab,0xee,0xaa,0xd0,0x47,0x9d, + 0x04,0x20,0x73,0x83,0x69,0xb7,0xa2,0x92,0x38,0x0a,0x12,0xa1,0xd3,0x65,0xa0,0xf6,0x31,0x4b,0x6e,0xc3,0xaf,0x23,0x60,0x31,0xcc,0xde,0x79,0xaa,0x93,0xf9,0x83,0x11,0x35,0x8a,0x47,0x9d, + 0x04,0x20,0x73,0x9a,0x3d,0xc1,0x8d,0x1a,0x82,0x33,0x7f,0xd1,0xc6,0x13,0x99,0x85,0x92,0x65,0x5c,0x9e,0x6e,0x9e,0xe1,0x92,0x78,0xe9,0xb5,0x84,0x51,0x44,0xe2,0x64,0x25,0x39,0x47,0x9d, + 0x04,0x20,0x74,0x2e,0x8a,0xdd,0xe8,0x9f,0xf9,0x69,0x39,0xf3,0x90,0x7c,0xa8,0xed,0x5a,0xb9,0x20,0xfc,0x94,0x6e,0xcd,0x6d,0xc6,0x6a,0xd5,0xad,0x13,0x12,0xae,0xee,0xe6,0x14,0x47,0x9d, + 0x04,0x20,0x75,0xd5,0x8a,0x25,0xa9,0x0a,0xfc,0xaf,0xa8,0x57,0x00,0xa7,0x82,0xf0,0x0a,0x7e,0xc8,0x99,0x96,0x6d,0x0b,0x33,0x35,0x7a,0x93,0xbc,0xf9,0x9c,0x70,0xa7,0x3c,0xd5,0x47,0x9d, + 0x04,0x20,0x7e,0x9c,0x89,0xe2,0x53,0xc0,0x25,0xd7,0xdc,0x8e,0xd7,0xb4,0xc7,0x5f,0xc0,0x71,0x79,0x3a,0x2b,0x01,0x6a,0xfe,0x24,0xfc,0xa2,0xb3,0xa4,0x78,0x12,0x55,0x2a,0xb5,0x47,0x9d, + 0x04,0x20,0x7a,0x75,0x1b,0xc3,0x52,0x28,0x6d,0x39,0x42,0x02,0x0b,0x4a,0xdb,0x28,0xdb,0xf0,0xff,0xac,0x08,0x9d,0xf4,0x18,0xfd,0x49,0x29,0x60,0x7e,0x7a,0xe5,0xf9,0x02,0x36,0x47,0x9d, + 0x04,0x20,0x7d,0x37,0x91,0x10,0x54,0x4e,0x43,0x21,0x81,0xc6,0x2f,0x20,0x67,0x6e,0x84,0xf7,0xd6,0x8a,0xbb,0x20,0xf6,0x81,0x65,0x94,0xa9,0x6c,0x1b,0x14,0x04,0xcc,0xae,0x20,0x47,0x9d, + 0x04,0x20,0x87,0x60,0xeb,0xff,0xbe,0x40,0xfa,0xd2,0x8e,0x9e,0x3c,0xf8,0x33,0x1c,0x5b,0xea,0x49,0x95,0xcb,0x81,0x32,0x44,0x36,0xc4,0x72,0xdb,0xec,0xd1,0xd4,0x77,0xde,0xb2,0x47,0x9d, + 0x04,0x20,0x81,0x34,0x90,0x93,0x9c,0xf9,0xc9,0xe7,0x81,0xa5,0xab,0xf1,0x03,0xe1,0xb3,0x2f,0xf7,0xcf,0x19,0x94,0x2f,0x7a,0x1b,0xc5,0x83,0xc9,0x8c,0xc3,0x5b,0x09,0x96,0x14,0x47,0x9d, + 0x04,0x20,0x81,0x75,0x30,0x42,0xd3,0xce,0xdf,0x29,0xcf,0xfb,0x39,0x83,0x12,0xd6,0x68,0x59,0x88,0x29,0x0b,0xbd,0xf2,0xd1,0x95,0x65,0x5a,0x12,0x24,0x38,0x23,0xeb,0x8b,0x65,0x47,0x9d, + 0x04,0x20,0x82,0x08,0xfe,0x1e,0xb4,0x75,0x48,0x30,0x84,0x5b,0xf1,0xd7,0xf6,0xda,0x4b,0xb2,0x3c,0x03,0xfa,0x96,0xe3,0x5b,0x22,0x61,0x23,0x98,0xbf,0xb1,0x0b,0xb1,0x28,0xc1,0x47,0x9d, + 0x04,0x20,0x84,0x32,0x46,0x12,0x33,0x84,0x6d,0xd8,0x0c,0xa0,0x52,0x5c,0x0c,0x6f,0xb6,0x25,0x3d,0x09,0x1e,0x3a,0x5f,0x4f,0xc9,0x31,0x6d,0x80,0x0a,0x8d,0xe6,0x05,0xcc,0xef,0x47,0x9d, + 0x04,0x20,0x86,0x6f,0xd2,0xe9,0x06,0xd4,0x55,0xa9,0x4a,0x21,0x73,0xf3,0xac,0xad,0x69,0x87,0x58,0xa2,0x1f,0x68,0xc9,0xcf,0x7d,0xcf,0x62,0x23,0xe4,0x4e,0xc1,0xa7,0xab,0xdd,0x47,0x9d, + 0x04,0x20,0x8e,0x82,0x32,0xa8,0x47,0x4e,0xb3,0xe6,0xc4,0x3d,0xf0,0x17,0x40,0xe5,0x81,0xe4,0xed,0x91,0xb4,0x42,0x50,0x45,0x79,0x55,0x52,0xca,0x45,0xe6,0x45,0x0d,0x40,0x40,0x47,0x9d, + 0x04,0x20,0x89,0x51,0xa3,0x8d,0xe9,0x39,0xd4,0xd0,0x2d,0x73,0x0d,0x87,0x5c,0x50,0xf2,0x51,0xfb,0x84,0xcb,0xde,0x8c,0x32,0xfc,0x79,0x64,0xc7,0xef,0x3a,0x71,0x55,0x09,0x1c,0x47,0x9d, + 0x04,0x20,0x8c,0x41,0xf8,0x7e,0xfb,0x25,0x05,0xb7,0x67,0x04,0x02,0xd1,0x5d,0xce,0x58,0xb4,0x73,0xbe,0x2f,0x9e,0xf1,0x41,0x77,0x1d,0x93,0x9d,0xa6,0x5e,0x8e,0x72,0xfe,0xd9,0x47,0x9d, + 0x04,0x20,0x91,0x74,0x55,0x47,0xc7,0x31,0x49,0x92,0x16,0xe0,0x81,0x61,0x06,0xf6,0x24,0x69,0xa2,0xb5,0x56,0xd8,0x9c,0x72,0x47,0xc8,0x15,0xb3,0xa6,0x43,0xbf,0x4b,0x55,0x69,0x47,0x9d, + 0x04,0x20,0x91,0xde,0x7d,0x52,0x02,0xa8,0x49,0xa3,0x8b,0x5d,0x86,0xd6,0xdf,0xee,0x12,0x11,0xc9,0xd1,0x8e,0x01,0xe5,0x3b,0x35,0x30,0xd0,0xaf,0xf6,0x04,0x0a,0x2c,0x62,0x94,0x47,0x9d, + 0x04,0x20,0x92,0xde,0x83,0x33,0xa4,0x7f,0x32,0x06,0xec,0x1e,0xe8,0x70,0x16,0x93,0xdf,0x79,0xd2,0x8c,0x12,0x41,0xa2,0xbb,0x2d,0x85,0xc3,0x21,0x68,0x76,0xdf,0x42,0x28,0xe6,0x47,0x9d, + 0x04,0x20,0x95,0xd9,0xe5,0x5a,0x23,0x7f,0x8b,0xa3,0x18,0x0e,0xc9,0xe2,0xbe,0x7e,0xf4,0xc6,0xc9,0x2d,0xc8,0xcc,0xda,0x2a,0xf7,0xb0,0xfc,0xbb,0x36,0x72,0xb0,0x93,0xad,0x83,0x47,0x9d, + 0x04,0x20,0x9e,0xf3,0xf9,0x48,0x49,0x18,0x5b,0x2c,0x0d,0xc7,0xb8,0xa5,0xd6,0xb1,0xd7,0x2a,0x37,0xd7,0xfb,0x35,0xe2,0x6b,0xd4,0xc9,0x73,0x92,0xf8,0x30,0x4f,0x33,0x51,0x0b,0x47,0x9d, + 0x04,0x20,0x98,0xda,0x29,0xab,0x8b,0xbf,0xd2,0xd5,0x2d,0xc9,0x44,0x86,0x2c,0xbf,0xc7,0xe0,0x78,0x44,0xce,0x84,0x9e,0x0f,0xd1,0x04,0x8c,0xcb,0x04,0xd7,0x7e,0xb5,0x77,0xec,0x47,0x9d, + 0x04,0x20,0x9c,0x6e,0xea,0x54,0xc2,0xb4,0x45,0xb8,0xa8,0x96,0x7e,0x6a,0xab,0x84,0xb5,0x7a,0xe6,0x5b,0x30,0xcb,0xdf,0xec,0xe4,0x51,0x29,0xe5,0x5b,0xed,0xe6,0xc7,0xaa,0xb9,0x47,0x9d, + 0x04,0x20,0x9e,0x1d,0xe4,0xd6,0x09,0x3e,0xf9,0x1d,0x07,0xe8,0xe7,0xff,0x75,0x8a,0x36,0x9f,0xe3,0x0d,0x16,0xd4,0xb3,0xc1,0x7e,0xcb,0x6d,0xb6,0xe6,0x50,0xce,0xc1,0x75,0xfe,0x47,0x9d, + 0x04,0x20,0xa6,0xf2,0xd2,0xdc,0xfe,0xc2,0x6a,0x25,0xd3,0x6b,0xf7,0x3d,0x9c,0xb0,0xc2,0x5c,0x14,0xc6,0x46,0x31,0xb4,0xc3,0xda,0x46,0x71,0xe5,0x87,0xe9,0x54,0xf1,0x38,0xcd,0x47,0x9d, + 0x04,0x20,0xa0,0xb5,0xd9,0xf5,0x83,0x63,0x5f,0x76,0xf7,0x50,0x40,0x76,0x27,0xcb,0x90,0xc0,0xb8,0x63,0x85,0xb3,0x44,0xc9,0x3c,0xa0,0x1a,0xaa,0xa0,0x00,0x59,0x15,0xc4,0x32,0x47,0x9d, + 0x04,0x20,0xa0,0xfb,0xd3,0x12,0xa7,0xc9,0xce,0x24,0xc8,0x06,0x39,0x73,0x08,0x7e,0xd8,0xb5,0xd9,0x6f,0xb7,0xd2,0xc1,0xed,0x21,0xcb,0x54,0xb7,0x13,0xf7,0x27,0x4e,0x3f,0x73,0x47,0x9d, + 0x04,0x20,0xa1,0x31,0x85,0x31,0xb8,0x82,0xb4,0x16,0xb0,0x26,0xab,0x21,0x10,0xf1,0x25,0x0a,0x6a,0xf3,0x10,0x96,0xf0,0xa9,0x0e,0x18,0x10,0x27,0xeb,0xa7,0x23,0x17,0x05,0x02,0x47,0x9d, + 0x04,0x20,0xa5,0xbe,0x82,0xfa,0xd8,0x0b,0xf3,0x9b,0x44,0x16,0x7f,0xa2,0x39,0xa8,0x51,0x43,0xe7,0xfa,0xb2,0x8e,0xe0,0x5f,0x35,0x9b,0x83,0x23,0x7f,0x3d,0x3b,0xfb,0xda,0x78,0x47,0x9d, + 0x04,0x20,0xa8,0xa6,0xbb,0x02,0x06,0x65,0x3b,0xb2,0x52,0x79,0xd1,0xc9,0x6a,0x01,0x42,0x43,0xca,0x69,0xe1,0x69,0x90,0xfe,0x2c,0xd2,0x7c,0x18,0xfd,0xab,0xc7,0x71,0x7f,0x8b,0x47,0x9d, + 0x04,0x20,0xac,0x1a,0xa1,0xb1,0xec,0x20,0x85,0xd5,0x39,0xa3,0x4e,0xf4,0x9b,0x04,0x8c,0x64,0x68,0x76,0x0f,0xa6,0x53,0x0a,0xd3,0x2a,0x42,0x24,0xd0,0x1c,0xbb,0x31,0xc3,0xf8,0x47,0x9d, + 0x04,0x20,0xb6,0x9a,0xd9,0x25,0xfb,0x77,0x5a,0x33,0xf2,0x24,0x74,0x6d,0x2a,0x0d,0x8a,0x4d,0x71,0xb0,0xba,0x9d,0x34,0xfe,0x56,0x52,0x55,0x7e,0xda,0x4d,0x15,0xc9,0x36,0x1e,0x47,0x9d, + 0x04,0x20,0xb3,0x6e,0x64,0x99,0x26,0x7a,0xeb,0xd4,0x53,0x8c,0x94,0xb1,0x4a,0x37,0x02,0xaa,0xa9,0xc8,0x36,0x11,0xec,0xf9,0x0f,0x08,0xa3,0x9f,0x3e,0xaf,0xd2,0xd1,0x2a,0x0b,0x47,0x9d, + 0x04,0x20,0xb3,0xa9,0xf9,0xa6,0xb4,0x83,0x20,0xbd,0x7d,0x90,0x65,0xc3,0x39,0x46,0x23,0xbb,0x78,0x38,0x06,0x68,0xda,0x42,0xf6,0xa9,0x6a,0x8d,0x20,0x98,0xe6,0x73,0xc6,0x92,0x47,0x9d, + 0x04,0x20,0xb3,0xe4,0x03,0xa4,0x24,0x4d,0xc8,0x77,0xe7,0xff,0xd2,0xb3,0x77,0x35,0x3f,0xff,0xde,0x44,0xb9,0x7a,0x02,0x84,0x81,0x0e,0x90,0x75,0x75,0x1f,0xaa,0x6c,0xd0,0x7c,0x47,0x9d, + 0x04,0x20,0xb5,0x11,0xd6,0x6b,0x1d,0x0f,0xc4,0xc9,0x6f,0xc0,0x47,0xa4,0x7c,0xe2,0x12,0x37,0xa1,0x32,0x11,0x36,0x65,0xe4,0x5d,0x79,0xb8,0x64,0xbd,0x51,0x61,0x57,0x0d,0x58,0x47,0x9d, + 0x04,0x20,0xb5,0x49,0xeb,0x2a,0x44,0x14,0x3c,0x42,0x53,0xda,0x79,0xd4,0xa8,0xa5,0xdd,0xae,0x07,0x12,0x11,0xa0,0xce,0x5f,0xd1,0x78,0xd3,0x9c,0xdd,0xdc,0x36,0x98,0x82,0x49,0x47,0x9d, + 0x04,0x20,0xbf,0x2d,0x5b,0xc1,0xd3,0x04,0x52,0xd4,0x23,0xd4,0x27,0x26,0x5a,0xc2,0x7d,0x8d,0xd6,0x2d,0x7d,0xfa,0x17,0x50,0xc5,0x21,0xf2,0xa6,0xbe,0xe7,0xc4,0xb7,0x94,0xd8,0x47,0x9d, + 0x04,0x20,0xb8,0x0a,0x2c,0x1f,0xcc,0xbd,0x88,0x1a,0x8a,0x46,0xb7,0x2c,0x20,0xd2,0xdf,0x6f,0x2b,0xfa,0x86,0x07,0x16,0x5a,0x7b,0x40,0x4f,0x80,0xa9,0xe1,0xda,0xda,0x62,0x69,0x47,0x9d, + 0x04,0x20,0xbb,0x32,0x43,0x18,0xd9,0xe2,0x98,0x96,0x61,0x0f,0xd0,0xdc,0x6a,0x9d,0x3b,0x06,0x99,0xb9,0x71,0x8a,0x43,0x06,0x91,0xc1,0x56,0x82,0xfa,0xdd,0x8a,0x30,0x24,0xc6,0x47,0x9d, + 0x04,0x20,0xbc,0x79,0x56,0x7a,0x37,0x72,0xe5,0x94,0xdb,0xec,0xfe,0xd8,0x84,0x6f,0xaf,0x7b,0x71,0x3f,0x82,0x0f,0xfd,0xbb,0xbc,0x60,0xdf,0x93,0x04,0xf0,0xbb,0x4c,0x36,0xca,0x47,0x9d, + 0x04,0x20,0xbc,0x7c,0x30,0x32,0x54,0x79,0x86,0x3b,0x5b,0x28,0x45,0xc0,0x40,0x38,0xc9,0xf7,0xce,0xd4,0x8d,0xe9,0x99,0x31,0xd0,0x89,0xa7,0x97,0x70,0x37,0xbe,0x8b,0xe5,0xba,0x47,0x9d, 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, + 0x04,0x20,0xc7,0x09,0x41,0xf9,0x00,0x08,0x1d,0xcf,0x7b,0xd5,0x14,0x37,0x01,0x1f,0xca,0xa9,0xbc,0xb3,0x76,0x1d,0x38,0x33,0x92,0x4d,0x5c,0x4b,0x6d,0x1f,0x54,0x43,0xc2,0x47,0x47,0x9d, + 0x04,0x20,0xc7,0x4f,0xee,0xe9,0x39,0xf4,0x8c,0xc0,0xf0,0x2a,0x11,0x5a,0x5b,0xb5,0x3a,0xe1,0x9a,0x2c,0xc0,0xbf,0x59,0xc7,0xd5,0xc0,0x35,0x19,0xcb,0xd6,0x3d,0x6b,0xe1,0xb0,0x47,0x9d, + 0x04,0x20,0xc0,0x3d,0x2f,0xba,0xbf,0x66,0x11,0x7c,0xee,0x0b,0xd6,0xe9,0xce,0x9e,0x78,0xfb,0x1d,0x77,0x6e,0x3c,0x1e,0xbd,0x00,0x21,0xb6,0xef,0x73,0xee,0xfa,0xb3,0x05,0x3d,0x47,0x9d, + 0x04,0x20,0xc0,0xc1,0xf5,0x59,0xe8,0x46,0xf6,0x9d,0x41,0xf0,0xde,0x8b,0x32,0xf9,0x6f,0xd6,0xb2,0xd5,0x36,0x56,0x43,0xd3,0x60,0x08,0x55,0x94,0x13,0xf5,0xef,0x7f,0x4d,0x4a,0x47,0x9d, + 0x04,0x20,0xc2,0x80,0xa6,0xc3,0x7d,0xb3,0x6c,0x17,0x05,0xfc,0x39,0xa5,0x71,0x8f,0x75,0x27,0x7f,0xd0,0xc8,0xab,0x94,0xfd,0x77,0xbd,0xdd,0x0f,0x2c,0x2e,0x70,0xaf,0xdd,0xdf,0x47,0x9d, + 0x04,0x20,0xc4,0x16,0xad,0xb9,0xd7,0x4b,0xd2,0x3f,0x53,0xe1,0xe2,0x80,0x12,0x6c,0xc8,0x18,0x96,0x5d,0x77,0x14,0x80,0x44,0xf0,0xaa,0xcd,0x20,0xd8,0xb4,0xc5,0x97,0x66,0xe4,0x47,0x9d, + 0x04,0x20,0xc8,0xa4,0xdd,0xa7,0xc0,0x95,0x9b,0x12,0xf7,0xd7,0x4e,0x9b,0xd4,0xb7,0x93,0x5d,0x99,0x87,0x43,0x81,0x23,0x52,0xde,0xd1,0x22,0x36,0x79,0xe1,0x3b,0x58,0xec,0xd9,0x47,0x9d, + 0x04,0x20,0xc9,0x0a,0xd6,0x83,0x40,0xd9,0x81,0xc2,0x67,0x4d,0xa4,0xeb,0x87,0xb0,0x1f,0x66,0x37,0xd7,0xc6,0xdb,0xc0,0x90,0xd0,0xc2,0xd5,0x07,0xeb,0xc7,0x97,0x60,0xa4,0x60,0x47,0x9d, + 0x04,0x20,0xc9,0x2a,0x5e,0xe6,0xcc,0x54,0x34,0xca,0xda,0x96,0xc1,0x41,0x58,0x7b,0x47,0x48,0x1e,0xa1,0x0c,0xb2,0x59,0x2c,0x8c,0x23,0xec,0x5c,0x43,0x7f,0xd7,0x28,0x1c,0xd0,0x47,0x9d, + 0x04,0x20,0xc9,0xd0,0x9a,0x69,0xc1,0xba,0x0b,0x07,0xa4,0x22,0x67,0xaf,0x35,0x99,0x23,0x0b,0x8b,0xf4,0x9d,0xc2,0x9d,0x6d,0xbb,0xf7,0xf5,0x3a,0x0b,0x39,0x4c,0x3d,0x3a,0x36,0x47,0x9d, + 0x04,0x20,0xca,0x11,0xb7,0xed,0xeb,0x7c,0x27,0xbe,0x5e,0xe3,0xe3,0x23,0xf7,0x16,0xb5,0x45,0xda,0x87,0xcf,0xe8,0x53,0x8e,0x6a,0xa3,0x66,0x9a,0x56,0xdc,0xb8,0xa9,0x4e,0xfe,0x47,0x9d, + 0x04,0x20,0xca,0xa0,0x31,0xe6,0x88,0xeb,0xd5,0x18,0x55,0x29,0xd6,0x6d,0x22,0xf5,0x4b,0x6f,0xe5,0x35,0x85,0x96,0xeb,0xd8,0xdf,0x52,0x7c,0xf1,0x5c,0x1a,0xe7,0x15,0xd4,0x9b,0x47,0x9d, + 0x04,0x20,0xcb,0x2a,0x8c,0xe7,0xe5,0x1f,0x4e,0x3a,0x13,0xd6,0x9e,0xd7,0x68,0x51,0x83,0xf4,0x2d,0x3e,0x21,0x38,0x63,0x18,0xe9,0x97,0x27,0xff,0x45,0x48,0xc3,0x6c,0xca,0x59,0x47,0x9d, + 0x04,0x20,0xcb,0x2e,0xb8,0xe5,0xd7,0x37,0x0a,0xc9,0x3b,0xcb,0xd5,0xe9,0x0e,0xcc,0x77,0x62,0xf0,0x05,0x0e,0x04,0x5a,0xf3,0x44,0x9f,0x60,0xd6,0xd1,0x4c,0x9b,0x99,0x58,0x26,0x47,0x9d, + 0x04,0x20,0xcd,0x7a,0x43,0x28,0xac,0x1b,0xe8,0xd3,0x8d,0x9b,0xb1,0xc6,0x0b,0x9b,0x2f,0x40,0x1e,0x15,0x12,0x25,0x80,0xf5,0xc4,0xd2,0x1e,0xe7,0xce,0xcc,0x9c,0x82,0xfc,0x3f,0x47,0x9d, +}; + +static const uint8_t chainparams_seed_testnet4[] = { + 0x01,0x04,0x12,0xbd,0x9c,0x66,0xbc,0xcd, + 0x01,0x04,0x12,0xc9,0xcf,0x37,0xbc,0xcd, + 0x01,0x04,0x33,0x9e,0xf8,0x08,0xbc,0xcd, + 0x01,0x04,0x39,0x80,0xb0,0xa3,0xbc,0xcd, + 0x01,0x04,0x52,0x43,0x66,0x0f,0xbc,0xcd, + 0x01,0x04,0x58,0x63,0xf8,0x32,0xbc,0xcd, + 0x01,0x04,0x5f,0xd9,0x49,0xa2,0xbc,0xcd, + 0x01,0x04,0x67,0x63,0xab,0xd4,0xbc,0xcd, + 0x01,0x04,0x67,0xa5,0xc0,0xd2,0xbc,0xcd, }; #endif // BITCOIN_CHAINPARAMSSEEDS_H diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 6b9727a158..3943c4fb1d 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <clientversion.h> #include <util/string.h> @@ -13,6 +13,8 @@ #include <string> #include <vector> +using util::Join; + /** * Name of client reported in the 'version' message. Report the same name * for both bitcoind and bitcoin-qt, to make it harder for attackers to @@ -21,14 +23,12 @@ const std::string CLIENT_NAME("Satoshi"); -#ifdef HAVE_BUILD_INFO -#include <obj/build.h> -// The <obj/build.h>, which is generated by the build environment (share/genbuild.sh), +#include <bitcoin-build-info.h> +// The <bitcoin-build-info.h>, which is generated by the build environment (cmake/script/GenerateBuildInfo.cmake), // could contain only one line of the following: // - "#define BUILD_GIT_TAG ...", if the top commit is tagged // - "#define BUILD_GIT_COMMIT ...", if the top commit is not tagged // - "// No build information available", if proper git information is not available -#endif //! git will put "#define GIT_COMMIT_ID ..." on the next line inside archives. $Format:%n#define GIT_COMMIT_ID "%H"$ diff --git a/src/clientversion.h b/src/clientversion.h index 73aaf868e4..d1202b1259 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -7,11 +7,11 @@ #include <util/macros.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep // Check that required client information is defined #if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR) -#error Client version information missing: version is not defined by bitcoin-config.h or in any other way +#error Client version information missing: version is not defined by bitcoin-build-config.h or in any other way #endif //! Copyright string used in Windows .rc files diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h new file mode 100644 index 0000000000..757c81f108 --- /dev/null +++ b/src/cluster_linearize.h @@ -0,0 +1,1341 @@ +// 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 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. */ + std::vector<Entry> entries; + + /** Which positions are used. */ + SetType m_used; + +public: + /** Equality operator (primarily for testing purposes). */ + friend bool operator==(const DepGraph& a, const DepGraph& b) noexcept + { + if (a.m_used != b.m_used) return false; + // Only compare the used positions within the entries vector. + for (auto idx : a.m_used) { + if (a.entries[idx] != b.entries[idx]) return false; + } + return true; + } + + // 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 given another DepGraph and a mapping from old to new. + * + * @param depgraph The original DepGraph that is being remapped. + * + * @param mapping A Span such that mapping[i] gives the position in the new DepGraph + * for position i in the old depgraph. Its size must be equal to + * depgraph.PositionRange(). The value of mapping[i] is ignored if + * position i is a hole in depgraph (i.e., if !depgraph.Positions()[i]). + * + * @param pos_range The PositionRange() for the new DepGraph. It must equal the largest + * value in mapping for any used position in depgraph plus 1, or 0 if + * depgraph.TxCount() == 0. + * + * Complexity: O(N^2) where N=depgraph.TxCount(). + */ + DepGraph(const DepGraph<SetType>& depgraph, Span<const ClusterIndex> mapping, ClusterIndex pos_range) noexcept : entries(pos_range) + { + Assume(mapping.size() == depgraph.PositionRange()); + Assume((pos_range == 0) == (depgraph.TxCount() == 0)); + for (ClusterIndex i : depgraph.Positions()) { + auto new_idx = mapping[i]; + Assume(new_idx < pos_range); + // Add transaction. + entries[new_idx].ancestors = SetType::Singleton(new_idx); + entries[new_idx].descendants = SetType::Singleton(new_idx); + m_used.Set(new_idx); + // Fill in fee and size. + entries[new_idx].feerate = depgraph.entries[i].feerate; + } + for (ClusterIndex i : depgraph.Positions()) { + // Fill in dependencies by mapping direct parents. + SetType parents; + for (auto j : depgraph.GetReducedParents(i)) parents.Set(mapping[j]); + AddDependencies(parents, mapping[i]); + } + // Verify that the provided pos_range was correct (no unused positions at the end). + Assume(m_used.None() ? (pos_range == 0) : (pos_range == m_used.Last() + 1)); + } + + /** Get the set of transactions positions in use. Complexity: O(1). */ + const SetType& Positions() const noexcept { return m_used; } + /** Get the range of positions in this DepGraph. All entries in Positions() are in [0, PositionRange() - 1]. */ + ClusterIndex PositionRange() const noexcept { return entries.size(); } + /** Get the number of transactions in the graph. Complexity: O(1). */ + auto TxCount() const noexcept { return m_used.Count(); } + /** 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 (in the first available + * position), and return its ClusterIndex. + * + * Complexity: O(1) (amortized, due to resizing of backing vector). + */ + ClusterIndex AddTransaction(const FeeFrac& feefrac) noexcept + { + static constexpr auto ALL_POSITIONS = SetType::Fill(SetType::Size()); + auto available = ALL_POSITIONS - m_used; + Assume(available.Any()); + ClusterIndex new_idx = available.First(); + if (new_idx == entries.size()) { + entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx)); + } else { + entries[new_idx] = Entry(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx)); + } + m_used.Set(new_idx); + return new_idx; + } + + /** Remove the specified positions from this DepGraph. + * + * The specified positions will no longer be part of Positions(), and dependencies with them are + * removed. Note that due to DepGraph only tracking ancestors/descendants (and not direct + * dependencies), if a parent is removed while a grandparent remains, the grandparent will + * remain an ancestor. + * + * Complexity: O(N) where N=TxCount(). + */ + void RemoveTransactions(const SetType& del) noexcept + { + m_used -= del; + // Remove now-unused trailing entries. + while (!entries.empty() && !m_used[entries.size() - 1]) { + entries.pop_back(); + } + // Remove the deleted transactions from ancestors/descendants of other transactions. Note + // that the deleted positions will retain old feerate and dependency information. This does + // not matter as they will be overwritten by AddTransaction if they get used again. + for (auto& entry : entries) { + entry.ancestors &= m_used; + entry.descendants &= m_used; + } + } + + /** Modify this transaction graph, adding multiple parents to a specified child. + * + * Complexity: O(N) where N=TxCount(). + */ + void AddDependencies(const SetType& parents, ClusterIndex child) noexcept + { + Assume(m_used[child]); + Assume(parents.IsSubsetOf(m_used)); + // Compute the ancestors of parents that are not already ancestors of child. + SetType par_anc; + for (auto par : parents - Ancestors(child)) { + par_anc |= Ancestors(par); + } + par_anc -= Ancestors(child); + // Bail out if there are no such ancestors. + if (par_anc.None()) return; + // To each such ancestor, add as descendants the descendants of the child. + const auto& chl_des = entries[child].descendants; + for (auto anc_of_par : par_anc) { + entries[anc_of_par].descendants |= chl_des; + } + // To each descendant of the child, add those ancestors. + for (auto dec_of_chl : Descendants(child)) { + entries[dec_of_chl].ancestors |= par_anc; + } + } + + /** Compute the (reduced) set of parents of node i in this graph. + * + * This returns the minimal subset of the parents of i whose ancestors together equal all of + * i's ancestors (unless i is part of a cycle of dependencies). Note that DepGraph does not + * store the set of parents; this information is inferred from the ancestor sets. + * + * Complexity: O(N) where N=Ancestors(i).Count() (which is bounded by TxCount()). + */ + SetType GetReducedParents(ClusterIndex i) const noexcept + { + SetType parents = Ancestors(i); + parents.Reset(i); + for (auto parent : parents) { + if (parents[parent]) { + parents -= Ancestors(parent); + parents.Set(parent); + } + } + return parents; + } + + /** Compute the (reduced) set of children of node i in this graph. + * + * This returns the minimal subset of the children of i whose descendants together equal all of + * i's descendants (unless i is part of a cycle of dependencies). Note that DepGraph does not + * store the set of children; this information is inferred from the descendant sets. + * + * Complexity: O(N) where N=Descendants(i).Count() (which is bounded by TxCount()). + */ + SetType GetReducedChildren(ClusterIndex i) const noexcept + { + SetType children = Descendants(i); + children.Reset(i); + for (auto child : children) { + if (children[child]) { + children -= Descendants(child); + children.Set(child); + } + } + return children; + } + + /** 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(m_used); } + + /** 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 a transaction to this SetInfo (which must not yet be in it). */ + void Set(const DepGraph<SetType>& depgraph, ClusterIndex pos) noexcept + { + Assume(!transactions[pos]); + transactions.Set(pos); + feerate += depgraph.FeeRate(pos); + } + + /** 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{depgraph.Positions()}, + m_ancestor_set_feerates(depgraph.PositionRange()) + { + // Precompute ancestor-set feerates. + for (ClusterIndex i : m_depgraph.Positions()) { + /** 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(); + } + + /** Count the number of remaining unlinearized transactions. */ + ClusterIndex NumRemaining() const noexcept + { + return m_todo.Count(); + } + + /** 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; + /** m_sorted_to_original[i] is the original position that sorted transaction position i had. */ + std::vector<ClusterIndex> m_sorted_to_original; + /** m_original_to_sorted[i] is the sorted position original transaction position i has. */ + std::vector<ClusterIndex> m_original_to_sorted; + /** Internal dependency graph for the cluster (with transactions in decreasing individual + * feerate order). */ + DepGraph<SetType> m_sorted_depgraph; + /** Which transactions are left to do (indices in m_sorted_depgraph's order). */ + SetType m_todo; + + /** Given a set of transactions with sorted indices, get their original indices. */ + SetType SortedToOriginal(const SetType& arg) const noexcept + { + SetType ret; + for (auto pos : arg) ret.Set(m_sorted_to_original[pos]); + return ret; + } + + /** Given a set of transactions with original indices, get their sorted indices. */ + SetType OriginalToSorted(const SetType& arg) const noexcept + { + SetType ret; + for (auto pos : arg) ret.Set(m_original_to_sorted[pos]); + return ret; + } + +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(N^2) where N=depgraph.Count(). + */ + SearchCandidateFinder(const DepGraph<SetType>& depgraph, uint64_t rng_seed) noexcept : + m_rng(rng_seed), + m_sorted_to_original(depgraph.TxCount()), + m_original_to_sorted(depgraph.PositionRange()) + { + // Determine reordering mapping, by sorting by decreasing feerate. Unusued positions are + // not included, as they will never be looked up anyway. + ClusterIndex sorted_pos{0}; + for (auto i : depgraph.Positions()) { + m_sorted_to_original[sorted_pos++] = i; + } + std::sort(m_sorted_to_original.begin(), m_sorted_to_original.end(), [&](auto a, auto b) { + auto feerate_cmp = depgraph.FeeRate(a) <=> depgraph.FeeRate(b); + if (feerate_cmp == 0) return a < b; + return feerate_cmp > 0; + }); + // Compute reverse mapping. + for (ClusterIndex i = 0; i < m_sorted_to_original.size(); ++i) { + m_original_to_sorted[m_sorted_to_original[i]] = i; + } + // Compute reordered dependency graph. + m_sorted_depgraph = DepGraph(depgraph, m_original_to_sorted, m_sorted_to_original.size()); + m_todo = m_sorted_depgraph.Positions(); + } + + /** 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: possibly O(N * min(max_iterations, sqrt(2^N))) where N=depgraph.TxCount(). + */ + std::pair<SetInfo<SetType>, uint64_t> FindCandidateSet(uint64_t max_iterations, SetInfo<SetType> best) noexcept + { + Assume(!AllDone()); + + // Convert the provided best to internal sorted indices. + best.transactions = OriginalToSorted(best.transactions); + + /** 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; + /** (Only when inc is not empty) The best feerate of any superset of inc that is also a + * subset of (inc | und), without requiring it to be topologically valid. It forms a + * conservative upper bound on how good a set this work item can give rise to. + * Transactions whose feerate is below best's are ignored when determining this value, + * which means it may technically be an underestimate, but if so, this work item + * cannot result in something that beats best anyway. */ + FeeFrac pot_feerate; + + /** Construct a new work item. */ + WorkItem(SetInfo<SetType>&& i, SetType&& u, FeeFrac&& p_f) noexcept : + inc(std::move(i)), und(std::move(u)), pot_feerate(std::move(p_f)) + { + Assume(pot_feerate.IsEmpty() == inc.feerate.IsEmpty()); + } + + /** Swap two WorkItems. */ + void Swap(WorkItem& other) noexcept + { + swap(inc, other.inc); + swap(und, other.und); + swap(pot_feerate, other.pot_feerate); + } + }; + + /** The queue of work items. */ + VecDeque<WorkItem> queue; + queue.reserve(std::max<size_t>(256, 2 * m_todo.Count())); + + // Create initial entries per connected component of m_todo. While clusters themselves are + // generally connected, this is not necessarily true after some parts have already been + // removed from m_todo. Without this, effort can be wasted on searching "inc" sets that + // span multiple components. + auto to_cover = m_todo; + do { + auto component = m_sorted_depgraph.FindConnectedComponent(to_cover); + to_cover -= component; + // If best is not provided, set it to the first component, 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_sorted_depgraph, component); + queue.emplace_back(/*inc=*/SetInfo<SetType>{}, + /*und=*/std::move(component), + /*pot_feerate=*/FeeFrac{}); + } while (to_cover.Any()); + + /** Local copy of the iteration limit. */ + uint64_t iterations_left = max_iterations; + + /** The set of transactions in m_todo which have feerate > best's. */ + SetType imp = m_todo; + while (imp.Any()) { + ClusterIndex check = imp.Last(); + if (m_sorted_depgraph.FeeRate(check) >> best.feerate) break; + imp.Reset(check); + } + + /** Internal function to add an item to the queue of elements to explore if there are any + * transactions left to split on, possibly improving it before doing so, and to update + * best/imp. + * + * - 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 { + /** SetInfo object with the set whose feerate will become the new work item's + * pot_feerate. It starts off equal to inc. */ + auto pot = inc; + if (!inc.feerate.IsEmpty()) { + // Add entries to pot. We iterate over all undecided transactions whose feerate is + // higher than best. While undecided transactions of lower feerate may improve pot, + // the resulting pot feerate cannot possibly exceed best's (and this item will be + // skipped in split_fn anyway). + for (auto pos : imp & und) { + // Determine if adding transaction pos to pot (ignoring topology) would improve + // it. If not, we're done updating pot. This relies on the fact that + // m_sorted_depgraph, and thus the transactions iterated over, are in decreasing + // individual feerate order. + if (!(m_sorted_depgraph.FeeRate(pos) >> pot.feerate)) break; + pot.Set(m_sorted_depgraph, pos); + } + + // The "jump ahead" optimization: whenever pot has a topologically-valid subset, + // that subset can be added to inc. Any subset of (pot - inc) has the property that + // its feerate exceeds that of any set compatible with this work item (superset of + // inc, subset of (inc | und)). Thus, if T is a topological subset of pot, and B is + // the best topologically-valid set compatible with this work item, and (T - B) is + // non-empty, then (T | B) is better than B and also topological. This is in + // contradiction with the assumption that B is best. Thus, (T - B) must be empty, + // or T must be a subset of B. + // + // See https://delvingbitcoin.org/t/how-to-linearize-your-cluster/303 section 2.4. + const auto init_inc = inc.transactions; + for (auto pos : pot.transactions - inc.transactions) { + // If the transaction's ancestors are a subset of pot, we can add it together + // with its ancestors to inc. Just update the transactions here; the feerate + // update happens below. + auto anc_todo = m_sorted_depgraph.Ancestors(pos) & m_todo; + if (anc_todo.IsSubsetOf(pot.transactions)) inc.transactions |= anc_todo; + } + // Finally update und and inc's feerate to account for the added transactions. + und -= inc.transactions; + inc.feerate += m_sorted_depgraph.FeeRate(inc.transactions - init_inc); + + // If inc's feerate is better than best's, remember it as our new best. + if (inc.feerate > best.feerate) { + best = inc; + // See if we can remove any entries from imp now. + while (imp.Any()) { + ClusterIndex check = imp.Last(); + if (m_sorted_depgraph.FeeRate(check) >> best.feerate) break; + imp.Reset(check); + } + } + + // If no potential transactions exist beyond the already included ones, no + // improvement is possible anymore. + if (pot.feerate.size == inc.feerate.size) return; + // At this point und must be non-empty. If it were empty then pot would equal inc. + Assume(und.Any()); + } else { + Assume(inc.transactions.None()); + // If inc is empty, we just 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(/*inc=*/std::move(inc), + /*und=*/std::move(und), + /*pot_feerate=*/std::move(pot.feerate)); + }; + + /** 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)); + // If pot is empty, then so is inc. + Assume(elem.inc.feerate.IsEmpty() == elem.pot_feerate.IsEmpty()); + + const ClusterIndex first = elem.und.First(); + if (!elem.inc.feerate.IsEmpty()) { + // If no undecided transactions remain with feerate higher than best, this entry + // cannot be improved beyond best. + if (!elem.und.Overlaps(imp)) return; + // We can ignore any queue item whose potential feerate isn't better than the best + // seen so far. + if (elem.pot_feerate <= best.feerate) return; + } else { + // In case inc is empty use a simpler alternative check. + if (m_sorted_depgraph.FeeRate(first) <= best.feerate) return; + } + + // Decide which transaction to split on. Splitting is how new work items are added, and + // how progress is made. One split transaction is chosen among the queue item's + // undecided ones, and: + // - A work item is (potentially) added with that transaction plus its remaining + // descendants excluded (removed from the und set). + // - A work item is (potentially) added with that transaction plus its remaining + // ancestors included (added to the inc set). + // + // To decide what to split on, consider the undecided ancestors of the highest + // individual feerate undecided transaction. Pick the one which reduces the search space + // most. Let I(t) be the size of the undecided set after including t, and E(t) the size + // of the undecided set after excluding t. Then choose the split transaction t such + // that 2^I(t) + 2^E(t) is minimal, tie-breaking by highest individual feerate for t. + ClusterIndex split = 0; + const auto select = elem.und & m_sorted_depgraph.Ancestors(first); + Assume(select.Any()); + std::optional<std::pair<ClusterIndex, ClusterIndex>> split_counts; + for (auto t : select) { + // Call max = max(I(t), E(t)) and min = min(I(t), E(t)). Let counts = {max,min}. + // Sorting by the tuple counts is equivalent to sorting by 2^I(t) + 2^E(t). This + // expression is equal to 2^max + 2^min = 2^max * (1 + 1/2^(max - min)). The second + // factor (1 + 1/2^(max - min)) there is in (1,2]. Thus increasing max will always + // increase it, even when min decreases. Because of this, we can first sort by max. + std::pair<ClusterIndex, ClusterIndex> counts{ + (elem.und - m_sorted_depgraph.Ancestors(t)).Count(), + (elem.und - m_sorted_depgraph.Descendants(t)).Count()}; + if (counts.first < counts.second) std::swap(counts.first, counts.second); + // Remember the t with the lowest counts. + if (!split_counts.has_value() || counts < *split_counts) { + split = t; + split_counts = counts; + } + } + // Since there was at least one transaction in select, we must always find one. + Assume(split_counts.has_value()); + + // Add a work item corresponding to exclusion of the split transaction. + const auto& desc = m_sorted_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_sorted_depgraph.Ancestors(split) & m_todo; + add_fn(/*inc=*/elem.inc.Add(m_sorted_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 (converted to the original transaction indices), and the + // number of iterations performed. + best.transactions = SortedToOriginal(best.transactions); + 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 + { + const auto done_sorted = OriginalToSorted(done); + Assume(done_sorted.Any()); + Assume(done_sorted.IsSubsetOf(m_todo)); + m_todo -= done_sorted; + } +}; + +/** 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: possibly O(N * min(max_iterations + N, sqrt(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); + std::optional<SearchCandidateFinder<SetType>> src_finder; + linearization.reserve(depgraph.TxCount()); + bool optimal = true; + + // Treat the initialization of SearchCandidateFinder as taking N^2/64 (rounded up) iterations + // (largely due to the cost of constructing the internal sorted-by-feerate DepGraph inside + // SearchCandidateFinder), a rough approximation based on benchmark. If we don't have that + // many, don't start it. + uint64_t start_iterations = (uint64_t{depgraph.TxCount()} * depgraph.TxCount() + 63) / 64; + if (iterations_left > start_iterations) { + iterations_left -= start_iterations; + src_finder.emplace(depgraph, rng_seed); + } + + /** 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; + + uint64_t iterations_done_now = 0; + uint64_t max_iterations_now = 0; + if (src_finder) { + // Treat the invocation of SearchCandidateFinder::FindCandidateSet() as costing N/4 + // up-front (rounded up) iterations (largely due to the cost of connected-component + // splitting), a rough approximation based on benchmarks. + uint64_t base_iterations = (anc_finder.NumRemaining() + 3) / 4; + if (iterations_left > base_iterations) { + // Invoke bounded search to update best, with up to half of our remaining + // iterations as limit. + iterations_left -= base_iterations; + max_iterations_now = (iterations_left + 1) / 2; + 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; + if (src_finder) 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(depgraph.PositionRange() + 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 b62653e0de..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); } @@ -361,7 +372,7 @@ static bool ExecuteBackedWrapper(Func func, const std::vector<std::function<void for (const auto& f : err_callbacks) { f(); } - LogPrintf("Error reading from database: %s\n", e.what()); + LogError("Error reading from database: %s\n", e.what()); // Starting the shutdown sequence and returning false to the caller would be // interpreted as 'entry not found' (as opposed to unable to read data), and // could lead to invalid interpretation. Just exit immediately, as we can't 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..f59d2b8f0f 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -16,6 +16,7 @@ #include <util/fs.h> #include <util/fs_helpers.h> #include <util/strencodings.h> +#include <util/string.h> #ifdef WIN32 #include <codecvt> /* for codecvt_utf8_utf16 */ @@ -159,6 +160,7 @@ std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const ChainTypeToString(ChainType::REGTEST), ChainTypeToString(ChainType::SIGNET), ChainTypeToString(ChainType::TESTNET), + ChainTypeToString(ChainType::TESTNET4), ChainTypeToString(ChainType::MAIN), }; @@ -587,6 +589,23 @@ void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names) } } +void ArgsManager::CheckMultipleCLIArgs() const +{ + LOCK(cs_args); + std::vector<std::string> found{}; + auto cmds = m_available_args.find(OptionsCategory::CLI_COMMANDS); + if (cmds != m_available_args.end()) { + for (const auto& [cmd, argspec] : cmds->second) { + if (IsArgSet(cmd)) { + found.push_back(cmd); + } + } + if (found.size() > 1) { + throw std::runtime_error(strprintf("Only one of %s may be specified.", util::Join(found, ", "))); + } + } +} + std::string ArgsManager::GetHelpMessage() const { const bool show_debug = GetBoolArg("-help-debug", false); @@ -616,6 +635,9 @@ std::string ArgsManager::GetHelpMessage() const case OptionsCategory::RPC: usage += HelpMessageGroup("RPC server options:"); break; + case OptionsCategory::IPC: + usage += HelpMessageGroup("IPC interprocess connection options:"); + break; case OptionsCategory::WALLET: usage += HelpMessageGroup("Wallet options:"); break; @@ -634,6 +656,9 @@ std::string ArgsManager::GetHelpMessage() const case OptionsCategory::REGISTER_COMMANDS: usage += HelpMessageGroup("Register Commands:"); break; + case OptionsCategory::CLI_COMMANDS: + usage += HelpMessageGroup("CLI Commands:"); + break; default: break; } @@ -773,10 +798,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 +812,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..8d9daf5f65 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -63,6 +63,8 @@ enum class OptionsCategory { GUI, COMMANDS, REGISTER_COMMANDS, + CLI_COMMANDS, + IPC, HIDDEN // Always the last option to avoid printing these in the help }; @@ -364,6 +366,13 @@ protected: } /** + * Check CLI command args + * + * @throws std::runtime_error when multiple CLI_COMMAND arguments are specified + */ + void CheckMultipleCLIArgs() const; + + /** * Get the help string */ std::string GetHelpMessage() const; @@ -423,7 +432,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/config.cpp b/src/common/config.cpp index 1c85273f69..98223fc3e3 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -27,6 +27,9 @@ #include <utility> #include <vector> +using util::TrimString; +using util::TrimStringView; + static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections) { std::string str, prefix; diff --git a/src/common/messages.cpp b/src/common/messages.cpp new file mode 100644 index 0000000000..5fe3e9e4d8 --- /dev/null +++ b/src/common/messages.cpp @@ -0,0 +1,167 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <common/messages.h> + +#include <common/types.h> +#include <policy/fees.h> +#include <node/types.h> +#include <tinyformat.h> +#include <util/strencodings.h> +#include <util/string.h> +#include <util/translation.h> + +#include <cassert> +#include <map> +#include <string> +#include <utility> +#include <vector> + +using node::TransactionError; +using util::Join; + +namespace common { +std::string StringForFeeReason(FeeReason reason) +{ + static const std::map<FeeReason, std::string> fee_reason_strings = { + {FeeReason::NONE, "None"}, + {FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"}, + {FeeReason::FULL_ESTIMATE, "Target 85% Threshold"}, + {FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"}, + {FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"}, + {FeeReason::MEMPOOL_MIN, "Mempool Min Fee"}, + {FeeReason::PAYTXFEE, "PayTxFee set"}, + {FeeReason::FALLBACK, "Fallback fee"}, + {FeeReason::REQUIRED, "Minimum Required Fee"}, + }; + auto reason_string = fee_reason_strings.find(reason); + + if (reason_string == fee_reason_strings.end()) return "Unknown"; + + return reason_string->second; +} + +const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap() +{ + static const std::vector<std::pair<std::string, FeeEstimateMode>> FEE_MODES = { + {"unset", FeeEstimateMode::UNSET}, + {"economical", FeeEstimateMode::ECONOMICAL}, + {"conservative", FeeEstimateMode::CONSERVATIVE}, + }; + 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; }); +} + +std::string InvalidEstimateModeErrorMessage() +{ + return "Invalid estimate_mode parameter, must be one of: \"" + FeeModes("\", \"") + "\""; +} + +bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) +{ + auto searchkey = ToUpper(mode_string); + for (const auto& pair : FeeModeMap()) { + if (ToUpper(pair.first) == searchkey) { + fee_estimate_mode = pair.second; + return true; + } + } + return false; +} + +bilingual_str PSBTErrorString(PSBTError err) +{ + switch (err) { + case PSBTError::MISSING_INPUTS: + return Untranslated("Inputs missing or spent"); + case PSBTError::SIGHASH_MISMATCH: + return Untranslated("Specified sighash value does not match value stored in PSBT"); + case PSBTError::EXTERNAL_SIGNER_NOT_FOUND: + return Untranslated("External signer not found"); + case PSBTError::EXTERNAL_SIGNER_FAILED: + return Untranslated("External signer failed to sign"); + case PSBTError::UNSUPPORTED: + return Untranslated("Signer does not support PSBT"); + // no default case, so the compiler can warn about missing cases + } + assert(false); +} + +bilingual_str TransactionErrorString(const TransactionError err) +{ + switch (err) { + case TransactionError::OK: + return Untranslated("No error"); + case TransactionError::MISSING_INPUTS: + return Untranslated("Inputs missing or spent"); + 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: + return Untranslated("Mempool internal error"); + case TransactionError::MAX_FEE_EXCEEDED: + return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"); + case TransactionError::MAX_BURN_EXCEEDED: + return Untranslated("Unspendable output exceeds maximum configured by user (maxburnamount)"); + case TransactionError::INVALID_PACKAGE: + return Untranslated("Transaction rejected due to invalid package"); + // no default case, so the compiler can warn about missing cases + } + assert(false); +} + +bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind) +{ + return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); +} + +bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& invalid_value) +{ + return strprintf(_("Invalid port specified in %s: '%s'"), optname, invalid_value); +} + +bilingual_str AmountHighWarn(const std::string& optname) +{ + return strprintf(_("%s is set very high!"), optname); +} + +bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue) +{ + return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue); +} +} // namespace common diff --git a/src/common/messages.h b/src/common/messages.h new file mode 100644 index 0000000000..5827fccee0 --- /dev/null +++ b/src/common/messages.h @@ -0,0 +1,40 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +//! @file common/messages.h is a home for simple string functions returning +//! descriptive messages that are used in RPC and GUI interfaces or log +//! messages, and are called in different parts of the codebase across +//! node/wallet/gui boundaries. + +#ifndef BITCOIN_COMMON_MESSAGES_H +#define BITCOIN_COMMON_MESSAGES_H + +#include <string> + +struct bilingual_str; + +enum class FeeEstimateMode; +enum class FeeReason; +namespace node { +enum class TransactionError; +} // namespace node + +namespace common { +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); +bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind); +bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& strPort); +bilingual_str AmountHighWarn(const std::string& optname); +bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue); +} // namespace common + +#endif // BITCOIN_COMMON_MESSAGES_H diff --git a/src/common/netif.cpp b/src/common/netif.cpp new file mode 100644 index 0000000000..08f034a412 --- /dev/null +++ b/src/common/netif.cpp @@ -0,0 +1,303 @@ +// Copyright (c) 2024 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#include <bitcoin-build-config.h> // IWYU pragma: keep + +#include <common/netif.h> + +#include <logging.h> +#include <netbase.h> +#include <util/check.h> +#include <util/sock.h> +#include <util/syserror.h> + +#if defined(__linux__) +#include <linux/rtnetlink.h> +#elif defined(__FreeBSD__) +#include <osreldate.h> +#if __FreeBSD_version >= 1400000 +// Workaround https://github.com/freebsd/freebsd-src/pull/1070. +#define typeof __typeof +#include <netlink/netlink.h> +#include <netlink/netlink_route.h> +#endif +#elif defined(WIN32) +#include <iphlpapi.h> +#elif defined(__APPLE__) +#include <net/route.h> +#include <sys/sysctl.h> +#endif + +namespace { + +// Linux and FreeBSD 14.0+. For FreeBSD 13.2 the code can be compiled but +// running it requires loading a special kernel module, otherwise socket(AF_NETLINK,...) +// will fail, so we skip that. +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1400000) + +std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family) +{ + // Create a netlink socket. + auto sock{CreateSock(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)}; + if (!sock) { + LogPrintLevel(BCLog::NET, BCLog::Level::Error, "socket(AF_NETLINK): %s\n", NetworkErrorString(errno)); + return std::nullopt; + } + + // Send request. + struct { + nlmsghdr hdr; ///< Request header. + rtmsg data; ///< Request data, a "route message". + nlattr dst_hdr; ///< One attribute, conveying the route destination address. + char dst_data[16]; ///< Route destination address. To query the default route we use 0.0.0.0/0 or [::]/0. For IPv4 the first 4 bytes are used. + } request{}; + + // Whether to use the first 4 or 16 bytes from request.dst_data. + const size_t dst_data_len = family == AF_INET ? 4 : 16; + + request.hdr.nlmsg_type = RTM_GETROUTE; + request.hdr.nlmsg_flags = NLM_F_REQUEST; +#ifdef __linux__ + // Linux IPv4 / IPv6 - this must be present, otherwise no gateway is found + // FreeBSD IPv4 - does not matter, the gateway is found with or without this + // FreeBSD IPv6 - this must be absent, otherwise no gateway is found + request.hdr.nlmsg_flags |= NLM_F_DUMP; +#endif + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg) + sizeof(nlattr) + dst_data_len); + request.hdr.nlmsg_seq = 0; // Sequence number, used to match which reply is to which request. Irrelevant for us because we send just one request. + request.data.rtm_family = family; + request.data.rtm_dst_len = 0; // Prefix length. +#ifdef __FreeBSD__ + // Linux IPv4 / IPv6 this must be absent, otherwise no gateway is found + // FreeBSD IPv4 - does not matter, the gateway is found with or without this + // FreeBSD IPv6 - this must be present, otherwise no gateway is found + request.data.rtm_flags = RTM_F_PREFIX; +#endif + request.dst_hdr.nla_type = RTA_DST; + request.dst_hdr.nla_len = sizeof(nlattr) + dst_data_len; + + if (sock->Send(&request, request.hdr.nlmsg_len, 0) != static_cast<ssize_t>(request.hdr.nlmsg_len)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Error, "send() to netlink socket: %s\n", NetworkErrorString(errno)); + return std::nullopt; + } + + // Receive response. + char response[4096]; + int64_t recv_result; + do { + recv_result = sock->Recv(response, sizeof(response), 0); + } while (recv_result < 0 && (errno == EINTR || errno == EAGAIN)); + if (recv_result < 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Error, "recv() from netlink socket: %s\n", NetworkErrorString(errno)); + return std::nullopt; + } + + for (nlmsghdr* hdr = (nlmsghdr*)response; NLMSG_OK(hdr, recv_result); hdr = NLMSG_NEXT(hdr, recv_result)) { + rtmsg* r = (rtmsg*)NLMSG_DATA(hdr); + int remaining_len = RTM_PAYLOAD(hdr); + + // Iterate over the attributes. + rtattr *rta_gateway = nullptr; + int scope_id = 0; + for (rtattr* attr = RTM_RTA(r); RTA_OK(attr, remaining_len); attr = RTA_NEXT(attr, remaining_len)) { + if (attr->rta_type == RTA_GATEWAY) { + rta_gateway = attr; + } else if (attr->rta_type == RTA_OIF && sizeof(int) == RTA_PAYLOAD(attr)) { + std::memcpy(&scope_id, RTA_DATA(attr), sizeof(scope_id)); + } + } + + // Found gateway? + if (rta_gateway != nullptr) { + if (family == AF_INET && sizeof(in_addr) == RTA_PAYLOAD(rta_gateway)) { + in_addr gw; + std::memcpy(&gw, RTA_DATA(rta_gateway), sizeof(gw)); + return CNetAddr(gw); + } else if (family == AF_INET6 && sizeof(in6_addr) == RTA_PAYLOAD(rta_gateway)) { + in6_addr gw; + std::memcpy(&gw, RTA_DATA(rta_gateway), sizeof(gw)); + return CNetAddr(gw, scope_id); + } + } + } + + return std::nullopt; +} + +#elif defined(WIN32) + +std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family) +{ + NET_LUID interface_luid = {}; + SOCKADDR_INET destination_address = {}; + MIB_IPFORWARD_ROW2 best_route = {}; + SOCKADDR_INET best_source_address = {}; + DWORD best_if_idx = 0; + DWORD status = 0; + + // Pass empty destination address of the requested type (:: or 0.0.0.0) to get interface of default route. + destination_address.si_family = family; + status = GetBestInterfaceEx((sockaddr*)&destination_address, &best_if_idx); + if (status != NO_ERROR) { + LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Could not get best interface for default route: %s\n", NetworkErrorString(status)); + return std::nullopt; + } + + // Get best route to default gateway. + // Leave interface_luid at all-zeros to use interface index instead. + status = GetBestRoute2(&interface_luid, best_if_idx, nullptr, &destination_address, 0, &best_route, &best_source_address); + if (status != NO_ERROR) { + LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Could not get best route for default route for interface index %d: %s\n", + best_if_idx, NetworkErrorString(status)); + return std::nullopt; + } + + Assume(best_route.NextHop.si_family == family); + if (family == AF_INET) { + return CNetAddr(best_route.NextHop.Ipv4.sin_addr); + } else if(family == AF_INET6) { + return CNetAddr(best_route.NextHop.Ipv6.sin6_addr, best_route.InterfaceIndex); + } + return std::nullopt; +} + +#elif defined(__APPLE__) + +#define ROUNDUP32(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) + +std::optional<CNetAddr> FromSockAddr(const struct sockaddr* addr) +{ + // Check valid length. Note that sa_len is not part of POSIX, and exists on MacOS and some BSDs only, so we can't + // do this check in SetSockAddr. + if (!(addr->sa_family == AF_INET && addr->sa_len == sizeof(struct sockaddr_in)) && + !(addr->sa_family == AF_INET6 && addr->sa_len == sizeof(struct sockaddr_in6))) { + return std::nullopt; + } + + // Fill in a CService from the sockaddr, then drop the port part. + CService service; + if (service.SetSockAddr(addr)) { + return (CNetAddr)service; + } + return std::nullopt; +} + +//! MacOS: Get default gateway from route table. See route(4) for the format. +std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family) +{ + // net.route.0.inet[6].flags.gateway + int mib[] = {CTL_NET, PF_ROUTE, 0, family, NET_RT_FLAGS, RTF_GATEWAY}; + // The size of the available data is determined by calling sysctl() with oldp=nullptr. See sysctl(3). + size_t l = 0; + if (sysctl(/*name=*/mib, /*namelen=*/sizeof(mib) / sizeof(int), /*oldp=*/nullptr, /*oldlenp=*/&l, /*newp=*/nullptr, /*newlen=*/0) < 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Could not get sysctl length of routing table: %s\n", SysErrorString(errno)); + return std::nullopt; + } + std::vector<std::byte> buf(l); + if (sysctl(/*name=*/mib, /*namelen=*/sizeof(mib) / sizeof(int), /*oldp=*/buf.data(), /*oldlenp=*/&l, /*newp=*/nullptr, /*newlen=*/0) < 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Could not get sysctl data of routing table: %s\n", SysErrorString(errno)); + return std::nullopt; + } + // Iterate over messages (each message is a routing table entry). + for (size_t msg_pos = 0; msg_pos < buf.size(); ) { + if ((msg_pos + sizeof(rt_msghdr)) > buf.size()) return std::nullopt; + const struct rt_msghdr* rt = (const struct rt_msghdr*)(buf.data() + msg_pos); + const size_t next_msg_pos = msg_pos + rt->rtm_msglen; + if (rt->rtm_msglen < sizeof(rt_msghdr) || next_msg_pos > buf.size()) return std::nullopt; + // Iterate over addresses within message, get destination and gateway (if present). + // Address data starts after header. + size_t sa_pos = msg_pos + sizeof(struct rt_msghdr); + std::optional<CNetAddr> dst, gateway; + for (int i = 0; i < RTAX_MAX; i++) { + if (rt->rtm_addrs & (1 << i)) { + // 2 is just sa_len + sa_family, the theoretical minimum size of a socket address. + if ((sa_pos + 2) > next_msg_pos) return std::nullopt; + const struct sockaddr* sa = (const struct sockaddr*)(buf.data() + sa_pos); + if ((sa_pos + sa->sa_len) > next_msg_pos) return std::nullopt; + if (i == RTAX_DST) { + dst = FromSockAddr(sa); + } else if (i == RTAX_GATEWAY) { + gateway = FromSockAddr(sa); + } + // Skip sockaddr entries for bit flags we're not interested in, + // move cursor. + sa_pos += ROUNDUP32(sa->sa_len); + } + } + // Found default gateway? + if (dst && gateway && dst->IsBindAny()) { // Route to 0.0.0.0 or :: ? + return *gateway; + } + // Skip to next message. + msg_pos = next_msg_pos; + } + return std::nullopt; +} + +#else + +// Dummy implementation. +std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t) +{ + return std::nullopt; +} + +#endif + +} + +std::optional<CNetAddr> QueryDefaultGateway(Network network) +{ + Assume(network == NET_IPV4 || network == NET_IPV6); + + sa_family_t family; + if (network == NET_IPV4) { + family = AF_INET; + } else if(network == NET_IPV6) { + family = AF_INET6; + } else { + return std::nullopt; + } + + std::optional<CNetAddr> ret = QueryDefaultGatewayImpl(family); + + // It's possible for the default gateway to be 0.0.0.0 or ::0 on at least Windows + // for some routing strategies. If so, return as if no default gateway was found. + if (ret && !ret->IsBindAny()) { + return ret; + } else { + return std::nullopt; + } +} + +std::vector<CNetAddr> GetLocalAddresses() +{ + std::vector<CNetAddr> addresses; +#ifdef WIN32 + char pszHostName[256] = ""; + if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { + addresses = LookupHost(pszHostName, 0, true); + } +#elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS) + struct ifaddrs* myaddrs; + if (getifaddrs(&myaddrs) == 0) { + for (struct ifaddrs* ifa = myaddrs; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == nullptr) continue; + if ((ifa->ifa_flags & IFF_UP) == 0) continue; + if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) continue; + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); + addresses.emplace_back(s4->sin_addr); + } else if (ifa->ifa_addr->sa_family == AF_INET6) { + struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); + addresses.emplace_back(s6->sin6_addr); + } + } + freeifaddrs(myaddrs); + } +#endif + return addresses; +} diff --git a/src/common/netif.h b/src/common/netif.h new file mode 100644 index 0000000000..55bc023be6 --- /dev/null +++ b/src/common/netif.h @@ -0,0 +1,19 @@ +// Copyright (c) 2024 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMMON_NETIF_H +#define BITCOIN_COMMON_NETIF_H + +#include <netaddress.h> + +#include <optional> + +//! Query the OS for the default gateway for `network`. This only makes sense for NET_IPV4 and NET_IPV6. +//! Returns std::nullopt if it cannot be found, or there is no support for this OS. +std::optional<CNetAddr> QueryDefaultGateway(Network network); + +//! Return all local non-loopback IPv4 and IPv6 network addresses. +std::vector<CNetAddr> GetLocalAddresses(); + +#endif // BITCOIN_COMMON_NETIF_H diff --git a/src/common/pcp.cpp b/src/common/pcp.cpp new file mode 100644 index 0000000000..3cc1cba924 --- /dev/null +++ b/src/common/pcp.cpp @@ -0,0 +1,524 @@ +// Copyright (c) 2024 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#include <common/pcp.h> + +#include <common/netif.h> +#include <crypto/common.h> +#include <logging.h> +#include <netaddress.h> +#include <netbase.h> +#include <random.h> +#include <span.h> +#include <util/check.h> +#include <util/readwritefile.h> +#include <util/sock.h> +#include <util/strencodings.h> + +namespace { + +// RFC6886 NAT-PMP and RFC6887 Port Control Protocol (PCP) implementation. +// NAT-PMP and PCP use network byte order (big-endian). + +// NAT-PMP (v0) protocol constants. +//! NAT-PMP uses a fixed server port number (RFC6887 section 1.1). +constexpr uint16_t NATPMP_SERVER_PORT = 5351; +//! Version byte for NATPMP (RFC6886 1.1) +constexpr uint8_t NATPMP_VERSION = 0; +//! Request opcode base (RFC6886 3). +constexpr uint8_t NATPMP_REQUEST = 0x00; +//! Response opcode base (RFC6886 3). +constexpr uint8_t NATPMP_RESPONSE = 0x80; +//! Get external address (RFC6886 3.2) +constexpr uint8_t NATPMP_OP_GETEXTERNAL = 0x00; +//! Map TCP port (RFC6886 3.3) +constexpr uint8_t NATPMP_OP_MAP_TCP = 0x02; +//! Shared request header size in bytes. +constexpr size_t NATPMP_REQUEST_HDR_SIZE = 2; +//! Shared response header (minimum) size in bytes. +constexpr size_t NATPMP_RESPONSE_HDR_SIZE = 8; +//! GETEXTERNAL request size in bytes, including header (RFC6886 3.2). +constexpr size_t NATPMP_GETEXTERNAL_REQUEST_SIZE = NATPMP_REQUEST_HDR_SIZE + 0; +//! GETEXTERNAL response size in bytes, including header (RFC6886 3.2). +constexpr size_t NATPMP_GETEXTERNAL_RESPONSE_SIZE = NATPMP_RESPONSE_HDR_SIZE + 4; +//! MAP request size in bytes, including header (RFC6886 3.3). +constexpr size_t NATPMP_MAP_REQUEST_SIZE = NATPMP_REQUEST_HDR_SIZE + 10; +//! MAP response size in bytes, including header (RFC6886 3.3). +constexpr size_t NATPMP_MAP_RESPONSE_SIZE = NATPMP_RESPONSE_HDR_SIZE + 8; + +// Shared header offsets (RFC6886 3.2, 3.3), relative to start of packet. +//! Offset of version field in packets. +constexpr size_t NATPMP_HDR_VERSION_OFS = 0; +//! Offset of opcode field in packets +constexpr size_t NATPMP_HDR_OP_OFS = 1; +//! Offset of result code in packets. Result codes are 16 bit in NAT-PMP instead of 8 bit in PCP. +constexpr size_t NATPMP_RESPONSE_HDR_RESULT_OFS = 2; + +// GETEXTERNAL response offsets (RFC6886 3.2), relative to start of packet. +//! Returned external address +constexpr size_t NATPMP_GETEXTERNAL_RESPONSE_IP_OFS = 8; + +// MAP request offsets (RFC6886 3.3), relative to start of packet. +//! Internal port to be mapped. +constexpr size_t NATPMP_MAP_REQUEST_INTERNAL_PORT_OFS = 4; +//! Suggested external port for mapping. +constexpr size_t NATPMP_MAP_REQUEST_EXTERNAL_PORT_OFS = 6; +//! Requested port mapping lifetime in seconds. +constexpr size_t NATPMP_MAP_REQUEST_LIFETIME_OFS = 8; + +// MAP response offsets (RFC6886 3.3), relative to start of packet. +//! Internal port for mapping (will match internal port of request). +constexpr size_t NATPMP_MAP_RESPONSE_INTERNAL_PORT_OFS = 8; +//! External port for mapping. +constexpr size_t NATPMP_MAP_RESPONSE_EXTERNAL_PORT_OFS = 10; +//! Created port mapping lifetime in seconds. +constexpr size_t NATPMP_MAP_RESPONSE_LIFETIME_OFS = 12; + +// Relevant NETPMP result codes (RFC6886 3.5). +//! Result code representing success status. +constexpr uint8_t NATPMP_RESULT_SUCCESS = 0; +//! Result code representing unsupported version. +constexpr uint8_t NATPMP_RESULT_UNSUPP_VERSION = 1; +//! Result code representing lack of resources. +constexpr uint8_t NATPMP_RESULT_NO_RESOURCES = 4; + +//! Mapping of NATPMP result code to string (RFC6886 3.5). Result codes <=2 match PCP. +const std::map<uint8_t, std::string> NATPMP_RESULT_STR{ + {0, "SUCCESS"}, + {1, "UNSUPP_VERSION"}, + {2, "NOT_AUTHORIZED"}, + {3, "NETWORK_FAILURE"}, + {4, "NO_RESOURCES"}, + {5, "UNSUPP_OPCODE"}, +}; + +// PCP (v2) protocol constants. +//! Maximum packet size in bytes (RFC6887 section 7). +constexpr size_t PCP_MAX_SIZE = 1100; +//! PCP uses a fixed server port number (RFC6887 section 19.1). Shared with NAT-PMP. +constexpr uint16_t PCP_SERVER_PORT = NATPMP_SERVER_PORT; +//! Version byte. 0 is NAT-PMP (RFC6886), 1 is forbidden, 2 for PCP (RFC6887). +constexpr uint8_t PCP_VERSION = 2; +//! PCP Request Header. See RFC6887 section 7.1. Shared with NAT-PMP. +constexpr uint8_t PCP_REQUEST = NATPMP_REQUEST; // R = 0 +//! PCP Response Header. See RFC6887 section 7.2. Shared with NAT-PMP. +constexpr uint8_t PCP_RESPONSE = NATPMP_RESPONSE; // R = 1 +//! Map opcode. See RFC6887 section 19.2 +constexpr uint8_t PCP_OP_MAP = 0x01; +//! TCP protocol number (IANA). +constexpr uint16_t PCP_PROTOCOL_TCP = 6; +//! Request and response header size in bytes (RFC6887 section 7.1). +constexpr size_t PCP_HDR_SIZE = 24; +//! Map request and response size in bytes (RFC6887 section 11.1). +constexpr size_t PCP_MAP_SIZE = 36; + +// Header offsets shared between request and responses (RFC6887 7.1, 7.2), relative to start of packet. +//! Version field (1 byte). +constexpr size_t PCP_HDR_VERSION_OFS = NATPMP_HDR_VERSION_OFS; +//! Opcode field (1 byte). +constexpr size_t PCP_HDR_OP_OFS = NATPMP_HDR_OP_OFS; +//! Requested lifetime (request), granted lifetime (response) (4 bytes). +constexpr size_t PCP_HDR_LIFETIME_OFS = 4; + +// Request header offsets (RFC6887 7.1), relative to start of packet. +//! PCP client's IP address (16 bytes). +constexpr size_t PCP_REQUEST_HDR_IP_OFS = 8; + +// Response header offsets (RFC6887 7.2), relative to start of packet. +//! Result code (1 byte). +constexpr size_t PCP_RESPONSE_HDR_RESULT_OFS = 3; + +// MAP request/response offsets (RFC6887 11.1), relative to start of opcode-specific data. +//! Mapping nonce (12 bytes). +constexpr size_t PCP_MAP_NONCE_OFS = 0; +//! Protocol (1 byte). +constexpr size_t PCP_MAP_PROTOCOL_OFS = 12; +//! Internal port for mapping (2 bytes). +constexpr size_t PCP_MAP_INTERNAL_PORT_OFS = 16; +//! Suggested external port (request), assigned external port (response) (2 bytes). +constexpr size_t PCP_MAP_EXTERNAL_PORT_OFS = 18; +//! Suggested external IP (request), assigned external IP (response) (16 bytes). +constexpr size_t PCP_MAP_EXTERNAL_IP_OFS = 20; + +//! Result code representing success (RFC6887 7.4), shared with NAT-PMP. +constexpr uint8_t PCP_RESULT_SUCCESS = NATPMP_RESULT_SUCCESS; +//! Result code representing lack of resources (RFC6887 7.4). +constexpr uint8_t PCP_RESULT_NO_RESOURCES = 8; + +//! Mapping of PCP result code to string (RFC6887 7.4). Result codes <=2 match NAT-PMP. +const std::map<uint8_t, std::string> PCP_RESULT_STR{ + {0, "SUCCESS"}, + {1, "UNSUPP_VERSION"}, + {2, "NOT_AUTHORIZED"}, + {3, "MALFORMED_REQUEST"}, + {4, "UNSUPP_OPCODE"}, + {5, "UNSUPP_OPTION"}, + {6, "MALFORMED_OPTION"}, + {7, "NETWORK_FAILURE"}, + {8, "NO_RESOURCES"}, + {9, "UNSUPP_PROTOCOL"}, + {10, "USER_EX_QUOTA"}, + {11, "CANNOT_PROVIDE_EXTERNAL"}, + {12, "ADDRESS_MISMATCH"}, + {13, "EXCESSIVE_REMOTE_PEER"}, +}; + +//! Return human-readable string from NATPMP result code. +std::string NATPMPResultString(uint8_t result_code) +{ + auto result_i = NATPMP_RESULT_STR.find(result_code); + return strprintf("%s (code %d)", result_i == NATPMP_RESULT_STR.end() ? "(unknown)" : result_i->second, result_code); +} + +//! Return human-readable string from PCP result code. +std::string PCPResultString(uint8_t result_code) +{ + auto result_i = PCP_RESULT_STR.find(result_code); + return strprintf("%s (code %d)", result_i == PCP_RESULT_STR.end() ? "(unknown)" : result_i->second, result_code); +} + +//! Wrap address in IPv6 according to RFC6887. wrapped_addr needs to be able to store 16 bytes. +[[nodiscard]] bool PCPWrapAddress(Span<uint8_t> wrapped_addr, const CNetAddr &addr) +{ + Assume(wrapped_addr.size() == ADDR_IPV6_SIZE); + if (addr.IsIPv4()) { + struct in_addr addr4; + if (!addr.GetInAddr(&addr4)) return false; + // Section 5: "When the address field holds an IPv4 address, an IPv4-mapped IPv6 address [RFC4291] is used (::ffff:0:0/96)." + std::memcpy(wrapped_addr.data(), IPV4_IN_IPV6_PREFIX.data(), IPV4_IN_IPV6_PREFIX.size()); + std::memcpy(wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), &addr4, ADDR_IPV4_SIZE); + return true; + } else if (addr.IsIPv6()) { + struct in6_addr addr6; + if (!addr.GetIn6Addr(&addr6)) return false; + std::memcpy(wrapped_addr.data(), &addr6, ADDR_IPV6_SIZE); + return true; + } else { + return false; + } +} + +//! Unwrap PCP-encoded address according to RFC6887. +CNetAddr PCPUnwrapAddress(Span<const uint8_t> wrapped_addr) +{ + Assume(wrapped_addr.size() == ADDR_IPV6_SIZE); + if (util::HasPrefix(wrapped_addr, IPV4_IN_IPV6_PREFIX)) { + struct in_addr addr4; + std::memcpy(&addr4, wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), ADDR_IPV4_SIZE); + return CNetAddr(addr4); + } else { + struct in6_addr addr6; + std::memcpy(&addr6, wrapped_addr.data(), ADDR_IPV6_SIZE); + return CNetAddr(addr6); + } +} + +//! PCP or NAT-PMP send-receive loop. +std::optional<std::vector<uint8_t>> PCPSendRecv(Sock &sock, const std::string &protocol, Span<const uint8_t> request, int num_tries, + std::chrono::milliseconds timeout_per_try, + std::function<bool(Span<const uint8_t>)> check_packet) +{ + using namespace std::chrono; + // UDP is a potentially lossy protocol, so we try to send again a few times. + uint8_t response[PCP_MAX_SIZE]; + bool got_response = false; + int recvsz = 0; + for (int ntry = 0; !got_response && ntry < num_tries; ++ntry) { + if (ntry > 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Retrying (%d)\n", protocol, ntry); + } + // Dispatch packet to gateway. + if (sock.Send(request.data(), request.size(), 0) != static_cast<ssize_t>(request.size())) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "%s: Could not send request: %s\n", protocol, NetworkErrorString(WSAGetLastError())); + return std::nullopt; // Network-level error, probably no use retrying. + } + + // Wait for response(s) until we get a valid response, a network error, or time out. + auto cur_time = time_point_cast<milliseconds>(steady_clock::now()); + auto deadline = cur_time + timeout_per_try; + while ((cur_time = time_point_cast<milliseconds>(steady_clock::now())) < deadline) { + Sock::Event occurred = 0; + if (!sock.Wait(deadline - cur_time, Sock::RECV, &occurred)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "%s: Could not wait on socket: %s\n", protocol, NetworkErrorString(WSAGetLastError())); + return std::nullopt; // Network-level error, probably no use retrying. + } + if (!occurred) { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Timeout\n", protocol); + break; // Retry. + } + + // Receive response. + recvsz = sock.Recv(response, sizeof(response), MSG_DONTWAIT); + if (recvsz < 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "%s: Could not receive response: %s\n", protocol, NetworkErrorString(WSAGetLastError())); + return std::nullopt; // Network-level error, probably no use retrying. + } + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Received response of %d bytes: %s\n", protocol, recvsz, HexStr(Span(response, recvsz))); + + if (check_packet(Span<uint8_t>(response, recvsz))) { + got_response = true; // Got expected response, break from receive loop as well as from retry loop. + break; + } + } + } + if (!got_response) { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Giving up after %d tries\n", protocol, num_tries); + return std::nullopt; + } + return std::vector<uint8_t>(response, response + recvsz); +} + +} + +std::variant<MappingResult, MappingError> NATPMPRequestPortMap(const CNetAddr &gateway, uint16_t port, uint32_t lifetime, int num_tries, std::chrono::milliseconds timeout_per_try) +{ + struct sockaddr_storage dest_addr; + socklen_t dest_addrlen = sizeof(struct sockaddr_storage); + + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "natpmp: Requesting port mapping port %d from gateway %s\n", port, gateway.ToStringAddr()); + + // Validate gateway, make sure it's IPv4. NAT-PMP does not support IPv6. + if (!CService(gateway, PCP_SERVER_PORT).GetSockAddr((struct sockaddr*)&dest_addr, &dest_addrlen)) return MappingError::NETWORK_ERROR; + if (dest_addr.ss_family != AF_INET) return MappingError::NETWORK_ERROR; + + // Create IPv4 UDP socket + auto sock{CreateSock(AF_INET, SOCK_DGRAM, IPPROTO_UDP)}; + if (!sock) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Could not create UDP socket: %s\n", NetworkErrorString(WSAGetLastError())); + return MappingError::NETWORK_ERROR; + } + + // Associate UDP socket to gateway. + if (sock->Connect((struct sockaddr*)&dest_addr, dest_addrlen) != 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Could not connect to gateway: %s\n", NetworkErrorString(WSAGetLastError())); + return MappingError::NETWORK_ERROR; + } + + // Use getsockname to get the address toward the default gateway (the internal address). + struct sockaddr_in internal; + socklen_t internal_addrlen = sizeof(struct sockaddr_in); + if (sock->GetSockName((struct sockaddr*)&internal, &internal_addrlen) != 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Could not get sock name: %s\n", NetworkErrorString(WSAGetLastError())); + return MappingError::NETWORK_ERROR; + } + + // Request external IP address (RFC6886 section 3.2). + std::vector<uint8_t> request(NATPMP_GETEXTERNAL_REQUEST_SIZE); + request[NATPMP_HDR_VERSION_OFS] = NATPMP_VERSION; + request[NATPMP_HDR_OP_OFS] = NATPMP_REQUEST | NATPMP_OP_GETEXTERNAL; + + auto recv_res = PCPSendRecv(*sock, "natpmp", request, num_tries, timeout_per_try, + [&](const Span<const uint8_t> response) -> bool { + if (response.size() < NATPMP_GETEXTERNAL_RESPONSE_SIZE) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Response too small\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + if (response[NATPMP_HDR_VERSION_OFS] != NATPMP_VERSION || response[NATPMP_HDR_OP_OFS] != (NATPMP_RESPONSE | NATPMP_OP_GETEXTERNAL)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Response to wrong command\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + return true; + }); + + struct in_addr external_addr; + if (recv_res) { + const std::span<const uint8_t> response = *recv_res; + + Assume(response.size() >= NATPMP_GETEXTERNAL_RESPONSE_SIZE); + uint16_t result_code = ReadBE16(response.data() + NATPMP_RESPONSE_HDR_RESULT_OFS); + if (result_code != NATPMP_RESULT_SUCCESS) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Getting external address failed with result %s\n", NATPMPResultString(result_code)); + return MappingError::PROTOCOL_ERROR; + } + + std::memcpy(&external_addr, response.data() + NATPMP_GETEXTERNAL_RESPONSE_IP_OFS, ADDR_IPV4_SIZE); + } else { + return MappingError::NETWORK_ERROR; + } + + // Create TCP mapping request (RFC6886 section 3.3). + request = std::vector<uint8_t>(NATPMP_MAP_REQUEST_SIZE); + request[NATPMP_HDR_VERSION_OFS] = NATPMP_VERSION; + request[NATPMP_HDR_OP_OFS] = NATPMP_REQUEST | NATPMP_OP_MAP_TCP; + WriteBE16(request.data() + NATPMP_MAP_REQUEST_INTERNAL_PORT_OFS, port); + WriteBE16(request.data() + NATPMP_MAP_REQUEST_EXTERNAL_PORT_OFS, port); + WriteBE32(request.data() + NATPMP_MAP_REQUEST_LIFETIME_OFS, lifetime); + + recv_res = PCPSendRecv(*sock, "natpmp", request, num_tries, timeout_per_try, + [&](const Span<const uint8_t> response) -> bool { + if (response.size() < NATPMP_MAP_RESPONSE_SIZE) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Response too small\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + if (response[0] != NATPMP_VERSION || response[1] != (NATPMP_RESPONSE | NATPMP_OP_MAP_TCP)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Response to wrong command\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + uint16_t internal_port = ReadBE16(response.data() + NATPMP_MAP_RESPONSE_INTERNAL_PORT_OFS); + if (internal_port != port) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Response port doesn't match request\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + return true; + }); + + if (recv_res) { + const std::span<uint8_t> response = *recv_res; + + Assume(response.size() >= NATPMP_MAP_RESPONSE_SIZE); + uint16_t result_code = ReadBE16(response.data() + NATPMP_RESPONSE_HDR_RESULT_OFS); + if (result_code != NATPMP_RESULT_SUCCESS) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code)); + if (result_code == NATPMP_RESULT_NO_RESOURCES) { + return MappingError::NO_RESOURCES; + } + return MappingError::PROTOCOL_ERROR; + } + + uint32_t lifetime_ret = ReadBE32(response.data() + NATPMP_MAP_RESPONSE_LIFETIME_OFS); + uint16_t external_port = ReadBE16(response.data() + NATPMP_MAP_RESPONSE_EXTERNAL_PORT_OFS); + return MappingResult(NATPMP_VERSION, CService(internal.sin_addr, port), CService(external_addr, external_port), lifetime_ret); + } else { + return MappingError::NETWORK_ERROR; + } +} + +std::variant<MappingResult, MappingError> PCPRequestPortMap(const PCPMappingNonce &nonce, const CNetAddr &gateway, const CNetAddr &bind, uint16_t port, uint32_t lifetime, int num_tries, std::chrono::milliseconds timeout_per_try) +{ + struct sockaddr_storage dest_addr, bind_addr; + socklen_t dest_addrlen = sizeof(struct sockaddr_storage), bind_addrlen = sizeof(struct sockaddr_storage); + + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "pcp: Requesting port mapping for addr %s port %d from gateway %s\n", bind.ToStringAddr(), port, gateway.ToStringAddr()); + + // Validate addresses, make sure they're the same network family. + if (!CService(gateway, PCP_SERVER_PORT).GetSockAddr((struct sockaddr*)&dest_addr, &dest_addrlen)) return MappingError::NETWORK_ERROR; + if (!CService(bind, 0).GetSockAddr((struct sockaddr*)&bind_addr, &bind_addrlen)) return MappingError::NETWORK_ERROR; + if (dest_addr.ss_family != bind_addr.ss_family) return MappingError::NETWORK_ERROR; + + // Create UDP socket (IPv4 or IPv6 based on provided gateway). + auto sock{CreateSock(dest_addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)}; + if (!sock) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Could not create UDP socket: %s\n", NetworkErrorString(WSAGetLastError())); + return MappingError::NETWORK_ERROR; + } + + // Make sure that we send from requested destination address, anything else will be + // rejected by a security-conscious router. + if (sock->Bind((struct sockaddr*)&bind_addr, bind_addrlen) != 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Could not bind to address: %s\n", NetworkErrorString(WSAGetLastError())); + return MappingError::NETWORK_ERROR; + } + + // Associate UDP socket to gateway. + if (sock->Connect((struct sockaddr*)&dest_addr, dest_addrlen) != 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Could not connect to gateway: %s\n", NetworkErrorString(WSAGetLastError())); + return MappingError::NETWORK_ERROR; + } + + // Use getsockname to get the address toward the default gateway (the internal address), + // in case we don't know what address to map + // (this is only needed if bind is INADDR_ANY, but it doesn't hurt as an extra check). + struct sockaddr_storage internal_addr; + socklen_t internal_addrlen = sizeof(struct sockaddr_storage); + if (sock->GetSockName((struct sockaddr*)&internal_addr, &internal_addrlen) != 0) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Could not get sock name: %s\n", NetworkErrorString(WSAGetLastError())); + return MappingError::NETWORK_ERROR; + } + CService internal; + if (!internal.SetSockAddr((struct sockaddr*)&internal_addr)) return MappingError::NETWORK_ERROR; + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "pcp: Internal address after connect: %s\n", internal.ToStringAddr()); + + // Build request packet. Make sure the packet is zeroed so that reserved fields are zero + // as required by the spec (and not potentially leak data). + // Make sure there's space for the request header and MAP specific request data. + std::vector<uint8_t> request(PCP_HDR_SIZE + PCP_MAP_SIZE); + // Fill in request header, See RFC6887 Figure 2. + size_t ofs = 0; + request[ofs + PCP_HDR_VERSION_OFS] = PCP_VERSION; + request[ofs + PCP_HDR_OP_OFS] = PCP_REQUEST | PCP_OP_MAP; + WriteBE32(request.data() + ofs + PCP_HDR_LIFETIME_OFS, lifetime); + if (!PCPWrapAddress(Span(request).subspan(ofs + PCP_REQUEST_HDR_IP_OFS, ADDR_IPV6_SIZE), internal)) return MappingError::NETWORK_ERROR; + + ofs += PCP_HDR_SIZE; + + // Fill in MAP request packet, See RFC6887 Figure 9. + // Randomize mapping nonce (this is repeated in the response, to be able to + // correlate requests and responses, and used to authenticate changes to the mapping). + std::memcpy(request.data() + ofs + PCP_MAP_NONCE_OFS, nonce.data(), PCP_MAP_NONCE_SIZE); + request[ofs + PCP_MAP_PROTOCOL_OFS] = PCP_PROTOCOL_TCP; + WriteBE16(request.data() + ofs + PCP_MAP_INTERNAL_PORT_OFS, port); + WriteBE16(request.data() + ofs + PCP_MAP_EXTERNAL_PORT_OFS, port); + if (!PCPWrapAddress(Span(request).subspan(ofs + PCP_MAP_EXTERNAL_IP_OFS, ADDR_IPV6_SIZE), bind)) return MappingError::NETWORK_ERROR; + + ofs += PCP_MAP_SIZE; + Assume(ofs == request.size()); + + // Receive loop. + bool is_natpmp = false; + auto recv_res = PCPSendRecv(*sock, "pcp", request, num_tries, timeout_per_try, + [&](const Span<const uint8_t> response) -> bool { + // Unsupported version according to RFC6887 appendix A and RFC6886 section 3.5, can fall back to NAT-PMP. + if (response.size() == NATPMP_RESPONSE_HDR_SIZE && response[PCP_HDR_VERSION_OFS] == NATPMP_VERSION && response[PCP_RESPONSE_HDR_RESULT_OFS] == NATPMP_RESULT_UNSUPP_VERSION) { + is_natpmp = true; + return true; // Let it through to caller. + } + if (response.size() < (PCP_HDR_SIZE + PCP_MAP_SIZE)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Response too small\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + if (response[PCP_HDR_VERSION_OFS] != PCP_VERSION || response[PCP_HDR_OP_OFS] != (PCP_RESPONSE | PCP_OP_MAP)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Response to wrong command\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + // Handle MAP opcode response. See RFC6887 Figure 10. + // Check that returned mapping nonce matches our request. + if (!std::ranges::equal(response.subspan(PCP_HDR_SIZE + PCP_MAP_NONCE_OFS, PCP_MAP_NONCE_SIZE), nonce)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Mapping nonce mismatch\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + uint8_t protocol = response[PCP_HDR_SIZE + 12]; + uint16_t internal_port = ReadBE16(response.data() + PCP_HDR_SIZE + 16); + if (protocol != PCP_PROTOCOL_TCP || internal_port != port) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Response protocol or port doesn't match request\n"); + return false; // Wasn't response to what we expected, try receiving next packet. + } + return true; + }); + + if (!recv_res) { + return MappingError::NETWORK_ERROR; + } + if (is_natpmp) { + return MappingError::UNSUPP_VERSION; + } + + const std::span<const uint8_t> response = *recv_res; + // If we get here, we got a valid MAP response to our request. + // Check to see if we got the result we expected. + Assume(response.size() >= (PCP_HDR_SIZE + PCP_MAP_SIZE)); + uint8_t result_code = response[PCP_RESPONSE_HDR_RESULT_OFS]; + uint32_t lifetime_ret = ReadBE32(response.data() + PCP_HDR_LIFETIME_OFS); + uint16_t external_port = ReadBE16(response.data() + PCP_HDR_SIZE + PCP_MAP_EXTERNAL_PORT_OFS); + CNetAddr external_addr{PCPUnwrapAddress(response.subspan(PCP_HDR_SIZE + PCP_MAP_EXTERNAL_IP_OFS, ADDR_IPV6_SIZE))}; + if (result_code != PCP_RESULT_SUCCESS) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "pcp: Mapping failed with result %s\n", PCPResultString(result_code)); + if (result_code == PCP_RESULT_NO_RESOURCES) { + return MappingError::NO_RESOURCES; + } + return MappingError::PROTOCOL_ERROR; + } + + return MappingResult(PCP_VERSION, CService(internal, port), CService(external_addr, external_port), lifetime_ret); +} + +std::string MappingResult::ToString() +{ + Assume(version == NATPMP_VERSION || version == PCP_VERSION); + return strprintf("%s:%s -> %s (for %ds)", + version == NATPMP_VERSION ? "natpmp" : "pcp", + external.ToStringAddrPort(), + internal.ToStringAddrPort(), + lifetime + ); +} diff --git a/src/common/pcp.h b/src/common/pcp.h new file mode 100644 index 0000000000..ce2273e140 --- /dev/null +++ b/src/common/pcp.h @@ -0,0 +1,68 @@ +// Copyright (c) 2024 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMMON_PCP_H +#define BITCOIN_COMMON_PCP_H + +#include <netaddress.h> + +#include <variant> + +// RFC6886 NAT-PMP and RFC6887 Port Control Protocol (PCP) implementation. +// NAT-PMP and PCP use network byte order (big-endian). + +//! Mapping nonce size in bytes (see RFC6887 section 11.1). +constexpr size_t PCP_MAP_NONCE_SIZE = 12; + +//! PCP mapping nonce. Arbitrary data chosen by the client to identify a mapping. +typedef std::array<uint8_t, PCP_MAP_NONCE_SIZE> PCPMappingNonce; + +//! Unsuccessful response to a port mapping. +enum class MappingError { + NETWORK_ERROR, ///< Any kind of network-level error. + PROTOCOL_ERROR, ///< Any kind of protocol-level error, except unsupported version or no resources. + UNSUPP_VERSION, ///< Unsupported protocol version. + NO_RESOURCES, ///< No resources available (port probably already mapped). +}; + +//! Successful response to a port mapping. +struct MappingResult { + MappingResult(uint8_t version, const CService &internal_in, const CService &external_in, uint32_t lifetime_in): + version(version), internal(internal_in), external(external_in), lifetime(lifetime_in) {} + //! Protocol version, one of NATPMP_VERSION or PCP_VERSION. + uint8_t version; + //! Internal host:port. + CService internal; + //! External host:port. + CService external; + //! Granted lifetime of binding (seconds). + uint32_t lifetime; + + //! Format mapping as string for logging. + std::string ToString(); +}; + +//! Try to open a port using RFC 6886 NAT-PMP. IPv4 only. +//! +//! * gateway: Destination address for PCP requests (usually the default gateway). +//! * port: Internal port, and desired external port. +//! * lifetime: Requested lifetime in seconds for mapping. The server may assign as shorter or longer lifetime. A lifetime of 0 deletes the mapping. +//! * num_tries: Number of tries in case of no response. +//! +//! Returns the external_ip:external_port of the mapping if successful, otherwise a MappingError. +std::variant<MappingResult, MappingError> NATPMPRequestPortMap(const CNetAddr &gateway, uint16_t port, uint32_t lifetime, int num_tries = 3, std::chrono::milliseconds timeout_per_try = std::chrono::milliseconds(1000)); + +//! Try to open a port using RFC 6887 Port Control Protocol (PCP). Handles IPv4 and IPv6. +//! +//! * nonce: Mapping cookie. Keep this the same over renewals. +//! * gateway: Destination address for PCP requests (usually the default gateway). +//! * bind: Specific local bind address for IPv6 pinholing. Set this as INADDR_ANY for IPv4. +//! * port: Internal port, and desired external port. +//! * lifetime: Requested lifetime in seconds for mapping. The server may assign as shorter or longer lifetime. A lifetime of 0 deletes the mapping. +//! * num_tries: Number of tries in case of no response. +//! +//! Returns the external_ip:external_port of the mapping if successful, otherwise a MappingError. +std::variant<MappingResult, MappingError> PCPRequestPortMap(const PCPMappingNonce &nonce, const CNetAddr &gateway, const CNetAddr &bind, uint16_t port, uint32_t lifetime, int num_tries = 3, std::chrono::milliseconds timeout_per_try = std::chrono::milliseconds(1000)); + +#endif // BITCOIN_COMMON_PCP_H diff --git a/src/common/run_command.cpp b/src/common/run_command.cpp index 67608b985f..1f6d51b4f4 100644 --- a/src/common/run_command.cpp +++ b/src/common/run_command.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <common/run_command.h> diff --git a/src/common/settings.cpp b/src/common/settings.cpp index c1520dacd2..0b11e246c6 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -4,7 +4,7 @@ #include <common/settings.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <tinyformat.h> #include <univalue.h> diff --git a/src/util/message.cpp b/src/common/signmessage.cpp index 1afb28cc10..1612751e44 100644 --- a/src/util/message.cpp +++ b/src/common/signmessage.cpp @@ -3,12 +3,12 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/signmessage.h> #include <hash.h> #include <key.h> #include <key_io.h> #include <pubkey.h> #include <uint256.h> -#include <util/message.h> #include <util/strencodings.h> #include <cassert> diff --git a/src/util/message.h b/src/common/signmessage.h index d0e2422574..215b563bbb 100644 --- a/src/util/message.h +++ b/src/common/signmessage.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_UTIL_MESSAGE_H -#define BITCOIN_UTIL_MESSAGE_H +#ifndef BITCOIN_COMMON_SIGNMESSAGE_H +#define BITCOIN_COMMON_SIGNMESSAGE_H #include <uint256.h> @@ -74,4 +74,4 @@ uint256 MessageHash(const std::string& message); std::string SigningResultString(const SigningResult res); -#endif // BITCOIN_UTIL_MESSAGE_H +#endif // BITCOIN_COMMON_SIGNMESSAGE_H diff --git a/src/common/system.cpp b/src/common/system.cpp index ddd0feda3b..6a9463a0a5 100644 --- a/src/common/system.cpp +++ b/src/common/system.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <common/system.h> @@ -28,6 +28,8 @@ #include <string> #include <thread> +using util::ReplaceAll; + // Application startup time (used for uptime calculation) const int64_t nStartupTime = GetTime(); diff --git a/src/common/system.h b/src/common/system.h index d9115d3b33..a4b56be9ac 100644 --- a/src/common/system.h +++ b/src/common/system.h @@ -6,7 +6,7 @@ #ifndef BITCOIN_COMMON_SYSTEM_H #define BITCOIN_COMMON_SYSTEM_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <cstdint> #include <string> diff --git a/src/common/types.h b/src/common/types.h new file mode 100644 index 0000000000..0d9cb67ce9 --- /dev/null +++ b/src/common/types.h @@ -0,0 +1,26 @@ +// Copyright (c) 2010-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +//! @file common/types.h is a home for simple enum and struct type definitions +//! that can be used internally by functions in the libbitcoin_common library, +//! but also used externally by node, wallet, and GUI code. +//! +//! This file is intended to define only simple types that do not have external +//! dependencies. More complicated types should be defined in dedicated header +//! files. + +#ifndef BITCOIN_COMMON_TYPES_H +#define BITCOIN_COMMON_TYPES_H + +namespace common { +enum class PSBTError { + MISSING_INPUTS, + SIGHASH_MISMATCH, + EXTERNAL_SIGNER_NOT_FOUND, + EXTERNAL_SIGNER_FAILED, + UNSUPPORTED, +}; +} // namespace common + +#endif // BITCOIN_COMMON_TYPES_H diff --git a/src/compressor.h b/src/compressor.h index 0968454679..a0970c595e 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -55,8 +55,8 @@ struct ScriptCompression { /** * make this static for now (there are only 6 special scripts defined) - * this can potentially be extended together with a new nVersion for - * transactions, in which case this value becomes dependent on nVersion + * this can potentially be extended together with a new version for + * transactions, in which case this value becomes dependent on version * and nHeight of the enclosing transaction. */ static const unsigned int nSpecialScripts = 6; diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 384f70bc10..cffe9cdafd 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -27,4 +27,11 @@ static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * /** Interpret sequence numbers as relative lock-time constraints. */ static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0); +/** + * 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; + #endif // BITCOIN_CONSENSUS_CONSENSUS_H diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp index af01902c92..dc32f0ab80 100644 --- a/src/consensus/merkle.cpp +++ b/src/consensus/merkle.cpp @@ -83,3 +83,106 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated) return ComputeMerkleRoot(std::move(leaves), mutated); } +/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */ +static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector<uint256>* pbranch) { + if (pbranch) pbranch->clear(); + if (leaves.size() == 0) { + if (pmutated) *pmutated = false; + if (proot) *proot = uint256(); + return; + } + bool mutated = false; + // count is the number of leaves processed so far. + uint32_t count = 0; + // inner is an array of eagerly computed subtree hashes, indexed by tree + // level (0 being the leaves). + // For example, when count is 25 (11001 in binary), inner[4] is the hash of + // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to + // the last leaf. The other inner entries are undefined. + uint256 inner[32]; + // Which position in inner is a hash that depends on the matching leaf. + int matchlevel = -1; + // First process all leaves into 'inner' values. + while (count < leaves.size()) { + uint256 h = leaves[count]; + bool matchh = count == branchpos; + count++; + int level; + // For each of the lower bits in count that are 0, do 1 step. Each + // corresponds to an inner value that existed before processing the + // current leaf, and each needs a hash to combine it. + for (level = 0; !(count & ((uint32_t{1}) << level)); level++) { + if (pbranch) { + if (matchh) { + pbranch->push_back(inner[level]); + } else if (matchlevel == level) { + pbranch->push_back(h); + matchh = true; + } + } + mutated |= (inner[level] == h); + h = Hash(inner[level], h); + } + // Store the resulting hash at inner position level. + inner[level] = h; + if (matchh) { + matchlevel = level; + } + } + // Do a final 'sweep' over the rightmost branch of the tree to process + // odd levels, and reduce everything to a single top value. + // Level is the level (counted from the bottom) up to which we've sweeped. + int level = 0; + // As long as bit number level in count is zero, skip it. It means there + // is nothing left at this level. + while (!(count & ((uint32_t{1}) << level))) { + level++; + } + uint256 h = inner[level]; + bool matchh = matchlevel == level; + while (count != ((uint32_t{1}) << level)) { + // If we reach this point, h is an inner value that is not the top. + // We combine it with itself (Bitcoin's special rule for odd levels in + // the tree) to produce a higher level one. + if (pbranch && matchh) { + pbranch->push_back(h); + } + h = Hash(h, h); + // Increment count to the value it would have if two entries at this + // level had existed. + count += ((uint32_t{1}) << level); + level++; + // And propagate the result upwards accordingly. + while (!(count & ((uint32_t{1}) << level))) { + if (pbranch) { + if (matchh) { + pbranch->push_back(inner[level]); + } else if (matchlevel == level) { + pbranch->push_back(h); + matchh = true; + } + } + h = Hash(inner[level], h); + level++; + } + } + // Return result. + if (pmutated) *pmutated = mutated; + if (proot) *proot = h; +} + +static std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) { + std::vector<uint256> ret; + MerkleComputation(leaves, nullptr, nullptr, position, &ret); + return ret; +} + +std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position) +{ + std::vector<uint256> leaves; + leaves.resize(block.vtx.size()); + for (size_t s = 0; s < block.vtx.size(); s++) { + leaves[s] = block.vtx[s]->GetHash(); + } + return ComputeMerkleBranch(leaves, position); +} diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h index 4ae5a5b897..363f68039c 100644 --- a/src/consensus/merkle.h +++ b/src/consensus/merkle.h @@ -24,4 +24,14 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = nullptr); */ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated = nullptr); +/** + * Compute merkle path to the specified transaction + * + * @param[in] block the block + * @param[in] position transaction for which to calculate the merkle path, defaults to coinbase + * + * @return merkle path ordered from the deepest + */ +std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position = 0); + #endif // BITCOIN_CONSENSUS_MERKLE_H diff --git a/src/consensus/params.h b/src/consensus/params.h index 25f53eb620..dd29b9408e 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -108,6 +108,11 @@ struct Params { /** Proof of work parameters */ uint256 powLimit; bool fPowAllowMinDifficultyBlocks; + /** + * Enforce BIP94 timewarp attack mitigation. On testnet4 this also enforces + * the block storm mitigation. + */ + bool enforce_BIP94; bool fPowNoRetargeting; int64_t nPowTargetSpacing; int64_t nPowTargetTimespan; diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 154146f08d..95466b759c 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -48,11 +48,7 @@ std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags int nMinHeight = -1; int64_t nMinTime = -1; - // tx.nVersion is signed integer so requires cast to unsigned otherwise - // we would be doing a signed comparison and half the range of nVersion - // wouldn't support BIP 68. - bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2 - && flags & LOCKTIME_VERIFY_SEQUENCE; + bool fEnforceBIP68 = tx.version >= 2 && flags & LOCKTIME_VERIFY_SEQUENCE; // Do not enforce sequence numbers as a relative lock time // unless we have been instructed to 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 5956d9df5f..23f341c230 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -16,6 +16,8 @@ #include <algorithm> #include <string> +using util::SplitString; + namespace { class OpCodeParser { @@ -232,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/core_write.cpp b/src/core_write.cpp index 3a2bf865fc..253dfde100 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -174,9 +174,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry entry.pushKV("txid", tx.GetHash().GetHex()); entry.pushKV("hash", tx.GetWitnessHash().GetHex()); - // Transaction version is actually unsigned in consensus checks, just signed in memory, - // so cast to unsigned before giving it to the user. - entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(tx.nVersion))); + entry.pushKV("version", tx.version); entry.pushKV("size", tx.GetTotalSize()); entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR); entry.pushKV("weight", GetTransactionWeight(tx)); diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt new file mode 100644 index 0000000000..03c6972dca --- /dev/null +++ b/src/crypto/CMakeLists.txt @@ -0,0 +1,68 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_library(bitcoin_crypto STATIC EXCLUDE_FROM_ALL + aes.cpp + chacha20.cpp + chacha20poly1305.cpp + hex_base.cpp + hkdf_sha256_32.cpp + hmac_sha256.cpp + hmac_sha512.cpp + muhash.cpp + poly1305.cpp + ripemd160.cpp + sha1.cpp + sha256.cpp + sha256_sse4.cpp + sha3.cpp + sha512.cpp + siphash.cpp + ../support/cleanse.cpp +) + +target_link_libraries(bitcoin_crypto + PRIVATE + core_interface +) + +if(HAVE_SSE41) + add_library(bitcoin_crypto_sse41 STATIC EXCLUDE_FROM_ALL + sha256_sse41.cpp + ) + target_compile_definitions(bitcoin_crypto_sse41 PUBLIC ENABLE_SSE41) + target_compile_options(bitcoin_crypto_sse41 PRIVATE ${SSE41_CXXFLAGS}) + target_link_libraries(bitcoin_crypto_sse41 PRIVATE core_interface) + target_link_libraries(bitcoin_crypto PRIVATE bitcoin_crypto_sse41) +endif() + +if(HAVE_AVX2) + add_library(bitcoin_crypto_avx2 STATIC EXCLUDE_FROM_ALL + sha256_avx2.cpp + ) + target_compile_definitions(bitcoin_crypto_avx2 PUBLIC ENABLE_AVX2) + target_compile_options(bitcoin_crypto_avx2 PRIVATE ${AVX2_CXXFLAGS}) + target_link_libraries(bitcoin_crypto_avx2 PRIVATE core_interface) + target_link_libraries(bitcoin_crypto PRIVATE bitcoin_crypto_avx2) +endif() + +if(HAVE_SSE41 AND HAVE_X86_SHANI) + add_library(bitcoin_crypto_x86_shani STATIC EXCLUDE_FROM_ALL + sha256_x86_shani.cpp + ) + target_compile_definitions(bitcoin_crypto_x86_shani PUBLIC ENABLE_SSE41 ENABLE_X86_SHANI) + target_compile_options(bitcoin_crypto_x86_shani PRIVATE ${X86_SHANI_CXXFLAGS}) + target_link_libraries(bitcoin_crypto_x86_shani PRIVATE core_interface) + target_link_libraries(bitcoin_crypto PRIVATE bitcoin_crypto_x86_shani) +endif() + +if(HAVE_ARM_SHANI) + add_library(bitcoin_crypto_arm_shani STATIC EXCLUDE_FROM_ALL + sha256_arm_shani.cpp + ) + target_compile_definitions(bitcoin_crypto_arm_shani PUBLIC ENABLE_ARM_SHANI) + target_compile_options(bitcoin_crypto_arm_shani PRIVATE ${ARM_SHANI_CXXFLAGS}) + target_link_libraries(bitcoin_crypto_arm_shani PRIVATE core_interface) + target_link_libraries(bitcoin_crypto PRIVATE bitcoin_crypto_arm_shani) +endif() diff --git a/src/crypto/common.h b/src/crypto/common.h index 1dc4f3f55c..d45459b1f6 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -70,6 +70,12 @@ uint64_t static inline ReadBE64(const unsigned char* ptr) return be64toh_internal(x); } +void static inline WriteBE16(unsigned char* ptr, uint16_t x) +{ + uint16_t v = htobe16_internal(x); + memcpy(ptr, &v, 2); +} + void static inline WriteBE32(unsigned char* ptr, uint32_t x) { uint32_t v = htobe32_internal(x); diff --git a/src/crypto/hex_base.cpp b/src/crypto/hex_base.cpp new file mode 100644 index 0000000000..67d691b63e --- /dev/null +++ b/src/crypto/hex_base.cpp @@ -0,0 +1,67 @@ +// 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. + +#include <crypto/hex_base.h> + +#include <array> +#include <cstring> +#include <string> + +namespace { + +using ByteAsHex = std::array<char, 2>; + +constexpr std::array<ByteAsHex, 256> CreateByteToHexMap() +{ + constexpr char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + std::array<ByteAsHex, 256> byte_to_hex{}; + for (size_t i = 0; i < byte_to_hex.size(); ++i) { + byte_to_hex[i][0] = hexmap[i >> 4]; + byte_to_hex[i][1] = hexmap[i & 15]; + } + return byte_to_hex; +} + +} // namespace + +std::string HexStr(const Span<const uint8_t> s) +{ + std::string rv(s.size() * 2, '\0'); + static constexpr auto byte_to_hex = CreateByteToHexMap(); + static_assert(sizeof(byte_to_hex) == 512); + + char* it = rv.data(); + for (uint8_t v : s) { + std::memcpy(it, byte_to_hex[v].data(), 2); + it += 2; + } + + assert(it == rv.data() + rv.size()); + return rv; +} + +const signed char p_util_hexdigit[256] = +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + +signed char HexDigit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + diff --git a/src/crypto/hex_base.h b/src/crypto/hex_base.h new file mode 100644 index 0000000000..cdfea68c29 --- /dev/null +++ b/src/crypto/hex_base.h @@ -0,0 +1,23 @@ +// 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. + +#ifndef BITCOIN_CRYPTO_HEX_BASE_H +#define BITCOIN_CRYPTO_HEX_BASE_H + +#include <span.h> + +#include <cstddef> +#include <cstdint> +#include <string> + +/** + * Convert a span of bytes to a lower-case hexadecimal string. + */ +std::string HexStr(const Span<const uint8_t> s); +inline std::string HexStr(const Span<const char> s) { return HexStr(MakeUCharSpan(s)); } +inline std::string HexStr(const Span<const std::byte> s) { return HexStr(MakeUCharSpan(s)); } + +signed char HexDigit(char c); + +#endif // BITCOIN_CRYPTO_HEX_BASE_H 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..09c5d3123e 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -2,13 +2,14 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #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..e0f153fd61 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; } @@ -130,7 +130,7 @@ static void SetMaxOpenFiles(leveldb::Options *options) { options->max_open_files = 64; } #endif - LogPrint(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n", + LogDebug(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n", options->max_open_files, default_open_files); } @@ -299,7 +299,7 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) HandleError(status); if (log_memory) { double mem_after = DynamicMemoryUsage() / 1024.0 / 1024; - LogPrint(BCLog::LEVELDB, "WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n", + LogDebug(BCLog::LEVELDB, "WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n", m_name, mem_before, mem_after); } return true; @@ -310,7 +310,7 @@ size_t CDBWrapper::DynamicMemoryUsage() const std::string memory; std::optional<size_t> parsed; if (!DBContext().pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral<size_t>(memory))) { - LogPrint(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n"); + LogDebug(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n"); return 0; } return parsed.value(); diff --git a/src/external_signer.cpp b/src/external_signer.cpp index ff159a2aa5..1810f45bc8 100644 --- a/src/external_signer.cpp +++ b/src/external_signer.cpp @@ -80,10 +80,10 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str // Check if signer fingerprint matches any input master key fingerprint auto matches_signer_fingerprint = [&](const PSBTInput& input) { for (const auto& entry : input.hd_keypaths) { - if (parsed_m_fingerprint == MakeUCharSpan(entry.second.fingerprint)) return true; + if (std::ranges::equal(parsed_m_fingerprint, entry.second.fingerprint)) return true; } for (const auto& entry : input.m_tap_bip32_paths) { - if (parsed_m_fingerprint == MakeUCharSpan(entry.second.second.fingerprint)) return true; + if (std::ranges::equal(parsed_m_fingerprint, entry.second.second.fingerprint)) return true; } return false; }; diff --git a/src/flatfile.cpp b/src/flatfile.cpp index 2bff663d8b..388b30efae 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; @@ -66,7 +66,7 @@ size_t FlatFileSeq::Allocate(const FlatFilePos& pos, size_t add_size, bool& out_ if (CheckDiskSpace(m_dir, inc_size)) { FILE *file = Open(pos); if (file) { - LogPrint(BCLog::VALIDATION, "Pre-allocating up to position 0x%x in %s%05u.dat\n", new_size, m_prefix, pos.nFile); + LogDebug(BCLog::VALIDATION, "Pre-allocating up to position 0x%x in %s%05u.dat\n", new_size, m_prefix, pos.nFile); AllocateFileRange(file, pos.nPos, inc_size); fclose(file); return inc_size; @@ -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..b134ef6452 100644 --- a/src/headerssync.cpp +++ b/src/headerssync.cpp @@ -13,11 +13,11 @@ // contrib/devtools/headerssync-params.py. //! Store one header commitment per HEADER_COMMITMENT_PERIOD blocks. -constexpr size_t HEADER_COMMITMENT_PERIOD{606}; +constexpr size_t HEADER_COMMITMENT_PERIOD{615}; //! Only feed headers to validation once this many headers on top have been //! received and validated against commitments. -constexpr size_t REDOWNLOAD_BUFFER_SIZE{14441}; // 14441/606 = ~23.8 commitments +constexpr size_t REDOWNLOAD_BUFFER_SIZE{14621}; // 14621/615 = ~23.8 commitments // Our memory analysis assumes 48 bytes for a CompressedHeader (so we should // re-calculate parameters if we compress further) @@ -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), @@ -43,7 +43,7 @@ HeadersSyncState::HeadersSyncState(NodeId id, const Consensus::Params& consensus // could try again, if necessary, to sync a longer chain). m_max_commitments = 6*(Ticks<std::chrono::seconds>(NodeClock::now() - NodeSeconds{std::chrono::seconds{chain_start->GetMedianTimePast()}}) + MAX_FUTURE_BLOCK_TIME) / HEADER_COMMITMENT_PERIOD; - LogPrint(BCLog::NET, "Initial headers sync started with peer=%d: height=%i, max_commitments=%i, min_work=%s\n", m_id, m_current_height, m_max_commitments, m_minimum_required_work.ToString()); + LogDebug(BCLog::NET, "Initial headers sync started with peer=%d: height=%i, max_commitments=%i, min_work=%s\n", m_id, m_current_height, m_max_commitments, m_minimum_required_work.ToString()); } /** Free any memory in use, and mark this object as no longer usable. This is @@ -93,7 +93,7 @@ HeadersSyncState::ProcessingResult HeadersSyncState::ProcessNextHeaders(const // If we're in PRESYNC and we get a non-full headers // message, then the peer's chain has ended and definitely doesn't // have enough work, so we can stop our sync. - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: incomplete headers message at height=%i (presync phase)\n", m_id, m_current_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: incomplete headers message at height=%i (presync phase)\n", m_id, m_current_height); } } } else if (m_download_state == State::REDOWNLOAD) { @@ -119,7 +119,7 @@ HeadersSyncState::ProcessingResult HeadersSyncState::ProcessNextHeaders(const // If we hit our target blockhash, then all remaining headers will be // returned and we can clear any leftover internal state. if (m_redownloaded_headers.empty() && m_process_all_remaining_headers) { - LogPrint(BCLog::NET, "Initial headers sync complete with peer=%d: releasing all at height=%i (redownload phase)\n", m_id, m_redownload_buffer_last_height); + LogDebug(BCLog::NET, "Initial headers sync complete with peer=%d: releasing all at height=%i (redownload phase)\n", m_id, m_redownload_buffer_last_height); } else if (full_headers_message) { // If the headers message is full, we need to request more. ret.request_more = true; @@ -128,7 +128,7 @@ HeadersSyncState::ProcessingResult HeadersSyncState::ProcessNextHeaders(const // declining to serve us that full chain again. Give up. // Note that there's no more processing to be done with these // headers, so we can still return success. - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: incomplete headers message at height=%i (redownload phase)\n", m_id, m_redownload_buffer_last_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: incomplete headers message at height=%i (redownload phase)\n", m_id, m_redownload_buffer_last_height); } } } @@ -151,7 +151,7 @@ bool HeadersSyncState::ValidateAndStoreHeadersCommitments(const std::vector<CBlo // This might be benign -- perhaps our peer reorged away from the chain // they were on. Give up on this sync for now (likely we will start a // new sync with a new starting point). - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: non-continuous headers at height=%i (presync phase)\n", m_id, m_current_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: non-continuous headers at height=%i (presync phase)\n", m_id, m_current_height); return false; } @@ -170,7 +170,7 @@ bool HeadersSyncState::ValidateAndStoreHeadersCommitments(const std::vector<CBlo m_redownload_buffer_last_hash = m_chain_start->GetBlockHash(); m_redownload_chain_work = m_chain_start->nChainWork; m_download_state = State::REDOWNLOAD; - LogPrint(BCLog::NET, "Initial headers sync transition with peer=%d: reached sufficient work at height=%i, redownloading from height=%i\n", m_id, m_current_height, m_redownload_buffer_last_height); + LogDebug(BCLog::NET, "Initial headers sync transition with peer=%d: reached sufficient work at height=%i, redownloading from height=%i\n", m_id, m_current_height, m_redownload_buffer_last_height); } return true; } @@ -189,7 +189,7 @@ bool HeadersSyncState::ValidateAndProcessSingleHeader(const CBlockHeader& curren // adjustment maximum. if (!PermittedDifficultyTransition(m_consensus_params, next_height, m_last_header_received.nBits, current.nBits)) { - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: invalid difficulty transition at height=%i (presync phase)\n", m_id, next_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: invalid difficulty transition at height=%i (presync phase)\n", m_id, next_height); return false; } @@ -201,7 +201,7 @@ bool HeadersSyncState::ValidateAndProcessSingleHeader(const CBlockHeader& curren // It's possible the chain grew since we started the sync; so // potentially we could succeed in syncing the peer's chain if we // try again later. - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: exceeded max commitments at height=%i (presync phase)\n", m_id, next_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: exceeded max commitments at height=%i (presync phase)\n", m_id, next_height); return false; } } @@ -223,7 +223,7 @@ bool HeadersSyncState::ValidateAndStoreRedownloadedHeader(const CBlockHeader& he // Ensure that we're working on a header that connects to the chain we're // downloading. if (header.hashPrevBlock != m_redownload_buffer_last_hash) { - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: non-continuous headers at height=%i (redownload phase)\n", m_id, next_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: non-continuous headers at height=%i (redownload phase)\n", m_id, next_height); return false; } @@ -237,7 +237,7 @@ bool HeadersSyncState::ValidateAndStoreRedownloadedHeader(const CBlockHeader& he if (!PermittedDifficultyTransition(m_consensus_params, next_height, previous_nBits, header.nBits)) { - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: invalid difficulty transition at height=%i (redownload phase)\n", m_id, next_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: invalid difficulty transition at height=%i (redownload phase)\n", m_id, next_height); return false; } @@ -256,7 +256,7 @@ bool HeadersSyncState::ValidateAndStoreRedownloadedHeader(const CBlockHeader& he // target blockhash just because we ran out of commitments. if (!m_process_all_remaining_headers && next_height % HEADER_COMMITMENT_PERIOD == m_commit_offset) { if (m_header_commitments.size() == 0) { - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: commitment overrun at height=%i (redownload phase)\n", m_id, next_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: commitment overrun at height=%i (redownload phase)\n", m_id, next_height); // Somehow our peer managed to feed us a different chain and // we've run out of commitments. return false; @@ -265,7 +265,7 @@ bool HeadersSyncState::ValidateAndStoreRedownloadedHeader(const CBlockHeader& he bool expected_commitment = m_header_commitments.front(); m_header_commitments.pop_front(); if (commitment != expected_commitment) { - LogPrint(BCLog::NET, "Initial headers sync aborted with peer=%d: commitment mismatch at height=%i (redownload phase)\n", m_id, next_height); + LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: commitment mismatch at height=%i (redownload phase)\n", m_id, next_height); return false; } } 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/httprpc.cpp b/src/httprpc.cpp index 3eb34dbe6a..69dd821dc0 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -11,6 +11,8 @@ #include <netaddress.h> #include <rpc/protocol.h> #include <rpc/server.h> +#include <util/fs.h> +#include <util/fs_helpers.h> #include <util/strencodings.h> #include <util/string.h> #include <walletinitinterface.h> @@ -19,10 +21,14 @@ #include <iterator> #include <map> #include <memory> +#include <optional> #include <set> #include <string> #include <vector> +using util::SplitString; +using util::TrimStringView; + /** WWW-Authenticate to present with 401 Unauthorized response */ static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; @@ -288,16 +294,29 @@ static bool InitRPCAuthentication() { if (gArgs.GetArg("-rpcpassword", "") == "") { - LogPrintf("Using random cookie authentication.\n"); - if (!GenerateAuthCookie(&strRPCUserColonPass)) { + LogInfo("Using random cookie authentication.\n"); + + std::optional<fs::perms> cookie_perms{std::nullopt}; + auto cookie_perms_arg{gArgs.GetArg("-rpccookieperms")}; + if (cookie_perms_arg) { + auto perm_opt = InterpretPermString(*cookie_perms_arg); + if (!perm_opt) { + LogInfo("Invalid -rpccookieperms=%s; must be one of 'owner', 'group', or 'all'.\n", *cookie_perms_arg); + return false; + } + cookie_perms = *perm_opt; + } + + if (!GenerateAuthCookie(&strRPCUserColonPass, cookie_perms)) { return false; } } else { LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n"); strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", ""); } - if (gArgs.GetArg("-rpcauth", "") != "") { - LogPrintf("Using rpcauth authentication.\n"); + + if (!gArgs.GetArgs("-rpcauth").empty()) { + LogInfo("Using rpcauth authentication.\n"); for (const std::string& rpcauth : gArgs.GetArgs("-rpcauth")) { std::vector<std::string> fields{SplitString(rpcauth, ':')}; const std::vector<std::string> salt_hmac{SplitString(fields.back(), '$')}; @@ -339,7 +358,7 @@ static bool InitRPCAuthentication() bool StartHTTPRPC(const std::any& context) { - LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); + LogDebug(BCLog::RPC, "Starting HTTP RPC server\n"); if (!InitRPCAuthentication()) return false; @@ -357,12 +376,12 @@ bool StartHTTPRPC(const std::any& context) void InterruptHTTPRPC() { - LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n"); + LogDebug(BCLog::RPC, "Interrupting HTTP RPC server\n"); } void StopHTTPRPC() { - LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n"); + LogDebug(BCLog::RPC, "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); if (g_wallet_init_interface.HasWalletSupport()) { UnregisterHTTPHandler("/wallet/", false); diff --git a/src/httpserver.cpp b/src/httpserver.cpp index b1d4dc9234..b8772ed852 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -2,12 +2,13 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <httpserver.h> #include <chainparamsbase.h> #include <common/args.h> +#include <common/messages.h> #include <compat/compat.h> #include <logging.h> #include <netbase.h> @@ -26,6 +27,7 @@ #include <deque> #include <memory> #include <optional> +#include <span> #include <string> #include <unordered_map> @@ -42,6 +44,8 @@ #include <support/events.h> +using common::InvalidPortErrMsg; + /** Maximum size of http request (request line + headers) */ static const size_t MAX_HEADERS_SIZE = 8192; @@ -234,7 +238,7 @@ static bool InitHTTPAllowList() std::string strAllowed; for (const CSubNet& subnet : rpc_allow_subnets) strAllowed += subnet.ToString() + " "; - LogPrint(BCLog::HTTP, "Allowing HTTP connections from: %s\n", strAllowed); + LogDebug(BCLog::HTTP, "Allowing HTTP connections from: %s\n", strAllowed); return true; } @@ -286,7 +290,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg) // Early address-based allow check if (!ClientAllowed(hreq->GetPeer())) { - LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n", + LogDebug(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n", hreq->GetPeer().ToStringAddrPort()); hreq->WriteReply(HTTP_FORBIDDEN); return; @@ -294,13 +298,13 @@ static void http_request_cb(struct evhttp_request* req, void* arg) // Early reject unknown HTTP methods if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) { - LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n", + LogDebug(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n", hreq->GetPeer().ToStringAddrPort()); hreq->WriteReply(HTTP_BAD_METHOD); return; } - LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n", + LogDebug(BCLog::HTTP, "Received a %s request for %s from %s\n", RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToStringAddrPort()); // Find registered handler for prefix @@ -314,7 +318,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg) if (i->exactMatch) match = (strURI == i->prefix); else - match = (strURI.substr(0, i->prefix.size()) == i->prefix); + match = strURI.starts_with(i->prefix); if (match) { path = strURI.substr(i->prefix.size()); break; @@ -339,7 +343,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg) /** Callback to reject HTTP requests after shutdown. */ static void http_reject_request_cb(struct evhttp_request* req, void*) { - LogPrint(BCLog::HTTP, "Rejecting request while shutting down\n"); + LogDebug(BCLog::HTTP, "Rejecting request while shutting down\n"); evhttp_send_error(req, HTTP_SERVUNAVAIL, nullptr); } @@ -347,10 +351,10 @@ static void http_reject_request_cb(struct evhttp_request* req, void*) static void ThreadHTTP(struct event_base* base) { util::ThreadRename("http"); - LogPrint(BCLog::HTTP, "Entering http event loop\n"); + LogDebug(BCLog::HTTP, "Entering http event loop\n"); event_base_dispatch(base); // Event loop will be interrupted by InterruptHTTPServer() - LogPrint(BCLog::HTTP, "Exited http event loop\n"); + LogDebug(BCLog::HTTP, "Exited http event loop\n"); } /** Bind HTTP server to specified addresses */ @@ -373,7 +377,10 @@ static bool HTTPBindAddresses(struct evhttp* http) for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) { uint16_t port{http_port}; std::string host; - SplitHostPort(strRPCBind, port, host); + if (!SplitHostPort(strRPCBind, port, host)) { + LogError("%s\n", InvalidPortErrMsg("-rpcbind", strRPCBind).original); + return false; + } endpoints.emplace_back(host, port); } } @@ -387,6 +394,12 @@ static bool HTTPBindAddresses(struct evhttp* http) if (i->first.empty() || (addr.has_value() && addr->IsBindAny())) { LogPrintf("WARNING: the RPC server is not safe to expose to untrusted networks such as the public internet\n"); } + // Set the no-delay option (disable Nagle's algorithm) on the TCP socket. + evutil_socket_t fd = evhttp_bound_socket_get_fd(bind_handle); + int one = 1; + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (sockopt_arg_type)&one, sizeof(one)) == SOCKET_ERROR) { + LogInfo("WARNING: Unable to set TCP_NODELAY on RPC server socket, continuing anyway\n"); + } boundSockets.push_back(bind_handle); } else { LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second); @@ -459,7 +472,7 @@ bool InitHTTPServer(const util::SignalInterrupt& interrupt) return false; } - LogPrint(BCLog::HTTP, "Initialized HTTP server\n"); + LogDebug(BCLog::HTTP, "Initialized HTTP server\n"); int workQueueDepth = std::max((long)gArgs.GetIntArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L); LogDebug(BCLog::HTTP, "creating work queue of depth %d\n", workQueueDepth); @@ -494,7 +507,7 @@ void StartHTTPServer() void InterruptHTTPServer() { - LogPrint(BCLog::HTTP, "Interrupting HTTP server\n"); + LogDebug(BCLog::HTTP, "Interrupting HTTP server\n"); if (eventHTTP) { // Reject requests on current connections evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr); @@ -506,9 +519,9 @@ void InterruptHTTPServer() void StopHTTPServer() { - LogPrint(BCLog::HTTP, "Stopping HTTP server\n"); + LogDebug(BCLog::HTTP, "Stopping HTTP server\n"); if (g_work_queue) { - LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n"); + LogDebug(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n"); for (auto& thread : g_thread_http_workers) { thread.join(); } @@ -522,7 +535,7 @@ void StopHTTPServer() boundSockets.clear(); { if (const auto n_connections{g_requests.CountActiveConnections()}; n_connections != 0) { - LogPrint(BCLog::HTTP, "Waiting for %d connections to stop HTTP server\n", n_connections); + LogDebug(BCLog::HTTP, "Waiting for %d connections to stop HTTP server\n", n_connections); } g_requests.WaitUntilEmpty(); } @@ -536,13 +549,13 @@ void StopHTTPServer() }, nullptr, nullptr); } if (eventBase) { - LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n"); + LogDebug(BCLog::HTTP, "Waiting for HTTP event thread to exit\n"); if (g_thread_http.joinable()) g_thread_http.join(); event_base_free(eventBase); eventBase = nullptr; } g_work_queue.reset(); - LogPrint(BCLog::HTTP, "Stopped HTTP server\n"); + LogDebug(BCLog::HTTP, "Stopped HTTP server\n"); } struct event_base* EventBase() @@ -634,7 +647,7 @@ void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value) * Replies must be sent in the main loop in the main http thread, * this cannot be done from worker threads. */ -void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) +void HTTPRequest::WriteReply(int nStatus, std::span<const std::byte> reply) { assert(!replySent && req); if (m_interrupt) { @@ -643,7 +656,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) // Send event to main http thread to send reply message struct evbuffer* evb = evhttp_request_get_output_buffer(req); assert(evb); - evbuffer_add(evb, strReply.data(), strReply.size()); + evbuffer_add(evb, reply.data(), reply.size()); auto req_copy = req; HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{ evhttp_send_reply(req_copy, nStatus, nullptr, nullptr); @@ -741,7 +754,7 @@ std::optional<std::string> GetQueryParameterFromUri(const char* uri, const std:: void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler) { - LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch); + LogDebug(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch); LOCK(g_httppathhandlers_mutex); pathHandlers.emplace_back(prefix, exactMatch, handler); } @@ -756,7 +769,7 @@ void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch) break; if (i != iend) { - LogPrint(BCLog::HTTP, "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch); + LogDebug(BCLog::HTTP, "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch); pathHandlers.erase(i); } } diff --git a/src/httpserver.h b/src/httpserver.h index 9a49877f09..33216a0119 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -7,6 +7,7 @@ #include <functional> #include <optional> +#include <span> #include <string> namespace util { @@ -123,12 +124,16 @@ public: /** * Write HTTP reply. * nStatus is the HTTP status code to send. - * strReply is the body of the reply. Keep it empty to send a standard message. + * reply is the body of the reply. Keep it empty to send a standard message. * * @note Can be called only once. As this will give the request back to the * main thread, do not call any other HTTPRequest methods after calling this. */ - void WriteReply(int nStatus, const std::string& strReply = ""); + void WriteReply(int nStatus, std::string_view reply = "") + { + WriteReply(nStatus, std::as_bytes(std::span{reply})); + } + void WriteReply(int nStatus, std::span<const std::byte> reply); }; /** Get the query parameter value from request uri for a specified key, or std::nullopt if the key @@ -151,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/i2p.cpp b/src/i2p.cpp index 962adb124d..0420bc9238 100644 --- a/src/i2p.cpp +++ b/src/i2p.cpp @@ -12,12 +12,12 @@ #include <netaddress.h> #include <netbase.h> #include <random.h> +#include <script/parsing.h> #include <sync.h> #include <tinyformat.h> #include <util/fs.h> #include <util/readwritefile.h> #include <util/sock.h> -#include <util/spanparsing.h> #include <util/strencodings.h> #include <util/threadinterrupt.h> @@ -26,6 +26,8 @@ #include <stdexcept> #include <string> +using util::Split; + namespace i2p { /** @@ -146,7 +148,7 @@ bool Session::Listen(Connection& conn) conn.sock = StreamAccept(); return true; } catch (const std::runtime_error& e) { - Log("Error listening: %s", e.what()); + LogPrintLevel(BCLog::I2P, BCLog::Level::Error, "Couldn't listen: %s\n", e.what()); CheckControlSock(); } return false; @@ -202,7 +204,11 @@ bool Session::Accept(Connection& conn) return true; } - Log("Error accepting%s: %s", disconnect ? " (will close the session)" : "", errmsg); + if (*m_interrupt) { + LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Accept was interrupted\n"); + } else { + LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error accepting%s: %s\n", disconnect ? " (will close the session)" : "", errmsg); + } if (disconnect) { LOCK(m_mutex); Disconnect(); @@ -217,7 +223,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error) // Refuse connecting to arbitrary ports. We don't specify any destination port to the SAM proxy // when connecting (SAM 3.1 does not use ports) and it forces/defaults it to I2P_SAM31_PORT. if (to.GetPort() != I2P_SAM31_PORT) { - Log("Error connecting to %s, connection refused due to arbitrary port %s", to.ToStringAddrPort(), to.GetPort()); + LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error connecting to %s, connection refused due to arbitrary port %s\n", to.ToStringAddrPort(), to.GetPort()); proxy_error = false; return false; } @@ -265,7 +271,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error) throw std::runtime_error(strprintf("\"%s\"", connect_reply.full)); } catch (const std::runtime_error& e) { - Log("Error connecting to %s: %s", to.ToStringAddrPort(), e.what()); + LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error connecting to %s: %s\n", to.ToStringAddrPort(), e.what()); CheckControlSock(); return false; } @@ -283,12 +289,6 @@ std::string Session::Reply::Get(const std::string& key) const return pos->second.value(); } -template <typename... Args> -void Session::Log(const std::string& fmt, const Args&... args) const -{ - LogPrint(BCLog::I2P, "%s\n", tfm::format(fmt, args...)); -} - Session::Reply Session::SendRequestAndGetReply(const Sock& sock, const std::string& request, bool check_result_ok) const @@ -308,7 +308,7 @@ Session::Reply Session::SendRequestAndGetReply(const Sock& sock, reply.full = sock.RecvUntilTerminator('\n', recv_timeout, *m_interrupt, MAX_MSG_SIZE); - for (const auto& kv : spanparsing::Split(reply.full, ' ')) { + for (const auto& kv : Split(reply.full, ' ')) { const auto& pos = std::find(kv.begin(), kv.end(), '='); if (pos != kv.end()) { reply.keys.emplace(std::string{kv.begin(), pos}, std::string{pos + 1, kv.end()}); @@ -344,7 +344,7 @@ void Session::CheckControlSock() std::string errmsg; if (m_control_sock && !m_control_sock->IsConnected(errmsg)) { - Log("Control socket error: %s", errmsg); + LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Control socket error: %s\n", errmsg); Disconnect(); } } @@ -414,7 +414,7 @@ void Session::CreateIfNotCreatedAlready() const auto session_type = m_transient ? "transient" : "persistent"; const auto session_id = GetRandHash().GetHex().substr(0, 10); // full is overkill, too verbose in the logs - Log("Creating %s SAM session %s with %s", session_type, session_id, m_control_host.ToString()); + LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Creating %s SAM session %s with %s\n", session_type, session_id, m_control_host.ToString()); auto sock = Hello(); @@ -451,7 +451,7 @@ void Session::CreateIfNotCreatedAlready() m_session_id = session_id; m_control_sock = std::move(sock); - Log("%s SAM session %s created, my address=%s", + LogPrintLevel(BCLog::I2P, BCLog::Level::Info, "%s SAM session %s created, my address=%s\n", Capitalize(session_type), m_session_id, m_my_addr.ToStringAddrPort()); @@ -482,9 +482,9 @@ void Session::Disconnect() { if (m_control_sock) { if (m_session_id.empty()) { - Log("Destroying incomplete SAM session"); + LogPrintLevel(BCLog::I2P, BCLog::Level::Info, "Destroying incomplete SAM session\n"); } else { - Log("Destroying SAM session %s", m_session_id); + LogPrintLevel(BCLog::I2P, BCLog::Level::Info, "Destroying SAM session %s\n", m_session_id); } m_control_sock.reset(); } @@ -157,14 +157,6 @@ private: }; /** - * Log a message in the `BCLog::I2P` category. - * @param[in] fmt printf(3)-like format string. - * @param[in] args printf(3)-like arguments that correspond to `fmt`. - */ - template <typename... Args> - void Log(const std::string& fmt, const Args&... args) const; - - /** * Send request and get a reply from the SAM proxy. * @param[in] sock A socket that is connected to the SAM proxy. * @param[in] request Raw request to send, a newline terminator is appended to it. diff --git a/src/index/base.cpp b/src/index/base.cpp index e66c89f9e4..1a7eb9cd5e 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -14,10 +14,10 @@ #include <node/database_args.h> #include <node/interface_ui.h> #include <tinyformat.h> +#include <util/string.h> #include <util/thread.h> #include <util/translation.h> #include <validation.h> // For g_chainman -#include <warnings.h> #include <string> #include <utility> @@ -28,10 +28,10 @@ constexpr auto SYNC_LOG_INTERVAL{30s}; constexpr auto SYNC_LOCATOR_WRITE_INTERVAL{30s}; template <typename... Args> -void BaseIndex::FatalErrorf(const char* fmt, const Args&... args) +void BaseIndex::FatalErrorf(util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) { auto message = tfm::format(fmt, args...); - node::AbortNode(m_chain->context()->shutdown, m_chain->context()->exit_status, Untranslated(message)); + node::AbortNode(m_chain->context()->shutdown_request, m_chain->context()->exit_status, Untranslated(message), m_chain->context()->warnings.get()); } CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash) @@ -113,7 +113,7 @@ bool BaseIndex::Init() // Child init const CBlockIndex* start_block = m_best_block_index.load(); - if (!CustomInit(start_block ? std::make_optional(interfaces::BlockKey{start_block->GetBlockHash(), start_block->nHeight}) : std::nullopt)) { + if (!CustomInit(start_block ? std::make_optional(interfaces::BlockRef{start_block->GetBlockHash(), start_block->nHeight}) : std::nullopt)) { return false; } diff --git a/src/index/base.h b/src/index/base.h index 0eb1d9ca3b..fbd9069a51 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -7,6 +7,8 @@ #include <dbwrapper.h> #include <interfaces/chain.h> +#include <interfaces/types.h> +#include <util/string.h> #include <util/threadinterrupt.h> #include <validationinterface.h> @@ -94,7 +96,7 @@ private: virtual bool AllowPrune() const = 0; template <typename... Args> - void FatalErrorf(const char* fmt, const Args&... args); + void FatalErrorf(util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args); protected: std::unique_ptr<interfaces::Chain> m_chain; @@ -106,7 +108,7 @@ protected: void ChainStateFlushed(ChainstateRole role, const CBlockLocator& locator) override; /// Initialize internal state from the database and block index. - [[nodiscard]] virtual bool CustomInit(const std::optional<interfaces::BlockKey>& block) { return true; } + [[nodiscard]] virtual bool CustomInit(const std::optional<interfaces::BlockRef>& block) { return true; } /// Write update index entries for a newly connected block. [[nodiscard]] virtual bool CustomAppend(const interfaces::BlockInfo& block) { return true; } @@ -117,7 +119,7 @@ protected: /// Rewind index to an earlier chain tip during a chain reorg. The tip must /// be an ancestor of the current best block. - [[nodiscard]] virtual bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) { return true; } + [[nodiscard]] virtual bool CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) { return true; } virtual DB& GetDB() const = 0; diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index 41bdca9df5..a808cc9085 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -112,7 +112,7 @@ BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, Blo m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE); } -bool BlockFilterIndex::CustomInit(const std::optional<interfaces::BlockKey>& block) +bool BlockFilterIndex::CustomInit(const std::optional<interfaces::BlockRef>& block) { if (!m_db->Read(DB_FILTER_POS, m_next_filter_pos)) { // Check that the cause of the read failure is that the key does not exist. Any other errors @@ -151,7 +151,7 @@ bool BlockFilterIndex::CustomCommit(CDBBatch& batch) LogError("%s: Failed to open filter file %d\n", __func__, pos.nFile); return false; } - if (!FileCommit(file.Get())) { + if (!file.Commit()) { LogError("%s: Failed to commit filter file %d\n", __func__, pos.nFile); return false; } @@ -201,11 +201,11 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile); return 0; } - if (!TruncateFile(last_file.Get(), pos.nPos)) { + if (!last_file.Truncate(pos.nPos)) { LogPrintf("%s: Failed to truncate filter file %d\n", __func__, pos.nFile); return 0; } - if (!FileCommit(last_file.Get())) { + if (!last_file.Commit()) { LogPrintf("%s: Failed to commit filter file %d\n", __func__, pos.nFile); return 0; } @@ -316,7 +316,7 @@ bool BlockFilterIndex::Write(const BlockFilter& filter, uint32_t block_height, c return true; } -bool BlockFilterIndex::CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) +bool BlockFilterIndex::CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) { CDBBatch batch(*m_db); std::unique_ptr<CDBIterator> db_it(m_db->NewIterator()); diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h index cdb9563fb8..ccb4845ef5 100644 --- a/src/index/blockfilterindex.h +++ b/src/index/blockfilterindex.h @@ -52,13 +52,13 @@ private: std::optional<uint256> ReadFilterHeader(int height, const uint256& expected_block_hash); protected: - bool CustomInit(const std::optional<interfaces::BlockKey>& block) override; + bool CustomInit(const std::optional<interfaces::BlockRef>& block) override; bool CustomCommit(CDBBatch& batch) override; bool CustomAppend(const interfaces::BlockInfo& block) override; - bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override; + bool CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) override; BaseIndex::DB& GetDB() const LIFETIMEBOUND override { return *m_db; } diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index dff8e50a4e..c950a18f3f 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -265,7 +265,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block) return true; } -bool CoinStatsIndex::CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) +bool CoinStatsIndex::CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) { CDBBatch batch(*m_db); std::unique_ptr<CDBIterator> db_it(m_db->NewIterator()); @@ -304,7 +304,7 @@ bool CoinStatsIndex::CustomRewind(const interfaces::BlockKey& current_tip, const return true; } -static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockKey& block, DBVal& result) +static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockRef& block, DBVal& result) { // First check if the result is stored under the height index and the value // there matches the block hash. This should be the case if the block is on @@ -350,7 +350,7 @@ std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex& block_ return stats; } -bool CoinStatsIndex::CustomInit(const std::optional<interfaces::BlockKey>& block) +bool CoinStatsIndex::CustomInit(const std::optional<interfaces::BlockRef>& block) { if (!m_db->Read(DB_MUHASH, m_muhash)) { // Check that the cause of the read failure is that the key does not diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h index d6322bfa7c..885b9e0a86 100644 --- a/src/index/coinstatsindex.h +++ b/src/index/coinstatsindex.h @@ -43,13 +43,13 @@ private: bool AllowPrune() const override { return true; } protected: - bool CustomInit(const std::optional<interfaces::BlockKey>& block) override; + bool CustomInit(const std::optional<interfaces::BlockRef>& block) override; bool CustomCommit(CDBBatch& batch) override; bool CustomAppend(const interfaces::BlockInfo& block) override; - bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override; + bool CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) override; BaseIndex::DB& GetDB() const override { return *m_db; } 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/index/txindex.cpp b/src/index/txindex.cpp index 80f615ed0e..425a7f00a0 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -87,10 +87,7 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe CBlockHeader header; try { file >> header; - if (fseek(file.Get(), postx.nTxOffset, SEEK_CUR)) { - LogError("%s: fseek(...) failed\n", __func__); - return false; - } + file.seek(postx.nTxOffset, SEEK_CUR); file >> TX_WITH_WITNESS(tx); } catch (const std::exception& e) { LogError("%s: Deserialize or I/O error - %s\n", __func__, e.what()); diff --git a/src/init.cpp b/src/init.cpp index 0aac2ac65f..ab53cb851d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -3,13 +3,11 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <init.h> #include <kernel/checks.h> -#include <kernel/mempool_persist.h> -#include <kernel/validation_cache_sizes.h> #include <addrman.h> #include <banman.h> @@ -31,6 +29,8 @@ #include <init/common.h> #include <interfaces/chain.h> #include <interfaces/init.h> +#include <interfaces/ipc.h> +#include <interfaces/mining.h> #include <interfaces/node.h> #include <kernel/context.h> #include <key.h> @@ -50,10 +50,10 @@ #include <node/interface_ui.h> #include <node/kernel_notifications.h> #include <node/mempool_args.h> +#include <node/mempool_persist.h> #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> @@ -109,30 +109,37 @@ #include <boost/signals2/signal.hpp> -#if ENABLE_ZMQ +#ifdef ENABLE_ZMQ #include <zmq/zmqabstractnotifier.h> #include <zmq/zmqnotificationinterface.h> #include <zmq/zmqrpc.h> #endif -using kernel::DumpMempool; -using kernel::LoadMempool; -using kernel::ValidationCacheSizes; +using common::AmountErrMsg; +using common::InvalidPortErrMsg; +using common::ResolveErrMsg; using node::ApplyArgsManOptions; using node::BlockManager; using node::CacheSizes; using node::CalculateCacheSizes; +using node::ChainstateLoadResult; +using node::ChainstateLoadStatus; using node::DEFAULT_PERSIST_MEMPOOL; -using node::DEFAULT_PRINTPRIORITY; +using node::DEFAULT_PRINT_MODIFIED_FEE; using node::DEFAULT_STOPATHEIGHT; +using node::DumpMempool; +using node::ImportBlocks; using node::KernelNotifications; using node::LoadChainstate; +using node::LoadMempool; using node::MempoolPath; using node::NodeContext; using node::ShouldPersistMempool; -using node::ImportBlocks; using node::VerifyLoadedChainstate; +using util::Join; +using util::ReplaceAll; +using util::ToString; static constexpr bool DEFAULT_PROXYRANDOMIZE{true}; static constexpr bool DEFAULT_REST_ENABLE{false}; @@ -143,11 +150,12 @@ static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false}; // Win32 LevelDB doesn't use filedescriptors, and the ones used for // accessing block files don't count towards the fd_set size limit // anyway. -#define MIN_CORE_FILEDESCRIPTORS 0 +#define MIN_LEVELDB_FDS 0 #else -#define MIN_CORE_FILEDESCRIPTORS 150 +#define MIN_LEVELDB_FDS 150 #endif +static constexpr int MIN_CORE_FDS = MIN_LEVELDB_FDS + NUM_FDS_MESSAGE_CAPTURE; static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map"; /** @@ -199,7 +207,14 @@ void InitContext(NodeContext& node) g_shutdown.emplace(); node.args = &gArgs; - node.shutdown = &*g_shutdown; + node.shutdown_signal = &*g_shutdown; + node.shutdown_request = [&node] { + assert(node.shutdown_signal); + if (!(*node.shutdown_signal)()) return false; + // Wake any threads that may be waiting for the tip to change. + if (node.notifications) WITH_LOCK(node.notifications->m_tip_block_mutex, node.notifications->m_tip_block_cv.notify_all()); + return true; + }; } ////////////////////////////////////////////////////////////////////////////// @@ -227,7 +242,7 @@ void InitContext(NodeContext& node) bool ShutdownRequested(node::NodeContext& node) { - return bool{*Assert(node.shutdown)}; + return bool{*Assert(node.shutdown_signal)}; } #if HAVE_SYSTEM @@ -292,10 +307,11 @@ void Shutdown(NodeContext& node) StopTorControl(); + if (node.background_init_thread.joinable()) node.background_init_thread.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. @@ -358,7 +374,7 @@ void Shutdown(NodeContext& node) client->stop(); } -#if ENABLE_ZMQ +#ifdef ENABLE_ZMQ if (g_zmq_notification_interface) { if (node.validation_signals) node.validation_signals->UnregisterValidationInterface(g_zmq_notification_interface.get()); g_zmq_notification_interface.reset(); @@ -403,7 +419,7 @@ static void HandleSIGHUP(int) static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) { if (!(*Assert(g_shutdown))()) { - LogPrintf("Error: failed to send shutdown signal on Ctrl-C\n"); + LogError("Failed to send shutdown signal on Ctrl-C\n"); return false; } Sleep(INFINITE); @@ -422,21 +438,7 @@ static void registerSignalHandler(int signal, void(*handler)(int)) } #endif -static boost::signals2::connection rpc_notify_block_change_connection; -static void OnRPCStarted() -{ - rpc_notify_block_change_connection = uiInterface.NotifyBlockTip_connect(std::bind(RPCNotifyBlockChange, std::placeholders::_2)); -} - -static void OnRPCStopped() -{ - rpc_notify_block_change_connection.disconnect(); - RPCNotifyBlockChange(nullptr); - g_best_block_cv.notify_all(); - LogPrint(BCLog::RPC, "RPC stopped.\n"); -} - -void SetupServerArgs(ArgsManager& argsman) +void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) { SetupHelpOptions(argsman); argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now @@ -445,10 +447,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); @@ -462,8 +466,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); @@ -474,14 +485,14 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-conf=<file>", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location (only useable from command line, not configuration file) (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); - argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (minimum %d, default: %d). Make sure you have enough RAM. In addition, unused memory allocated to the mempool is shared with this cache (see -maxmempool).", nMinDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 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); @@ -510,7 +521,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); @@ -525,7 +536,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection memory usage for the send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); -#if HAVE_SOCKADDR_UN +#ifdef HAVE_SOCKADDR_UN argsman.AddArg("-onion=<ip:port|path>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy). May be a local file path prefixed with 'unix:'.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); #else argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -537,8 +548,8 @@ 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); -#if HAVE_SOCKADDR_UN + 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 argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION); @@ -555,11 +566,7 @@ void SetupServerArgs(ArgsManager& argsman) #else hidden_args.emplace_back("-upnp"); #endif -#ifdef USE_NATPMP - argsman.AddArg("-natpmp", strprintf("Use NAT-PMP to map the listening port (default: %u)", DEFAULT_NATPMP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); -#else - hidden_args.emplace_back("-natpmp"); -#endif // USE_NATPMP + argsman.AddArg("-natpmp", strprintf("Use PCP or NAT-PMP to map the listening port (default: %u)", DEFAULT_NATPMP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers connecting to it. " "Use [host]:port notation for IPv6. Allowed permissions: " + Join(NET_PERMISSIONS_DOC, ", ") + ". " "Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -572,7 +579,7 @@ void SetupServerArgs(ArgsManager& argsman) g_wallet_init_interface.AddWalletOptions(argsman); -#if ENABLE_ZMQ +#ifdef ENABLE_ZMQ argsman.AddArg("-zmqpubhashblock=<address>", "Enable publish hash block in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); argsman.AddArg("-zmqpubhashtx=<address>", "Enable publish hash transaction in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); argsman.AddArg("-zmqpubrawblock=<address>", "Enable publish raw block in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); @@ -598,7 +605,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checklevel=<n>", strprintf("How thorough the block verification of -checkblocks is: %s (0-4, default: %u)", Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-checkblockindex", strprintf("Do a consistency check for the block tree, chainstate, and other validation data structures occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-checkblockindex", strprintf("Do a consistency check for the block tree, chainstate, and other validation data structures every <n> operations. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkaddrman=<n>", strprintf("Run addrman consistency checks every <n> operations. Use 0 to disable. (default: %u)", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkmempool=<n>", strprintf("Run mempool consistency checks every <n> transactions. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); @@ -612,12 +619,12 @@ 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)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINT_MODIFIED_FEE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); SetupChainParamsBaseOptions(argsman); @@ -633,7 +640,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)", @@ -652,8 +659,9 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); argsman.AddArg("-rpcdoccheck", strprintf("Throw a non-fatal error at runtime if the documentation for an RPC is incorrect (default: %u)", DEFAULT_RPC_DOC_CHECK), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC); argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); + argsman.AddArg("-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); @@ -661,6 +669,9 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC); argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); + if (can_listen_ipc) { + argsman.AddArg("-ipcbind=<address>", "Bind to Unix socket address and listen for incoming connections. Valid address values are \"unix\" to listen on the default path, <datadir>/node.sock, or \"unix:/custom/path\" to specify a custom path. Can be specified multiple times to listen on multiple paths. Default behavior is not to listen on any path. If relative paths are specified, they are interpreted relative to the network data directory. If paths include any parent directory components and the parent directories do not exist, they will be created.", ArgsManager::ALLOW_ANY, OptionsCategory::IPC); + } #if HAVE_DECL_FORK argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -674,21 +685,6 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddHiddenArgs(hidden_args); } -static bool fHaveGenesis = false; -static GlobalMutex g_genesis_wait_mutex; -static std::condition_variable g_genesis_wait_cv; - -static void BlockNotifyGenesisWait(const CBlockIndex* pBlockIndex) -{ - if (pBlockIndex != nullptr) { - { - LOCK(g_genesis_wait_mutex); - fHaveGenesis = true; - } - g_genesis_wait_cv.notify_all(); - } -} - #if HAVE_SYSTEM static void StartupNotify(const ArgsManager& args) { @@ -703,9 +699,7 @@ static void StartupNotify(const ArgsManager& args) static bool AppInitServers(NodeContext& node) { const ArgsManager& args = *Assert(node.args); - RPCServer::OnStarted(&OnRPCStarted); - RPCServer::OnStopped(&OnRPCStopped); - if (!InitHTTPServer(*Assert(node.shutdown))) { + if (!InitHTTPServer(*Assert(node.shutdown_signal))) { return false; } StartRPC(); @@ -724,73 +718,73 @@ void InitParameterInteraction(ArgsManager& args) // even when -connect or -proxy is specified if (args.IsArgSet("-bind")) { if (args.SoftSetBoolArg("-listen", true)) - LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__); + LogInfo("parameter interaction: -bind set -> setting -listen=1\n"); } if (args.IsArgSet("-whitebind")) { if (args.SoftSetBoolArg("-listen", true)) - LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); + LogInfo("parameter interaction: -whitebind set -> setting -listen=1\n"); } if (args.IsArgSet("-connect") || args.GetIntArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS) <= 0) { // when only connecting to trusted nodes, do not seed via DNS, or listen by default if (args.SoftSetBoolArg("-dnsseed", false)) - LogPrintf("%s: parameter interaction: -connect or -maxconnections=0 set -> setting -dnsseed=0\n", __func__); + LogInfo("parameter interaction: -connect or -maxconnections=0 set -> setting -dnsseed=0\n"); if (args.SoftSetBoolArg("-listen", false)) - LogPrintf("%s: parameter interaction: -connect or -maxconnections=0 set -> setting -listen=0\n", __func__); + LogInfo("parameter interaction: -connect or -maxconnections=0 set -> setting -listen=0\n"); } std::string proxy_arg = args.GetArg("-proxy", ""); if (proxy_arg != "" && proxy_arg != "0") { // to protect privacy, do not listen by default if a default proxy server is specified if (args.SoftSetBoolArg("-listen", false)) - LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); + LogInfo("parameter interaction: -proxy set -> setting -listen=0\n"); // to protect privacy, do not map ports when a proxy is set. The user may still specify -listen=1 // to listen locally, so don't rely on this happening through -listen below. if (args.SoftSetBoolArg("-upnp", false)) - LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); + LogInfo("parameter interaction: -proxy set -> setting -upnp=0\n"); if (args.SoftSetBoolArg("-natpmp", false)) { - LogPrintf("%s: parameter interaction: -proxy set -> setting -natpmp=0\n", __func__); + LogInfo("parameter interaction: -proxy set -> setting -natpmp=0\n"); } // to protect privacy, do not discover addresses by default if (args.SoftSetBoolArg("-discover", false)) - LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__); + LogInfo("parameter interaction: -proxy set -> setting -discover=0\n"); } if (!args.GetBoolArg("-listen", DEFAULT_LISTEN)) { // do not map ports or try to retrieve public IP when not listening (pointless) if (args.SoftSetBoolArg("-upnp", false)) - LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); + LogInfo("parameter interaction: -listen=0 -> setting -upnp=0\n"); if (args.SoftSetBoolArg("-natpmp", false)) { - LogPrintf("%s: parameter interaction: -listen=0 -> setting -natpmp=0\n", __func__); + LogInfo("parameter interaction: -listen=0 -> setting -natpmp=0\n"); } if (args.SoftSetBoolArg("-discover", false)) - LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); + LogInfo("parameter interaction: -listen=0 -> setting -discover=0\n"); if (args.SoftSetBoolArg("-listenonion", false)) - LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); + LogInfo("parameter interaction: -listen=0 -> setting -listenonion=0\n"); if (args.SoftSetBoolArg("-i2pacceptincoming", false)) { - LogPrintf("%s: parameter interaction: -listen=0 -> setting -i2pacceptincoming=0\n", __func__); + LogInfo("parameter interaction: -listen=0 -> setting -i2pacceptincoming=0\n"); } } if (args.IsArgSet("-externalip")) { // if an explicit public IP is specified, do not try to find others if (args.SoftSetBoolArg("-discover", false)) - LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__); + LogInfo("parameter interaction: -externalip set -> setting -discover=0\n"); } if (args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { // disable whitelistrelay in blocksonly mode if (args.SoftSetBoolArg("-whitelistrelay", false)) - LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__); + LogInfo("parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n"); // Reduce default mempool size in blocksonly mode to avoid unexpected resource usage if (args.SoftSetArg("-maxmempool", ToString(DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB))) - LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -maxmempool=%d\n", __func__, DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB); + LogInfo("parameter interaction: -blocksonly=1 -> setting -maxmempool=%d\n", DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB); } // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place. if (args.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { if (args.SoftSetBoolArg("-whitelistrelay", true)) - LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); + LogInfo("parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n"); } if (args.IsArgSet("-onlynet")) { const auto onlynets = args.GetArgs("-onlynet"); @@ -799,7 +793,7 @@ void InitParameterInteraction(ArgsManager& args) return n == NET_IPV4 || n == NET_IPV6; }); if (!clearnet_reachable && args.SoftSetBoolArg("-dnsseed", false)) { - LogPrintf("%s: parameter interaction: -onlynet excludes IPv4 and IPv6 -> setting -dnsseed=0\n", __func__); + LogInfo("parameter interaction: -onlynet excludes IPv4 and IPv6 -> setting -dnsseed=0\n"); } } } @@ -819,9 +813,8 @@ void InitLogging(const ArgsManager& args) namespace { // Variables internal to initialization process only int nMaxConnections; -int nUserMaxConnections; -int nFD; -ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS); +int available_fds; +ServiceFlags g_local_services = ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS); int64_t peer_connect_timeout; std::set<BlockFilterType> g_enabled_filter_types; @@ -831,10 +824,10 @@ std::set<BlockFilterType> g_enabled_filter_types; { // Rather than throwing std::bad-alloc if allocation fails, terminate // immediately to (try to) avoid chain corruption. - // Since LogPrintf may itself allocate memory, set the handler directly + // Since logging may itself allocate memory, set the handler directly // to terminate first. std::set_new_handler(std::terminate); - LogPrintf("Error: Out of memory. Terminating.\n"); + LogError("Out of memory. Terminating.\n"); // The log was successful, terminate now. std::terminate(); @@ -900,6 +893,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()) { @@ -931,7 +929,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) // Signal NODE_P2P_V2 if BIP324 v2 transport is enabled. if (args.GetBoolArg("-v2transport", DEFAULT_V2_TRANSPORT)) { - nLocalServices = ServiceFlags(nLocalServices | NODE_P2P_V2); + g_local_services = ServiceFlags(g_local_services | NODE_P2P_V2); } // Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled. @@ -940,7 +938,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) return InitError(_("Cannot set -peerblockfilters without -blockfilterindex.")); } - nLocalServices = ServiceFlags(nLocalServices | NODE_COMPACT_FILTERS); + g_local_services = ServiceFlags(g_local_services | NODE_COMPACT_FILTERS); } if (args.GetIntArg("-prune", 0)) { @@ -967,27 +965,33 @@ bool AppInitParameterInteraction(const ArgsManager& args) return InitError(Untranslated("Cannot set -listen=0 together with -listenonion=1")); } - // Make sure enough file descriptors are available - int nBind = std::max(nUserBind, size_t(1)); - nUserMaxConnections = args.GetIntArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); - nMaxConnections = std::max(nUserMaxConnections, 0); - - nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS + nBind + NUM_FDS_MESSAGE_CAPTURE); + // Make sure enough file descriptors are available. We need to reserve enough FDs to account for the bare minimum, + // plus all manual connections and all bound interfaces. Any remainder will be available for connection sockets -#ifdef USE_POLL - int fd_max = nFD; -#else - int fd_max = FD_SETSIZE; + // Number of bound interfaces (we have at least one) + int nBind = std::max(nUserBind, size_t(1)); + // Maximum number of connections with other nodes, this accounts for all types of outbounds and inbounds except for manual + int user_max_connection = args.GetIntArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); + if (user_max_connection < 0) { + return InitError(Untranslated("-maxconnections must be greater or equal than zero")); + } + // Reserve enough FDs to account for the bare minimum, plus any manual connections, plus the bound interfaces + int min_required_fds = MIN_CORE_FDS + MAX_ADDNODE_CONNECTIONS + nBind; + + // Try raising the FD limit to what we need (available_fds may be smaller than the requested amount if this fails) + available_fds = RaiseFileDescriptorLimit(user_max_connection + min_required_fds); + // If we are using select instead of poll, our actual limit may be even smaller +#ifndef USE_POLL + available_fds = std::min(FD_SETSIZE, available_fds); #endif + if (available_fds < min_required_fds) + return InitError(strprintf(_("Not enough file descriptors available. %d available, %d required."), available_fds, min_required_fds)); + // Trim requested connection counts, to fit into system limitations - // <int> in std::min<int>(...) to work around FreeBSD compilation issue described in #2695 - nMaxConnections = std::max(std::min<int>(nMaxConnections, fd_max - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS - NUM_FDS_MESSAGE_CAPTURE), 0); - if (nFD < MIN_CORE_FILEDESCRIPTORS) - return InitError(_("Not enough file descriptors available.")); - nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS - NUM_FDS_MESSAGE_CAPTURE, nMaxConnections); + nMaxConnections = std::min(available_fds - min_required_fds, user_max_connection); - if (nMaxConnections < nUserMaxConnections) - InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); + if (nMaxConnections < user_max_connection) + InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), user_max_connection, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags if (auto result{init::SetLoggingCategories(args)}; !result) return InitError(util::ErrorString(result)); @@ -1019,7 +1023,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) SetMockTime(args.GetIntArg("-mocktime", 0)); // SetMockTime(0) is a no-op if (args.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) - nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); + g_local_services = ServiceFlags(g_local_services | NODE_BLOOM); if (args.IsArgSet("-test")) { if (chainparams.GetChainType() != ChainType::REGTEST) { @@ -1058,6 +1062,13 @@ bool AppInitParameterInteraction(const ArgsManager& args) if (!blockman_result) { return InitError(util::ErrorString(blockman_result)); } + CTxMemPool::Options mempool_opts{ + .check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0, + }; + auto mempool_result{ApplyArgsManOptions(args, chainparams, mempool_opts)}; + if (!mempool_result) { + return InitError(util::ErrorString(mempool_result)); + } } return true; @@ -1111,9 +1122,155 @@ bool AppInitLockDataDirectory() bool AppInitInterfaces(NodeContext& node) { node.chain = node.init->makeChain(); + node.mining = node.init->makeMining(); return true; } +bool CheckHostPortOptions(const ArgsManager& args) { + for (const std::string port_option : { + "-port", + "-rpcport", + }) { + if (args.IsArgSet(port_option)) { + const std::string port = args.GetArg(port_option, ""); + uint16_t n; + if (!ParseUInt16(port, &n) || n == 0) { + return InitError(InvalidPortErrMsg(port_option, port)); + } + } + } + + for ([[maybe_unused]] const auto& [arg, unix] : std::vector<std::pair<std::string, bool>>{ + // arg name UNIX socket support + {"-i2psam", false}, + {"-onion", true}, + {"-proxy", true}, + {"-rpcbind", false}, + {"-torcontrol", false}, + {"-whitebind", false}, + {"-zmqpubhashblock", true}, + {"-zmqpubhashtx", true}, + {"-zmqpubrawblock", true}, + {"-zmqpubrawtx", true}, + {"-zmqpubsequence", true}, + }) { + for (const std::string& socket_addr : args.GetArgs(arg)) { + std::string host_out; + uint16_t port_out{0}; + if (!SplitHostPort(socket_addr, port_out, host_out)) { +#ifdef HAVE_SOCKADDR_UN + // Allow unix domain sockets for some options e.g. unix:/some/file/path + if (!unix || !socket_addr.starts_with(ADDR_PREFIX_UNIX)) { + return InitError(InvalidPortErrMsg(arg, socket_addr)); + } +#else + return InitError(InvalidPortErrMsg(arg, socket_addr)); +#endif + } + } + } + + return true; +} + +// A GUI user may opt to retry once if there is a failure during chainstate initialization. +// The function therefore has to support re-entry. +static ChainstateLoadResult InitAndLoadChainstate( + NodeContext& node, + bool do_reindex, + const bool do_reindex_chainstate, + CacheSizes& cache_sizes, + const ArgsManager& args) +{ + const CChainParams& chainparams = Params(); + CTxMemPool::Options mempool_opts{ + .check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0, + .signals = node.validation_signals.get(), + }; + Assert(ApplyArgsManOptions(args, chainparams, mempool_opts)); // no error can happen, already checked in AppInitParameterInteraction + bilingual_str mempool_error; + node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error); + if (!mempool_error.empty()) { + return {ChainstateLoadStatus::FAILURE_FATAL, mempool_error}; + } + 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)); + ChainstateManager::Options chainman_opts{ + .chainparams = chainparams, + .datadir = args.GetDataDirNet(), + .notifications = *node.notifications, + .signals = node.validation_signals.get(), + }; + Assert(ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction + BlockManager::Options blockman_opts{ + .chainparams = chainman_opts.chainparams, + .blocks_dir = args.GetBlocksDirPath(), + .notifications = chainman_opts.notifications, + }; + Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction + try { + node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts); + } catch (std::exception& e) { + return {ChainstateLoadStatus::FAILURE_FATAL, 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 + // dependency between validation and index/base, since the latter is not in + // libbitcoinkernel. + chainman.snapshot_download_completed = [&node]() { + if (!node.chainman->m_blockman.IsPruneMode()) { + LogPrintf("[snapshot] re-enabling NODE_NETWORK services\n"); + node.connman->AddLocalServices(NODE_NETWORK); + } + LogPrintf("[snapshot] restarting indexes\n"); + // Drain the validation interface queue to ensure that the old indexes + // don't have any pending work. + Assert(node.validation_signals)->SyncWithValidationInterfaceQueue(); + for (auto* index : node.indexes) { + index->Interrupt(); + index->Stop(); + if (!(index->Init() && index->StartBackgroundSync())) { + LogPrintf("[snapshot] WARNING failed to restart index %s on snapshot chain\n", index->GetName()); + } + } + }; + node::ChainstateLoadOptions options; + options.mempool = Assert(node.mempool.get()); + options.wipe_block_tree_db = do_reindex; + options.wipe_chainstate_db = do_reindex || do_reindex_chainstate; + options.prune = chainman.m_blockman.IsPruneMode(); + options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); + options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL); + options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel"); + options.coins_error_cb = [] { + uiInterface.ThreadSafeMessageBox( + _("Error reading from database, shutting down."), + "", CClientUIInterface::MSG_ERROR); + }; + uiInterface.InitMessage(_("Loading block index…").translated); + const auto load_block_index_start_time{SteadyClock::now()}; + auto catch_exceptions = [](auto&& f) { + try { + return f(); + } catch (const std::exception& e) { + LogError("%s\n", e.what()); + return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database")); + } + }; + auto [status, error] = catch_exceptions([&] { return LoadChainstate(chainman, cache_sizes, options); }); + if (status == node::ChainstateLoadStatus::SUCCESS) { + uiInterface.InitMessage(_("Verifying blocks…").translated); + if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) { + LogWarning("pruned datadir may not have more than %d blocks; only checking available blocks\n", + MIN_BLOCKS_TO_KEEP); + } + std::tie(status, error) = catch_exceptions([&] { return VerifyLoadedChainstate(chainman, options); }); + if (status == node::ChainstateLoadStatus::SUCCESS) { + LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time)); + } + } + return {status, error}; +}; + bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) { const ArgsManager& args = *Assert(node.args); @@ -1134,7 +1291,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return false; } - LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); + LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, available_fds); // Warn about relative -datadir path. if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) { @@ -1145,14 +1302,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; @@ -1169,9 +1318,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) scheduler.scheduleEvery([&args, &node]{ constexpr uint64_t min_disk_space = 50 << 20; // 50 MB if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) { - LogPrintf("Shutting down due to lack of disk space!\n"); - if (!(*Assert(node.shutdown))()) { - LogPrintf("Error: failed to send shutdown signal after disk space check\n"); + LogError("Shutting down due to lack of disk space!\n"); + if (!(Assert(node.shutdown_request))()) { + LogError("Failed to send shutdown signal after disk space check\n"); } } }, std::chrono::minutes{5}); @@ -1187,6 +1336,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) g_wallet_init_interface.Construct(node); uiInterface.InitWallet(); + if (interfaces::Ipc* ipc = node.init->ipc()) { + for (std::string address : gArgs.GetArgs("-ipcbind")) { + try { + ipc->listenAddress(address); + } catch (const std::exception& e) { + return InitError(strprintf(Untranslated("Unable to bind to IPC address '%s'. %s"), address, e.what())); + } + LogPrintf("Listening for IPC requests on address %s\n", address); + } + } + /* Register RPC commands regardless of -server setting so they will be * available in the GUI RPC console even if external calls are disabled. */ @@ -1194,10 +1354,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) for (const auto& client : node.chain_clients) { client->registerRpcs(); } -#if ENABLE_ZMQ +#ifdef ENABLE_ZMQ RegisterZMQRPCCommands(tableRPC); #endif + // Check port numbers + if (!CheckHostPortOptions(args)) return false; + /* Start the RPC server already. It will be started in "warmup" mode * and not really process calls already (but it will signify connections * that the server is there and will be ready later). Warmup mode will @@ -1264,11 +1427,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); @@ -1287,50 +1451,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) validation_signals.RegisterValidationInterface(fee_estimator); } - // Check port numbers - for (const std::string port_option : { - "-port", - "-rpcport", - }) { - if (args.IsArgSet(port_option)) { - const std::string port = args.GetArg(port_option, ""); - uint16_t n; - if (!ParseUInt16(port, &n) || n == 0) { - return InitError(InvalidPortErrMsg(port_option, port)); - } - } - } - - for ([[maybe_unused]] const auto& [arg, unix] : std::vector<std::pair<std::string, bool>>{ - // arg name UNIX socket support - {"-i2psam", false}, - {"-onion", true}, - {"-proxy", true}, - {"-rpcbind", false}, - {"-torcontrol", false}, - {"-whitebind", false}, - {"-zmqpubhashblock", true}, - {"-zmqpubhashtx", true}, - {"-zmqpubrawblock", true}, - {"-zmqpubrawtx", true}, - {"-zmqpubsequence", true}, - }) { - for (const std::string& socket_addr : args.GetArgs(arg)) { - std::string host_out; - uint16_t port_out{0}; - if (!SplitHostPort(socket_addr, port_out, host_out)) { -#if HAVE_SOCKADDR_UN - // Allow unix domain sockets for some options e.g. unix:/some/file/path - if (!unix || socket_addr.find(ADDR_PREFIX_UNIX) != 0) { - return InitError(InvalidPortErrMsg(arg, socket_addr)); - } -#else - return InitError(InvalidPortErrMsg(arg, socket_addr)); -#endif - } - } - } - for (const std::string& socket_addr : args.GetArgs("-bind")) { std::string host_out; uint16_t port_out{0}; @@ -1466,7 +1586,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return InitError(ResolveErrMsg("externalip", strAddr)); } -#if ENABLE_ZMQ +#ifdef ENABLE_ZMQ g_zmq_notification_interface = CZMQNotificationInterface::Create( [&chainman = node.chainman](std::vector<uint8_t>& block, const CBlockIndex& index) { assert(chainman); @@ -1480,23 +1600,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 7: load block chain - node.notifications = std::make_unique<KernelNotifications>(*Assert(node.shutdown), node.exit_status); - ReadNotificationArgs(args, *node.notifications); - bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false); - ChainstateManager::Options chainman_opts{ - .chainparams = chainparams, - .datadir = args.GetDataDirNet(), - .notifications = *node.notifications, - .signals = &validation_signals, - }; - Assert(ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction - - BlockManager::Options blockman_opts{ - .chainparams = chainman_opts.chainparams, - .blocks_dir = args.GetBlocksDirPath(), - .notifications = chainman_opts.notifications, - }; - Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction + node.notifications = std::make_unique<KernelNotifications>(Assert(node.shutdown_request), node.exit_status, *Assert(node.warnings)); + auto& kernel_notifications{*node.notifications}; + ReadNotificationArgs(args, kernel_notifications); // cache size calculations CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size()); @@ -1515,109 +1621,39 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) assert(!node.mempool); assert(!node.chainman); - CTxMemPool::Options mempool_opts{ - .check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0, - .signals = &validation_signals, - }; - auto result{ApplyArgsManOptions(args, chainparams, mempool_opts)}; - if (!result) { - return InitError(util::ErrorString(result)); - } - mempool_opts.check_ratio = std::clamp<int>(mempool_opts.check_ratio, 0, 1'000'000); - - int64_t descendant_limit_bytes = mempool_opts.limits.descendant_size_vbytes * 40; - if (mempool_opts.max_size_bytes < 0 || mempool_opts.max_size_bytes < descendant_limit_bytes) { - return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0))); - } - 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)); - - for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) { - node.mempool = std::make_unique<CTxMemPool>(mempool_opts); - - node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts); - ChainstateManager& chainman = *node.chainman; - - // This is defined and set here instead of inline in validation.h to avoid a hard - // dependency between validation and index/base, since the latter is not in - // libbitcoinkernel. - chainman.restart_indexes = [&node]() { - LogPrintf("[snapshot] restarting indexes\n"); - - // Drain the validation interface queue to ensure that the old indexes - // don't have any pending work. - Assert(node.validation_signals)->SyncWithValidationInterfaceQueue(); - - for (auto* index : node.indexes) { - index->Interrupt(); - index->Stop(); - if (!(index->Init() && index->StartBackgroundSync())) { - LogPrintf("[snapshot] WARNING failed to restart index %s on snapshot chain\n", index->GetName()); - } - } - }; - - node::ChainstateLoadOptions options; - options.mempool = Assert(node.mempool.get()); - options.reindex = chainman.m_blockman.m_reindexing; - options.reindex_chainstate = fReindexChainState; - options.prune = chainman.m_blockman.IsPruneMode(); - options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); - options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL); - options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel"); - options.coins_error_cb = [] { - uiInterface.ThreadSafeMessageBox( - _("Error reading from database, shutting down."), - "", CClientUIInterface::MSG_ERROR); - }; - - uiInterface.InitMessage(_("Loading block index…").translated); - const auto load_block_index_start_time{SteadyClock::now()}; - auto catch_exceptions = [](auto&& f) { - try { - return f(); - } catch (const std::exception& e) { - LogPrintf("%s\n", e.what()); - return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database")); - } - }; - auto [status, error] = catch_exceptions([&]{ return LoadChainstate(chainman, cache_sizes, options); }); - if (status == node::ChainstateLoadStatus::SUCCESS) { - uiInterface.InitMessage(_("Verifying blocks…").translated); - if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) { - LogWarning("pruned datadir may not have more than %d blocks; only checking available blocks\n", - MIN_BLOCKS_TO_KEEP); - } - std::tie(status, error) = catch_exceptions([&]{ return VerifyLoadedChainstate(chainman, options);}); - if (status == node::ChainstateLoadStatus::SUCCESS) { - fLoaded = true; - LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time)); - } - } - - if (status == node::ChainstateLoadStatus::FAILURE_FATAL || status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) { - return InitError(error); + bool do_reindex{args.GetBoolArg("-reindex", false)}; + const bool do_reindex_chainstate{args.GetBoolArg("-reindex-chainstate", false)}; + + // Chainstate initialization and loading may be retried once with reindexing by GUI users + auto [status, error] = InitAndLoadChainstate( + node, + do_reindex, + do_reindex_chainstate, + cache_sizes, + args); + if (status == ChainstateLoadStatus::FAILURE && !do_reindex && !ShutdownRequested(node)) { + // suggest a reindex + bool do_retry = uiInterface.ThreadSafeQuestion( + error + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"), + error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", + "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); + if (!do_retry) { + LogError("Aborted block database rebuild. Exiting.\n"); + return false; } - - if (!fLoaded && !ShutdownRequested(node)) { - // first suggest a reindex - if (!options.reindex) { - bool fRet = uiInterface.ThreadSafeQuestion( - error + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"), - error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", - "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); - if (fRet) { - chainman.m_blockman.m_reindexing = true; - if (!Assert(node.shutdown)->reset()) { - LogPrintf("Internal error: failed to reset shutdown signal.\n"); - } - } else { - LogPrintf("Aborted block database rebuild. Exiting.\n"); - return false; - } - } else { - return InitError(error); - } + do_reindex = true; + if (!Assert(node.shutdown_signal)->reset()) { + LogError("Internal error: failed to reset shutdown signal.\n"); } + std::tie(status, error) = InitAndLoadChainstate( + node, + do_reindex, + do_reindex_chainstate, + cache_sizes, + args); + } + if (status != ChainstateLoadStatus::SUCCESS && status != ChainstateLoadStatus::INTERRUPTED) { + return InitError(error); } // As LoadBlockIndex can take several minutes, it's possible the user @@ -1633,23 +1669,24 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) assert(!node.peerman); node.peerman = PeerManager::make(*node.connman, *node.addrman, node.banman.get(), chainman, - *node.mempool, peerman_opts); + *node.mempool, *node.warnings, + peerman_opts); validation_signals.RegisterValidationInterface(node.peerman.get()); // ********************************************************* Step 8: start indexers if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, chainman.m_blockman.m_reindexing); + g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, do_reindex); node.indexes.emplace_back(g_txindex.get()); } for (const auto& filter_type : g_enabled_filter_types) { - InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, chainman.m_blockman.m_reindexing); + InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, do_reindex); node.indexes.emplace_back(GetBlockFilterIndex(filter_type)); } if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) { - g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, chainman.m_blockman.m_reindexing); + g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, do_reindex); node.indexes.emplace_back(g_coin_stats_index.get()); } @@ -1668,7 +1705,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // if pruning, perform the initial blockstore prune // after any wallet rescanning has taken place. if (chainman.m_blockman.IsPruneMode()) { - if (!chainman.m_blockman.m_reindexing) { + if (chainman.m_blockman.m_blockfiles_indexed) { LOCK(cs_main); for (Chainstate* chainstate : chainman.GetAll()) { uiInterface.InitMessage(_("Pruning blockstore…").translated); @@ -1676,8 +1713,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } } } else { - LogPrintf("Setting NODE_NETWORK on non-prune mode\n"); - nLocalServices = ServiceFlags(nLocalServices | NODE_NETWORK); + // Prior to setting NODE_NETWORK, check if we can provide historical blocks. + if (!WITH_LOCK(chainman.GetMutex(), return chainman.BackgroundSyncInProgress())) { + LogPrintf("Setting NODE_NETWORK on non-prune mode\n"); + g_local_services = ServiceFlags(g_local_services | NODE_NETWORK); + } else { + LogPrintf("Running node in NODE_NETWORK_LIMITED mode until snapshot background sync completes\n"); + } } // ********************************************************* Step 11: import blocks @@ -1694,7 +1736,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height()); // On first startup, warn on low block storage space - if (!chainman.m_blockman.m_reindexing && !fReindexChainState && chain_active_height <= 1) { + if (!do_reindex && !do_reindex_chainstate && chain_active_height <= 1) { uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024}; uint64_t additional_bytes_needed{ chainman.m_blockman.IsPruneMode() ? @@ -1712,15 +1754,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } } - // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. - // No locking, as this happens before any background thread is started. - boost::signals2::connection block_notify_genesis_wait_connection; - if (WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip() == nullptr)) { - block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(std::bind(BlockNotifyGenesisWait, std::placeholders::_2)); - } else { - fHaveGenesis = true; - } - #if HAVE_SYSTEM const std::string block_notify = args.GetArg("-blocknotify", ""); if (!block_notify.empty()) { @@ -1739,14 +1772,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) vImportFiles.push_back(fs::PathFromString(strFile)); } - chainman.m_thread_load = std::thread(&util::TraceThread, "initload", [=, &chainman, &args, &node] { + node.background_init_thread = std::thread(&util::TraceThread, "initload", [=, &chainman, &args, &node] { ScheduleBatchPriority(); // Import blocks ImportBlocks(chainman, vImportFiles); if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); - if (!(*Assert(node.shutdown))()) { - LogPrintf("Error: failed to send shutdown signal after finishing block import\n"); + if (!(Assert(node.shutdown_request))()) { + LogError("Failed to send shutdown signal after finishing block import\n"); } return; } @@ -1765,15 +1798,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) }); // Wait for genesis block to be processed - { - WAIT_LOCK(g_genesis_wait_mutex, lock); - // We previously could hang here if shutdown was requested prior to - // ImportBlocks getting started, so instead we just wait on a timer to - // check ShutdownRequested() regularly. - while (!fHaveGenesis && !ShutdownRequested(node)) { - g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500)); - } - block_notify_genesis_wait_connection.disconnect(); + if (WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip() == nullptr)) { + WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock); + kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) { + return !kernel_notifications.m_tip_block.IsNull() || ShutdownRequested(node); + }); } if (ShutdownRequested(node)) { @@ -1782,17 +1811,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 12: start node - //// debug print int64_t best_block_time{}; { - LOCK(cs_main); + LOCK(chainman.GetMutex()); + const auto& tip{*Assert(chainman.ActiveTip())}; LogPrintf("block tree size = %u\n", chainman.BlockIndex().size()); - chain_active_height = chainman.ActiveChain().Height(); - best_block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : chainman.GetParams().GenesisBlock().GetBlockTime(); + chain_active_height = tip.nHeight; + best_block_time = tip.GetBlockTime(); if (tip_info) { tip_info->block_height = chain_active_height; tip_info->block_time = best_block_time; - tip_info->verification_progress = GuessVerificationProgress(chainman.GetParams().TxData(), chainman.ActiveChain().Tip()); + tip_info->verification_progress = GuessVerificationProgress(chainman.GetParams().TxData(), &tip); } if (tip_info && chainman.m_best_header) { tip_info->header_height = chainman.m_best_header->nHeight; @@ -1802,11 +1831,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) LogPrintf("nBestHeight = %d\n", chain_active_height); if (node.peerman) node.peerman->SetBestBlock(chain_active_height, std::chrono::seconds{best_block_time}); - // Map ports with UPnP or NAT-PMP. + // Map ports with UPnP or NAT-PMP StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), args.GetBoolArg("-natpmp", DEFAULT_NATPMP)); CConnman::Options connOptions; - connOptions.nLocalServices = nLocalServices; + connOptions.m_local_services = g_local_services; connOptions.m_max_automatic_connections = nMaxConnections; connOptions.uiInterface = &uiInterface; connOptions.m_banman = node.banman.get(); @@ -1880,6 +1909,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); @@ -1959,11 +1990,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // cannot yet be called. Before we make it callable, we need to make sure // that the RPC's view of the best block is valid and consistent with // ChainstateManager's active tip. - // - // If we do not do this, RPC's view of the best block will be height=0 and - // hash=0x0. This will lead to erroroneous responses for things like - // waitforblockheight. - RPCNotifyBlockChange(WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip())); SetRPCWarmupFinished(); uiInterface.InitMessage(_("Done loading").translated); diff --git a/src/init.h b/src/init.h index ead5f5e0d2..6d8a35d80e 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; @@ -76,7 +74,7 @@ bool AppInitMain(node::NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip /** * Register all arguments with the ArgsManager */ -void SetupServerArgs(ArgsManager& argsman); +void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc=false); /** Validates requirements to run the indexes and spawns each index initial sync thread */ bool StartIndexBackgroundSync(node::NodeContext& node); diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp index aceff1e40f..eae30bc995 100644 --- a/src/init/bitcoin-gui.cpp +++ b/src/init/bitcoin-gui.cpp @@ -34,6 +34,11 @@ public: } std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } + // bitcoin-gui accepts -ipcbind option even though it does not use it + // directly. It just returns true here to accept the option because + // bitcoin-node accepts the option, and bitcoin-gui accepts all bitcoin-node + // options and will start the node with those options. + bool canListenIpc() override { return true; } node::NodeContext m_node; std::unique_ptr<interfaces::Ipc> m_ipc; }; diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 97b8dc1161..3f8c50b8d6 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -30,12 +30,14 @@ public: } std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); } + std::unique_ptr<interfaces::Mining> makeMining() override { return interfaces::MakeMining(m_node); } std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override { return MakeWalletLoader(chain, *Assert(m_node.args)); } std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } + bool canListenIpc() override { return true; } node::NodeContext& m_node; std::unique_ptr<interfaces::Ipc> m_ipc; }; diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp index 3003a8fde1..5209c72973 100644 --- a/src/init/bitcoin-qt.cpp +++ b/src/init/bitcoin-qt.cpp @@ -6,6 +6,7 @@ #include <interfaces/chain.h> #include <interfaces/echo.h> #include <interfaces/init.h> +#include <interfaces/mining.h> #include <interfaces/node.h> #include <interfaces/wallet.h> #include <node/context.h> @@ -25,6 +26,7 @@ public: } std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); } + std::unique_ptr<interfaces::Mining> makeMining() override { return interfaces::MakeMining(m_node); } std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override { return MakeWalletLoader(chain, *Assert(m_node.args)); diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index b5df764017..48be8831d2 100644 --- a/src/init/bitcoind.cpp +++ b/src/init/bitcoind.cpp @@ -6,6 +6,7 @@ #include <interfaces/chain.h> #include <interfaces/echo.h> #include <interfaces/init.h> +#include <interfaces/mining.h> #include <interfaces/node.h> #include <interfaces/wallet.h> #include <node/context.h> @@ -27,6 +28,7 @@ public: } std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); } + std::unique_ptr<interfaces::Mining> makeMining() override { return interfaces::MakeMining(m_node); } std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override { return MakeWalletLoader(chain, *Assert(m_node.args)); diff --git a/src/init/common.cpp b/src/init/common.cpp index f473ee6d66..dd8ca020d2 100644 --- a/src/init/common.cpp +++ b/src/init/common.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <clientversion.h> #include <common/args.h> @@ -20,14 +20,16 @@ #include <string> #include <vector> +using util::SplitString; + namespace init { 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..4e858d1f89 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -41,12 +41,6 @@ namespace interfaces { class Handler; class Wallet; -//! Hash/height pair to help track and identify blocks. -struct BlockKey { - uint256 hash; - int height = -1; -}; - //! Helper for findBlock to selectively return pieces of block data. If block is //! found, data will be returned by setting specified output variables. If block //! is not found, output variables will keep their previous values. @@ -96,6 +90,17 @@ struct BlockInfo { BlockInfo(const uint256& hash LIFETIMEBOUND) : hash(hash) {} }; +//! The action to be taken after updating a settings value. +//! WRITE indicates that the updated value must be written to disk, +//! while SKIP_WRITE indicates that the change will be kept in memory-only +//! without persisting it. +enum class SettingsAction { + WRITE, + SKIP_WRITE +}; + +using SettingsUpdate = std::function<std::optional<interfaces::SettingsAction>(common::SettingsValue&)>; + //! Interface giving clients (wallet processes, maybe other analysis tools in //! the future) ability to access to the chain state, receive notifications, //! estimate fees, and submit transactions. @@ -123,7 +128,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 +314,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) {} @@ -344,9 +349,23 @@ public: //! Return <datadir>/settings.json setting value. virtual common::SettingsValue getRwSetting(const std::string& name) = 0; - //! Write a setting to <datadir>/settings.json. Optionally just update the - //! setting in memory and do not write the file. - virtual bool updateRwSetting(const std::string& name, const common::SettingsValue& value, bool write=true) = 0; + //! Updates a setting in <datadir>/settings.json. + //! Null can be passed to erase the setting. There is intentionally no + //! support for writing null values to settings.json. + //! Depending on the action returned by the update function, this will either + //! update the setting in memory or write the updated settings to disk. + virtual bool updateRwSetting(const std::string& name, const SettingsUpdate& update_function) = 0; + + //! Replace a setting in <datadir>/settings.json with a new value. + //! Null can be passed to erase the setting. + //! This method provides a simpler alternative to updateRwSetting when + //! atomically reading and updating the setting is not required. + virtual bool overwriteRwSetting(const std::string& name, common::SettingsValue value, SettingsAction action = SettingsAction::WRITE) = 0; + + //! Delete a given setting in <datadir>/settings.json. + //! This method provides a simpler alternative to overwriteRwSetting when + //! erasing a setting, for ease of use and readability. + virtual bool deleteRwSettings(const std::string& name, SettingsAction action = SettingsAction::WRITE) = 0; //! Synchronously send transactionAddedToMempool notifications about all //! current mempool transactions to the specified handler and return after @@ -371,7 +390,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/init.h b/src/interfaces/init.h index addc45aa26..b496ada05f 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -7,6 +7,7 @@ #include <interfaces/chain.h> #include <interfaces/echo.h> +#include <interfaces/mining.h> #include <interfaces/node.h> #include <interfaces/wallet.h> @@ -32,9 +33,11 @@ public: virtual ~Init() = default; virtual std::unique_ptr<Node> makeNode() { return nullptr; } virtual std::unique_ptr<Chain> makeChain() { return nullptr; } + virtual std::unique_ptr<Mining> makeMining() { return nullptr; } virtual std::unique_ptr<WalletLoader> makeWalletLoader(Chain& chain) { return nullptr; } virtual std::unique_ptr<Echo> makeEcho() { return nullptr; } virtual Ipc* ipc() { return nullptr; } + virtual bool canListenIpc() { return false; } }; //! Return implementation of Init interface for the node process. If the argv diff --git a/src/interfaces/ipc.h b/src/interfaces/ipc.h index 963649fc9a..fb340552c5 100644 --- a/src/interfaces/ipc.h +++ b/src/interfaces/ipc.h @@ -41,6 +41,11 @@ class Init; //! to make other proxy objects calling other remote interfaces. It can also //! destroy the initial interfaces::Init object to close the connection and //! shut down the spawned process. +//! +//! When connecting to an existing process, the steps are similar to spawning a +//! new process, except a socket is created instead of a socketpair, and +//! destroying an Init interface doesn't end the process, since there can be +//! multiple connections. class Ipc { public: @@ -54,6 +59,17 @@ public: //! true. If this is not a spawned child process, return false. virtual bool startSpawnedProcess(int argc, char* argv[], int& exit_status) = 0; + //! Connect to a socket address and make a client interface proxy object + //! using provided callback. connectAddress returns an interface pointer if + //! the connection was established, returns null if address is empty ("") or + //! disabled ("0") or if a connection was refused but not required ("auto"), + //! and throws an exception if there was an unexpected error. + virtual std::unique_ptr<Init> connectAddress(std::string& address) = 0; + + //! Connect to a socket address and make a client interface proxy object + //! using provided callback. Throws an exception if there was an error. + virtual void listenAddress(std::string& address) = 0; + //! Add cleanup callback to remote interface that will run when the //! interface is deleted. template<typename Interface> diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h new file mode 100644 index 0000000000..c77f3c30a2 --- /dev/null +++ b/src/interfaces/mining.h @@ -0,0 +1,132 @@ +// 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. + +#ifndef BITCOIN_INTERFACES_MINING_H +#define BITCOIN_INTERFACES_MINING_H + +#include <consensus/amount.h> // for CAmount +#include <interfaces/types.h> // for BlockRef +#include <node/types.h> // for BlockCreateOptions +#include <primitives/block.h> // for CBlock, CBlockHeader +#include <primitives/transaction.h> // for CTransactionRef +#include <stdint.h> // for int64_t +#include <uint256.h> // for uint256 +#include <util/time.h> // for MillisecondsDouble + +#include <memory> // for unique_ptr, shared_ptr +#include <optional> // for optional +#include <vector> // for vector + +namespace node { +struct NodeContext; +} // namespace node + +class BlockValidationState; +class CScript; + +namespace interfaces { + +//! Block template interface +class BlockTemplate +{ +public: + virtual ~BlockTemplate() = default; + + virtual CBlockHeader getBlockHeader() = 0; + virtual CBlock getBlock() = 0; + + virtual std::vector<CAmount> getTxFees() = 0; + virtual std::vector<int64_t> getTxSigops() = 0; + + virtual CTransactionRef getCoinbaseTx() = 0; + virtual std::vector<unsigned char> getCoinbaseCommitment() = 0; + virtual int getWitnessCommitmentIndex() = 0; + + /** + * Compute merkle path to the coinbase transaction + * + * @return merkle path ordered from the deepest + */ + virtual std::vector<uint256> getCoinbaseMerklePath() = 0; + + /** + * Construct and broadcast the block. + * + * @returns if the block was processed, independent of block validity + */ + virtual bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CMutableTransaction coinbase) = 0; +}; + +//! Interface giving clients (RPC, Stratum v2 Template Provider in the future) +//! ability to create block templates. +class Mining +{ +public: + virtual ~Mining() = default; + + //! If this chain is exclusively used for testing + virtual bool isTestChain() = 0; + + //! Returns whether IBD is still in progress. + virtual bool isInitialBlockDownload() = 0; + + //! Returns the hash and height for the tip of this chain + virtual std::optional<BlockRef> getTip() = 0; + + /** + * Waits for the connected tip to change. If the tip was not connected on + * startup, this will wait. + * + * @param[in] current_tip block hash of the current chain tip. Function waits + * for the chain tip to differ from this. + * @param[in] timeout how long to wait for a new tip + * @returns Hash and height of the current chain tip after this call. + */ + virtual BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout = MillisecondsDouble::max()) = 0; + + /** + * Construct a new block template + * + * @param[in] script_pub_key the coinbase output + * @param[in] options options for creating the block + * @returns a block template + */ + virtual std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options = {}) = 0; + + /** + * Processes new block. A valid new block is automatically relayed to peers. + * + * @param[in] block The block we want to process. + * @param[out] new_block A boolean which is set to indicate if the block was first received via this call + * @returns If the block was processed, independently of block validity + */ + virtual bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) = 0; + + //! Return the number of transaction updates in the mempool, + //! used to decide whether to make a new block template. + virtual unsigned int getTransactionsUpdated() = 0; + + /** + * Check a block is completely valid from start to finish. + * Only works on top of our current best block. + * Does not check proof-of-work. + * + * @param[in] block the block to validate + * @param[in] check_merkle_root call CheckMerkleRoot() + * @param[out] state details of why a block failed to validate + * @returns false if it does not build on the current tip, or any of the checks fail + */ + virtual bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) = 0; + + //! Get internal node context. Useful for RPC and testing, + //! but not accessible across processes. + virtual node::NodeContext* context() { return nullptr; } +}; + +//! Return implementation of Mining interface. +std::unique_ptr<Mining> MakeMining(node::NodeContext& node); + +} // namespace interfaces + +#endif // BITCOIN_INTERFACES_MINING_H diff --git a/src/interfaces/node.h b/src/interfaces/node.h index aeb2612c07..91a623a65d 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -7,6 +7,7 @@ #include <common/settings.h> #include <consensus/amount.h> // For CAmount +#include <logging.h> // For BCLog::CategoryMask #include <net.h> // For NodeId #include <net_types.h> // For banmap_t #include <netaddress.h> // For Network @@ -30,10 +31,10 @@ class RPCTimerInterface; class UniValue; class Proxy; enum class SynchronizationState; -enum class TransactionError; struct CNodeStateStats; struct bilingual_str; namespace node { +enum class TransactionError; struct NodeContext; } // namespace node namespace wallet { @@ -59,7 +60,7 @@ struct BlockAndHeaderTipInfo class ExternalSigner { public: - virtual ~ExternalSigner() {}; + virtual ~ExternalSigner() = default; //! Get signer display name virtual std::string getName() = 0; @@ -69,7 +70,7 @@ public: class Node { public: - virtual ~Node() {} + virtual ~Node() = default; //! Init logging. virtual void initLogging() = 0; @@ -84,7 +85,7 @@ public: virtual int getExitStatus() = 0; // Get log flags. - virtual uint32_t getLogCategories() = 0; + virtual BCLog::CategoryMask getLogCategories() = 0; //! Initialize app dependencies. virtual bool baseInitialize() = 0; @@ -120,7 +121,7 @@ public: virtual void resetSettings() = 0; //! Map port. - virtual void mapPort(bool use_upnp, bool use_natpmp) = 0; + virtual void mapPort(bool use_upnp, bool use_pcp) = 0; //! Get proxy. virtual bool getProxy(Network net, Proxy& proxy_info) = 0; @@ -162,12 +163,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; @@ -208,7 +215,7 @@ public: virtual std::optional<Coin> getUnspentOutput(const COutPoint& output) = 0; //! Broadcast transaction. - virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0; + virtual node::TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0; //! Get wallet loader. virtual WalletLoader& walletLoader() = 0; diff --git a/src/interfaces/types.h b/src/interfaces/types.h new file mode 100644 index 0000000000..e5edd301a7 --- /dev/null +++ b/src/interfaces/types.h @@ -0,0 +1,20 @@ +// 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. + +#ifndef BITCOIN_INTERFACES_TYPES_H +#define BITCOIN_INTERFACES_TYPES_H + +#include <uint256.h> + +namespace interfaces { + +//! Hash/height pair to help track and identify blocks. +struct BlockRef { + uint256 hash; + int height = -1; +}; + +} // namespace interfaces + +#endif // BITCOIN_INTERFACES_TYPES_H diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index c41f35829d..df1ced48a7 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -6,13 +6,13 @@ #define BITCOIN_INTERFACES_WALLET_H #include <addresstype.h> +#include <common/signmessage.h> #include <consensus/amount.h> #include <interfaces/chain.h> #include <pubkey.h> #include <script/script.h> #include <support/allocators/secure.h> #include <util/fs.h> -#include <util/message.h> #include <util/result.h> #include <util/ui_change_type.h> @@ -30,9 +30,14 @@ class CFeeRate; class CKey; enum class FeeReason; enum class OutputType; -enum class TransactionError; struct PartiallySignedTransaction; struct bilingual_str; +namespace common { +enum class PSBTError; +} // namespace common +namespace node { +enum class TransactionError; +} // namespace node namespace wallet { class CCoinControl; class CWallet; @@ -60,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; @@ -202,7 +207,7 @@ public: int& num_blocks) = 0; //! Fill PSBT. - virtual TransactionError fillPSBT(int sighash_type, + virtual std::optional<common::PSBTError> fillPSBT(int sighash_type, bool sign, bool bip32derivs, size_t* n_signed, @@ -337,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/ipc/CMakeLists.txt b/src/ipc/CMakeLists.txt new file mode 100644 index 0000000000..904d72f56e --- /dev/null +++ b/src/ipc/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_library(bitcoin_ipc STATIC EXCLUDE_FROM_ALL + capnp/mining.cpp + capnp/protocol.cpp + interfaces.cpp + process.cpp +) + +target_capnp_sources(bitcoin_ipc ${PROJECT_SOURCE_DIR} + capnp/common.capnp + capnp/echo.capnp + capnp/init.capnp + capnp/mining.capnp +) + +target_link_libraries(bitcoin_ipc + PRIVATE + core_interface + univalue +) diff --git a/src/ipc/capnp/.gitignore b/src/ipc/capnp/.gitignore deleted file mode 100644 index 036df1430c..0000000000 --- a/src/ipc/capnp/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# capnp generated files -*.capnp.* diff --git a/src/ipc/capnp/common-types.h b/src/ipc/capnp/common-types.h index 39e368491b..51af6a5f0a 100644 --- a/src/ipc/capnp/common-types.h +++ b/src/ipc/capnp/common-types.h @@ -6,6 +6,9 @@ #define BITCOIN_IPC_CAPNP_COMMON_TYPES_H #include <clientversion.h> +#include <interfaces/types.h> +#include <primitives/transaction.h> +#include <serialize.h> #include <streams.h> #include <univalue.h> @@ -16,33 +19,24 @@ namespace ipc { namespace capnp { -//! Use SFINAE to define Serializeable<T> trait which is true if type T has a -//! Serialize(stream) method, false otherwise. -template <typename T> -struct Serializable { -private: - template <typename C> - static std::true_type test(decltype(std::declval<C>().Serialize(std::declval<std::nullptr_t&>()))*); - template <typename> - static std::false_type test(...); - -public: - static constexpr bool value = decltype(test<T>(nullptr))::value; -}; +//! Construct a ParamStream wrapping a data stream with serialization parameters +//! needed to pass transaction objects between bitcoin processes. +//! In the future, more params may be added here to serialize other objects that +//! require serialization parameters. Params should just be chosen to serialize +//! objects completely and ensure that serializing and deserializing objects +//! with the specified parameters produces equivalent objects. It's also +//! harmless to specify serialization parameters here that are not used. +template <typename S> +auto Wrap(S& s) +{ + return ParamsStream{s, TX_WITH_WITNESS}; +} -//! Use SFINAE to define Unserializeable<T> trait which is true if type T has -//! an Unserialize(stream) method, false otherwise. +//! Detect if type has a deserialize_type constructor, which is +//! used to deserialize types like CTransaction that can't be unserialized into +//! existing objects because they are immutable. template <typename T> -struct Unserializable { -private: - template <typename C> - static std::true_type test(decltype(std::declval<C>().Unserialize(std::declval<std::nullptr_t&>()))*); - template <typename> - static std::false_type test(...); - -public: - static constexpr bool value = decltype(test<T>(nullptr))::value; -}; +concept Deserializable = std::is_constructible_v<T, ::deserialize_type, ::DataStream&>; } // namespace capnp } // namespace ipc @@ -50,42 +44,78 @@ public: namespace mp { //! Overload multiprocess library's CustomBuildField hook to allow any //! serializable object to be stored in a capnproto Data field or passed to a -//! canproto interface. Use Priority<1> so this hook has medium priority, and +//! capnproto interface. Use Priority<1> so this hook has medium priority, and //! higher priority hooks could take precedence over this one. template <typename LocalType, typename Value, typename Output> -void CustomBuildField( - TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Value&& value, Output&& output, - // Enable if serializeable and if LocalType is not cv or reference - // qualified. If LocalType is cv or reference qualified, it is important to - // fall back to lower-priority Priority<0> implementation of this function - // that strips cv references, to prevent this CustomBuildField overload from - // taking precedence over more narrow overloads for specific LocalTypes. - std::enable_if_t<ipc::capnp::Serializable<LocalType>::value && - std::is_same_v<LocalType, std::remove_cv_t<std::remove_reference_t<LocalType>>>>* enable = nullptr) +void CustomBuildField(TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Value&& value, Output&& output) +// Enable if serializeable and if LocalType is not cv or reference qualified. If +// LocalType is cv or reference qualified, it is important to fall back to +// lower-priority Priority<0> implementation of this function that strips cv +// references, to prevent this CustomBuildField overload from taking precedence +// over more narrow overloads for specific LocalTypes. +requires Serializable<LocalType, DataStream> && std::is_same_v<LocalType, std::remove_cv_t<std::remove_reference_t<LocalType>>> { DataStream stream; - value.Serialize(stream); + auto wrapper{ipc::capnp::Wrap(stream)}; + value.Serialize(wrapper); auto result = output.init(stream.size()); memcpy(result.begin(), stream.data(), stream.size()); } //! Overload multiprocess library's CustomReadField hook to allow any object //! with an Unserialize method to be read from a capnproto Data field or -//! returned from canproto interface. Use Priority<1> so this hook has medium +//! returned from capnproto interface. Use Priority<1> so this hook has medium //! priority, and higher priority hooks could take precedence over this one. template <typename LocalType, typename Input, typename ReadDest> -decltype(auto) -CustomReadField(TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest, - std::enable_if_t<ipc::capnp::Unserializable<LocalType>::value>* enable = nullptr) +decltype(auto) CustomReadField(TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest) +requires Unserializable<LocalType, DataStream> && (!ipc::capnp::Deserializable<LocalType>) { return read_dest.update([&](auto& value) { if (!input.has()) return; auto data = input.get(); SpanReader stream({data.begin(), data.end()}); - value.Unserialize(stream); + auto wrapper{ipc::capnp::Wrap(stream)}; + value.Unserialize(wrapper); }); } +//! Overload multiprocess library's CustomReadField hook to allow any object +//! with a deserialize constructor to be read from a capnproto Data field or +//! returned from capnproto interface. Use Priority<1> so this hook has medium +//! priority, and higher priority hooks could take precedence over this one. +template <typename LocalType, typename Input, typename ReadDest> +decltype(auto) CustomReadField(TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest) +requires ipc::capnp::Deserializable<LocalType> +{ + assert(input.has()); + auto data = input.get(); + SpanReader stream({data.begin(), data.end()}); + auto wrapper{ipc::capnp::Wrap(stream)}; + return read_dest.construct(::deserialize, wrapper); +} + +//! Overload CustomBuildField and CustomReadField to serialize std::chrono +//! parameters and return values as numbers. +template <class Rep, class Period, typename Value, typename Output> +void CustomBuildField(TypeList<std::chrono::duration<Rep, Period>>, Priority<1>, InvokeContext& invoke_context, Value&& value, + Output&& output) +{ + static_assert(std::numeric_limits<decltype(output.get())>::lowest() <= std::numeric_limits<Rep>::lowest(), + "capnp type does not have enough range to hold lowest std::chrono::duration value"); + static_assert(std::numeric_limits<decltype(output.get())>::max() >= std::numeric_limits<Rep>::max(), + "capnp type does not have enough range to hold highest std::chrono::duration value"); + output.set(value.count()); +} + +template <class Rep, class Period, typename Input, typename ReadDest> +decltype(auto) CustomReadField(TypeList<std::chrono::duration<Rep, Period>>, Priority<1>, InvokeContext& invoke_context, + Input&& input, ReadDest&& read_dest) +{ + return read_dest.construct(input.get()); +} + +//! Overload CustomBuildField and CustomReadField to serialize UniValue +//! parameters and return values as JSON strings. template <typename Value, typename Output> void CustomBuildField(TypeList<UniValue>, Priority<1>, InvokeContext& invoke_context, Value&& value, Output&& output) { @@ -103,6 +133,33 @@ decltype(auto) CustomReadField(TypeList<UniValue>, Priority<1>, InvokeContext& i value.read(std::string_view{data.begin(), data.size()}); }); } + +//! Generic ::capnp::Data field builder for any C++ type that can be converted +//! to a span of bytes, like std::vector<char> or std::array<uint8_t>, or custom +//! blob types like uint256 or PKHash with data() and size() methods pointing to +//! bytes. +//! +//! Note: it might make sense to move this function into libmultiprocess, since +//! it is fairly generic. However this would require decreasing its priority so +//! it can be overridden, which would require more changes inside +//! libmultiprocess to avoid conflicting with the Priority<1> CustomBuildField +//! function it already provides for std::vector. Also, it might make sense to +//! provide a CustomReadField counterpart to this function, which could be +//! called to read C++ types that can be constructed from spans of bytes from +//! ::capnp::Data fields. But so far there hasn't been a need for this. +template <typename LocalType, typename Value, typename Output> +void CustomBuildField(TypeList<LocalType>, Priority<2>, InvokeContext& invoke_context, Value&& value, Output&& output) +requires + (std::is_same_v<decltype(output.get()), ::capnp::Data::Builder>) && + (std::convertible_to<Value, std::span<const std::byte>> || + std::convertible_to<Value, std::span<const char>> || + std::convertible_to<Value, std::span<const unsigned char>> || + std::convertible_to<Value, std::span<const signed char>>) +{ + auto data = std::span{value}; + auto result = output.init(data.size()); + memcpy(result.begin(), data.data(), data.size()); +} } // namespace mp #endif // BITCOIN_IPC_CAPNP_COMMON_TYPES_H diff --git a/src/ipc/capnp/common.capnp b/src/ipc/capnp/common.capnp new file mode 100644 index 0000000000..b3359f3f07 --- /dev/null +++ b/src/ipc/capnp/common.capnp @@ -0,0 +1,16 @@ +# 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. + +@0xcd2c6232cb484a28; + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("ipc::capnp::messages"); + +using Proxy = import "/mp/proxy.capnp"; +$Proxy.includeTypes("ipc/capnp/common-types.h"); + +struct BlockRef $Proxy.wrap("interfaces::BlockRef") { + hash @0 :Data; + height @1 :Int32; +} diff --git a/src/ipc/capnp/init-types.h b/src/ipc/capnp/init-types.h index 42031441b5..c3ddca27c0 100644 --- a/src/ipc/capnp/init-types.h +++ b/src/ipc/capnp/init-types.h @@ -6,5 +6,6 @@ #define BITCOIN_IPC_CAPNP_INIT_TYPES_H #include <ipc/capnp/echo.capnp.proxy-types.h> +#include <ipc/capnp/mining.capnp.proxy-types.h> #endif // BITCOIN_IPC_CAPNP_INIT_TYPES_H diff --git a/src/ipc/capnp/init.capnp b/src/ipc/capnp/init.capnp index e6d358c665..1001ee5336 100644 --- a/src/ipc/capnp/init.capnp +++ b/src/ipc/capnp/init.capnp @@ -10,11 +10,14 @@ $Cxx.namespace("ipc::capnp::messages"); using Proxy = import "/mp/proxy.capnp"; $Proxy.include("interfaces/echo.h"); $Proxy.include("interfaces/init.h"); +$Proxy.include("interfaces/mining.h"); $Proxy.includeTypes("ipc/capnp/init-types.h"); using Echo = import "echo.capnp"; +using Mining = import "mining.capnp"; interface Init $Proxy.wrap("interfaces::Init") { construct @0 (threadMap: Proxy.ThreadMap) -> (threadMap :Proxy.ThreadMap); makeEcho @1 (context :Proxy.Context) -> (result :Echo.Echo); + makeMining @2 (context :Proxy.Context) -> (result :Mining.Mining); } diff --git a/src/ipc/capnp/mining-types.h b/src/ipc/capnp/mining-types.h new file mode 100644 index 0000000000..2e60b43fcf --- /dev/null +++ b/src/ipc/capnp/mining-types.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef BITCOIN_IPC_CAPNP_MINING_TYPES_H +#define BITCOIN_IPC_CAPNP_MINING_TYPES_H + +#include <interfaces/mining.h> +#include <ipc/capnp/common.capnp.proxy-types.h> +#include <ipc/capnp/common-types.h> +#include <ipc/capnp/mining.capnp.proxy.h> +#include <node/miner.h> +#include <node/types.h> +#include <validation.h> + +namespace mp { +// Custom serialization for BlockValidationState. +void CustomBuildMessage(InvokeContext& invoke_context, + const BlockValidationState& src, + ipc::capnp::messages::BlockValidationState::Builder&& builder); +void CustomReadMessage(InvokeContext& invoke_context, + const ipc::capnp::messages::BlockValidationState::Reader& reader, + BlockValidationState& dest); +} // namespace mp + +#endif // BITCOIN_IPC_CAPNP_MINING_TYPES_H diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp new file mode 100644 index 0000000000..5e0216acea --- /dev/null +++ b/src/ipc/capnp/mining.capnp @@ -0,0 +1,52 @@ +# 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. + +@0xc77d03df6a41b505; + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("ipc::capnp::messages"); + +using Common = import "common.capnp"; +using Proxy = import "/mp/proxy.capnp"; +$Proxy.include("interfaces/mining.h"); +$Proxy.includeTypes("ipc/capnp/mining-types.h"); + +interface Mining $Proxy.wrap("interfaces::Mining") { + isTestChain @0 (context :Proxy.Context) -> (result: Bool); + isInitialBlockDownload @1 (context :Proxy.Context) -> (result: Bool); + getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool); + waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef); + createNewBlock @4 (scriptPubKey: Data, options: BlockCreateOptions) -> (result: BlockTemplate); + processNewBlock @5 (context :Proxy.Context, block: Data) -> (newBlock: Bool, result: Bool); + getTransactionsUpdated @6 (context :Proxy.Context) -> (result: UInt32); + testBlockValidity @7 (context :Proxy.Context, block: Data, checkMerkleRoot: Bool) -> (state: BlockValidationState, result: Bool); +} + +interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { + getBlockHeader @0 (context: Proxy.Context) -> (result: Data); + getBlock @1 (context: Proxy.Context) -> (result: Data); + getTxFees @2 (context: Proxy.Context) -> (result: List(Int64)); + getTxSigops @3 (context: Proxy.Context) -> (result: List(Int64)); + getCoinbaseTx @4 (context: Proxy.Context) -> (result: Data); + getCoinbaseCommitment @5 (context: Proxy.Context) -> (result: Data); + getWitnessCommitmentIndex @6 (context: Proxy.Context) -> (result: Int32); + getCoinbaseMerklePath @7 (context: Proxy.Context) -> (result: List(Data)); + submitSolution@8 (context: Proxy.Context, version: UInt32, timestamp: UInt32, nonce: UInt32, coinbase :Data) -> (result: Bool); +} + +struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") { + useMempool @0 :Bool $Proxy.name("use_mempool"); + coinbaseMaxAdditionalWeight @1 :UInt64 $Proxy.name("coinbase_max_additional_weight"); + coinbaseOutputMaxAdditionalSigops @2 :UInt64 $Proxy.name("coinbase_output_max_additional_sigops"); +} + +# Note: serialization of the BlockValidationState C++ type is somewhat fragile +# and using the struct can be awkward. It would be good if testBlockValidity +# method were changed to return validity information in a simpler format. +struct BlockValidationState { + mode @0 :Int32; + result @1 :Int32; + rejectReason @2 :Text; + debugMessage @3 :Text; +} diff --git a/src/ipc/capnp/mining.cpp b/src/ipc/capnp/mining.cpp new file mode 100644 index 0000000000..0f9533c1c7 --- /dev/null +++ b/src/ipc/capnp/mining.cpp @@ -0,0 +1,47 @@ +// 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. + +#include <ipc/capnp/mining-types.h> +#include <ipc/capnp/mining.capnp.proxy-types.h> + +#include <mp/proxy-types.h> + +namespace mp { +void CustomBuildMessage(InvokeContext& invoke_context, + const BlockValidationState& src, + ipc::capnp::messages::BlockValidationState::Builder&& builder) +{ + if (src.IsValid()) { + builder.setMode(0); + } else if (src.IsInvalid()) { + builder.setMode(1); + } else if (src.IsError()) { + builder.setMode(2); + } else { + assert(false); + } + builder.setResult(static_cast<int>(src.GetResult())); + builder.setRejectReason(src.GetRejectReason()); + builder.setDebugMessage(src.GetDebugMessage()); +} + +void CustomReadMessage(InvokeContext& invoke_context, + const ipc::capnp::messages::BlockValidationState::Reader& reader, + BlockValidationState& dest) +{ + if (reader.getMode() == 0) { + assert(reader.getResult() == 0); + assert(reader.getRejectReason().size() == 0); + assert(reader.getDebugMessage().size() == 0); + } else if (reader.getMode() == 1) { + dest.Invalid(static_cast<BlockValidationResult>(reader.getResult()), reader.getRejectReason(), reader.getDebugMessage()); + } else if (reader.getMode() == 2) { + assert(reader.getResult() == 0); + dest.Error(reader.getRejectReason()); + assert(reader.getDebugMessage().size() == 0); + } else { + assert(false); + } +} +} // namespace mp diff --git a/src/ipc/capnp/protocol.cpp b/src/ipc/capnp/protocol.cpp index 37b57a9525..4b67a5bd1e 100644 --- a/src/ipc/capnp/protocol.cpp +++ b/src/ipc/capnp/protocol.cpp @@ -23,6 +23,8 @@ #include <mutex> #include <optional> #include <string> +#include <sys/socket.h> +#include <system_error> #include <thread> namespace ipc { @@ -30,7 +32,7 @@ namespace capnp { namespace { void IpcLogFn(bool raise, std::string message) { - LogPrint(BCLog::IPC, "%s\n", message); + LogDebug(BCLog::IPC, "%s\n", message); if (raise) throw Exception(message); } @@ -51,11 +53,20 @@ public: startLoop(exe_name); return mp::ConnectStream<messages::Init>(*m_loop, fd); } - void serve(int fd, const char* exe_name, interfaces::Init& init) override + void listen(int listen_fd, const char* exe_name, interfaces::Init& init) override + { + startLoop(exe_name); + if (::listen(listen_fd, /*backlog=*/5) != 0) { + throw std::system_error(errno, std::system_category()); + } + mp::ListenConnections<messages::Init>(*m_loop, listen_fd, init); + } + void serve(int fd, const char* exe_name, interfaces::Init& init, const std::function<void()>& ready_fn = {}) override { assert(!m_loop); mp::g_thread_context.thread_name = mp::ThreadName(exe_name); m_loop.emplace(exe_name, &IpcLogFn, &m_context); + if (ready_fn) ready_fn(); mp::ServeStream<messages::Init>(*m_loop, fd, init); m_loop->loop(); m_loop.reset(); diff --git a/src/ipc/interfaces.cpp b/src/ipc/interfaces.cpp index e446cc98db..33555f05d4 100644 --- a/src/ipc/interfaces.cpp +++ b/src/ipc/interfaces.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 <common/args.h> #include <common/system.h> #include <interfaces/init.h> #include <interfaces/ipc.h> @@ -37,11 +38,11 @@ public: { int pid; int fd = m_process->spawn(new_exe_name, m_process_argv0, pid); - LogPrint(::BCLog::IPC, "Process %s pid %i launched\n", new_exe_name, pid); + LogDebug(::BCLog::IPC, "Process %s pid %i launched\n", new_exe_name, pid); auto init = m_protocol->connect(fd, m_exe_name); Ipc::addCleanup(*init, [this, new_exe_name, pid] { int status = m_process->waitSpawned(pid); - LogPrint(::BCLog::IPC, "Process %s pid %i exited with status %i\n", new_exe_name, pid, status); + LogDebug(::BCLog::IPC, "Process %s pid %i exited with status %i\n", new_exe_name, pid, status); }); return init; } @@ -56,6 +57,35 @@ public: exit_status = EXIT_SUCCESS; return true; } + std::unique_ptr<interfaces::Init> connectAddress(std::string& address) override + { + if (address.empty() || address == "0") return nullptr; + int fd; + if (address == "auto") { + // Treat "auto" the same as "unix" except don't treat it an as error + // if the connection is not accepted. Just return null so the caller + // can work offline without a connection, or spawn a new + // bitcoin-node process and connect to it. + address = "unix"; + try { + fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address); + } catch (const std::system_error& e) { + // If connection type is auto and socket path isn't accepting connections, or doesn't exist, catch the error and return null; + if (e.code() == std::errc::connection_refused || e.code() == std::errc::no_such_file_or_directory) { + return nullptr; + } + throw; + } + } else { + fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address); + } + return m_protocol->connect(fd, m_exe_name); + } + void listenAddress(std::string& address) override + { + int fd = m_process->bind(gArgs.GetDataDirNet(), m_exe_name, address); + m_protocol->listen(fd, m_exe_name, m_init); + } void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) override { m_protocol->addCleanup(type, iface, std::move(cleanup)); diff --git a/src/ipc/process.cpp b/src/ipc/process.cpp index 9657dcd092..432c365d8f 100644 --- a/src/ipc/process.cpp +++ b/src/ipc/process.cpp @@ -4,22 +4,28 @@ #include <ipc/process.h> #include <ipc/protocol.h> +#include <logging.h> #include <mp/util.h> #include <tinyformat.h> #include <util/fs.h> #include <util/strencodings.h> +#include <util/syserror.h> #include <cstdint> #include <cstdlib> +#include <errno.h> #include <exception> #include <iostream> #include <stdexcept> #include <string.h> -#include <system_error> +#include <sys/socket.h> +#include <sys/un.h> #include <unistd.h> #include <utility> #include <vector> +using util::RemovePrefixView; + namespace ipc { namespace { class ProcessImpl : public Process @@ -54,7 +60,95 @@ public: } return true; } + int connect(const fs::path& data_dir, + const std::string& dest_exe_name, + std::string& address) override; + int bind(const fs::path& data_dir, const std::string& exe_name, std::string& address) override; }; + +static bool ParseAddress(std::string& address, + const fs::path& data_dir, + const std::string& dest_exe_name, + struct sockaddr_un& addr, + std::string& error) +{ + if (address.compare(0, 4, "unix") == 0 && (address.size() == 4 || address[4] == ':')) { + fs::path path; + if (address.size() <= 5) { + path = data_dir / fs::PathFromString(strprintf("%s.sock", RemovePrefixView(dest_exe_name, "bitcoin-"))); + } else { + path = data_dir / fs::PathFromString(address.substr(5)); + } + std::string path_str = fs::PathToString(path); + address = strprintf("unix:%s", path_str); + if (path_str.size() >= sizeof(addr.sun_path)) { + error = strprintf("Unix address path %s exceeded maximum socket path length", fs::quoted(fs::PathToString(path))); + return false; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path_str.c_str(), sizeof(addr.sun_path)-1); + return true; + } + + error = strprintf("Unrecognized address '%s'", address); + return false; +} + +int ProcessImpl::connect(const fs::path& data_dir, + const std::string& dest_exe_name, + std::string& address) +{ + struct sockaddr_un addr; + std::string error; + if (!ParseAddress(address, data_dir, dest_exe_name, addr, error)) { + throw std::invalid_argument(error); + } + + int fd; + if ((fd = ::socket(addr.sun_family, SOCK_STREAM, 0)) == -1) { + throw std::system_error(errno, std::system_category()); + } + if (::connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + return fd; + } + int connect_error = errno; + if (::close(fd) != 0) { + LogPrintf("Error closing file descriptor %i '%s': %s\n", fd, address, SysErrorString(errno)); + } + throw std::system_error(connect_error, std::system_category()); +} + +int ProcessImpl::bind(const fs::path& data_dir, const std::string& exe_name, std::string& address) +{ + struct sockaddr_un addr; + std::string error; + if (!ParseAddress(address, data_dir, exe_name, addr, error)) { + throw std::invalid_argument(error); + } + + if (addr.sun_family == AF_UNIX) { + fs::path path = addr.sun_path; + if (path.has_parent_path()) fs::create_directories(path.parent_path()); + if (fs::symlink_status(path).type() == fs::file_type::socket) { + fs::remove(path); + } + } + + int fd; + if ((fd = ::socket(addr.sun_family, SOCK_STREAM, 0)) == -1) { + throw std::system_error(errno, std::system_category()); + } + + if (::bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + return fd; + } + int bind_error = errno; + if (::close(fd) != 0) { + LogPrintf("Error closing file descriptor %i: %s\n", fd, SysErrorString(errno)); + } + throw std::system_error(bind_error, std::system_category()); +} } // namespace std::unique_ptr<Process> MakeProcess() { return std::make_unique<ProcessImpl>(); } diff --git a/src/ipc/process.h b/src/ipc/process.h index 40f2d2acf6..2ed8b73fab 100644 --- a/src/ipc/process.h +++ b/src/ipc/process.h @@ -34,6 +34,16 @@ public: //! process. If so, return true and a file descriptor for communicating //! with the parent process. virtual bool checkSpawned(int argc, char* argv[], int& fd) = 0; + + //! Canonicalize and connect to address, returning socket descriptor. + virtual int connect(const fs::path& data_dir, + const std::string& dest_exe_name, + std::string& address) = 0; + + //! Create listening socket, bind and canonicalize address, and return socket descriptor. + virtual int bind(const fs::path& data_dir, + const std::string& exe_name, + std::string& address) = 0; }; //! Constructor for Process interface. Implementation will vary depending on diff --git a/src/ipc/protocol.h b/src/ipc/protocol.h index 4cd892e411..b2ebf99e8c 100644 --- a/src/ipc/protocol.h +++ b/src/ipc/protocol.h @@ -25,12 +25,38 @@ public: //! Return Init interface that forwards requests over given socket descriptor. //! Socket communication is handled on a background thread. + //! + //! @note It could be potentially useful in the future to add + //! std::function<void()> on_disconnect callback argument here. But there + //! isn't an immediate need, because the protocol implementation can clean + //! up its own state (calling ProxyServer destructors, etc) on disconnect, + //! and any client calls will just throw ipc::Exception errors after a + //! disconnect. virtual std::unique_ptr<interfaces::Init> connect(int fd, const char* exe_name) = 0; + //! Listen for connections on provided socket descriptor, accept them, and + //! handle requests on accepted connections. This method doesn't block, and + //! performs I/O on a background thread. + virtual void listen(int listen_fd, const char* exe_name, interfaces::Init& init) = 0; + //! Handle requests on provided socket descriptor, forwarding them to the //! provided Init interface. Socket communication is handled on the //! current thread, and this call blocks until the socket is closed. - virtual void serve(int fd, const char* exe_name, interfaces::Init& init) = 0; + //! + //! @note: If this method is called, it needs be called before connect() or + //! listen() methods, because for ease of implementation it's inflexible and + //! always runs the event loop in the foreground thread. It can share its + //! event loop with the other methods but can't share an event loop that was + //! created by them. This isn't really a problem because serve() is only + //! called by spawned child processes that call it immediately to + //! communicate back with parent processes. + // + //! The optional `ready_fn` callback will be called after the event loop is + //! created but before it is started. This can be useful in tests to trigger + //! client connections from another thread as soon as the event loop is + //! available, but should not be neccessary in normal code which starts + //! clients and servers independently. + virtual void serve(int fd, const char* exe_name, interfaces::Init& init, const std::function<void()>& ready_fn = {}) = 0; //! Add cleanup callback to interface that will run when the interface is //! deleted. diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt new file mode 100644 index 0000000000..7bf8efc516 --- /dev/null +++ b/src/kernel/CMakeLists.txt @@ -0,0 +1,147 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# TODO: libbitcoinkernel is a work in progress consensus engine +# library, as more and more modules are decoupled from the +# consensus engine, this list will shrink to only those +# which are absolutely necessary. +add_library(bitcoinkernel + bitcoinkernel.cpp + chain.cpp + checks.cpp + chainparams.cpp + coinstats.cpp + context.cpp + cs_main.cpp + disconnected_transactions.cpp + mempool_removal_reason.cpp + ../arith_uint256.cpp + ../chain.cpp + ../coins.cpp + ../compressor.cpp + ../consensus/merkle.cpp + ../consensus/tx_check.cpp + ../consensus/tx_verify.cpp + ../core_read.cpp + ../dbwrapper.cpp + ../deploymentinfo.cpp + ../deploymentstatus.cpp + ../flatfile.cpp + ../hash.cpp + ../logging.cpp + ../node/blockstorage.cpp + ../node/chainstate.cpp + ../node/utxo_snapshot.cpp + ../policy/feerate.cpp + ../policy/packages.cpp + ../policy/policy.cpp + ../policy/rbf.cpp + ../policy/settings.cpp + ../policy/truc_policy.cpp + ../pow.cpp + ../primitives/block.cpp + ../primitives/transaction.cpp + ../pubkey.cpp + ../random.cpp + ../randomenv.cpp + ../script/interpreter.cpp + ../script/script.cpp + ../script/script_error.cpp + ../script/sigcache.cpp + ../script/solver.cpp + ../signet.cpp + ../streams.cpp + ../support/lockedpool.cpp + ../sync.cpp + ../txdb.cpp + ../txmempool.cpp + ../uint256.cpp + ../util/chaintype.cpp + ../util/check.cpp + ../util/feefrac.cpp + ../util/fs.cpp + ../util/fs_helpers.cpp + ../util/hasher.cpp + ../util/moneystr.cpp + ../util/rbf.cpp + ../util/serfloat.cpp + ../util/signalinterrupt.cpp + ../util/strencodings.cpp + ../util/string.cpp + ../util/syserror.cpp + ../util/threadnames.cpp + ../util/time.cpp + ../util/tokenpipe.cpp + ../validation.cpp + ../validationinterface.cpp + ../versionbits.cpp +) +target_link_libraries(bitcoinkernel + PRIVATE + core_interface + bitcoin_clientversion + bitcoin_crypto + leveldb + secp256k1 + $<TARGET_NAME_IF_EXISTS:USDT::headers> + PUBLIC + Boost::headers +) + +# libbitcoinkernel requires default symbol visibility, explicitly +# specify that here so that things still work even when user +# configures with -DREDUCE_EXPORTS=ON +# +# Note this is a quick hack that will be removed as we +# incrementally define what to export from the library. +set_target_properties(bitcoinkernel PROPERTIES + CXX_VISIBILITY_PRESET default +) + +# When building the static library, install all static libraries the +# bitcoinkernel depends on. +if(NOT BUILD_SHARED_LIBS) + # Recursively get all the static libraries a target depends on and put them in libs_out + function(get_target_static_link_libs target libs_out) + get_target_property(linked_libraries ${target} LINK_LIBRARIES) + foreach(dep ${linked_libraries}) + if(TARGET ${dep}) + get_target_property(dep_type ${dep} TYPE) + if(dep_type STREQUAL "STATIC_LIBRARY") + list(APPEND ${libs_out} ${dep}) + get_target_static_link_libs(${dep} ${libs_out}) + endif() + endif() + endforeach() + set(${libs_out} ${${libs_out}} PARENT_SCOPE) + endfunction() + + set(all_kernel_static_link_libs "") + get_target_static_link_libs(bitcoinkernel all_kernel_static_link_libs) + + # LIBS_PRIVATE is substituted in the pkg-config file. + set(LIBS_PRIVATE "") + foreach(lib ${all_kernel_static_link_libs}) + install(TARGETS ${lib} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + string(APPEND LIBS_PRIVATE " -l${lib}") + endforeach() + + string(STRIP "${LIBS_PRIVATE}" LIBS_PRIVATE) +endif() + +configure_file(${PROJECT_SOURCE_DIR}/libbitcoinkernel.pc.in ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc @ONLY) +install(FILES ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + +include(GNUInstallDirs) +install(TARGETS bitcoinkernel + RUNTIME + DESTINATION ${CMAKE_INSTALL_BINDIR} + COMPONENT Kernel + LIBRARY + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT Kernel + ARCHIVE + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT Kernel +) diff --git a/src/kernel/blockmanager_opts.h b/src/kernel/blockmanager_opts.h index 16072b669b..261ec3be58 100644 --- a/src/kernel/blockmanager_opts.h +++ b/src/kernel/blockmanager_opts.h @@ -14,17 +14,19 @@ 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; Notifications& notifications; - bool reindex{false}; }; } // namespace kernel diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index 94b8a44323..0f128d4c56 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -26,10 +26,22 @@ #include <cstring> #include <type_traits> +using namespace util::hex_literals; + +// 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; - txNew.nVersion = 1; + txNew.version = 1; txNew.vin.resize(1); txNew.vout.resize(1); txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); @@ -61,7 +73,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; - const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; + const CScript genesisOutputScript = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG; return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward); } @@ -76,20 +88,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 +117,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{"000000000000000000000000000000000000000088e186b70e0862c193ec44d6"}; + consensus.defaultAssumeValid = uint256{"000000000000000000011c5890365bdbe5d25b97ce0057589acaef4f1a57263f"}; // 856760 /** * The message start string is designed to be unlikely to occur in normal data. @@ -118,13 +131,13 @@ public: pchMessageStart[3] = 0xd9; nDefaultPort = 8333; nPruneAfterHeight = 100000; - m_assumed_blockchain_size = 600; - m_assumed_chain_state_size = 10; + m_assumed_blockchain_size = 620; + m_assumed_chain_state_size = 14; 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. @@ -134,12 +147,12 @@ public: vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9 vSeeds.emplace_back("dnsseed.bitcoin.dashjr-list-of-p2p-nodes.us."); // Luke Dashjr - vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.btc.petertodd.net."); // Peter Todd, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.bitcoin.sprovoost.nl."); // Sjors Provoost vSeeds.emplace_back("dnsseed.emzy.de."); // Stephan Oeste vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice + vSeeds.emplace_back("seed.mainnet.achownodes.xyz."); // Ava Chow, only supports x1, x5, x9, x49, x809, x849, xd, x400, x404, x408, x448, xc08, xc48, x40c base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5); @@ -156,31 +169,36 @@ 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, - .dTxRate = 6.569290261471664, + // Data from RPC: getchaintxstats 4096 000000000000000000011c5890365bdbe5d25b97ce0057589acaef4f1a57263f + .nTime = 1723649144, + .tx_count = 1059312821, + .dTxRate = 6.721086701157182, }; } }; @@ -196,18 +214,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 @@ -222,8 +241,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{"000000000000000000000000000000000000000000000f209695166be8b61fa9"}; + consensus.defaultAssumeValid = uint256{"000000000000000465b1a66c9f386308e8c75acef9201f3f577811da09fc90ad"}; // 2873500 pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -231,13 +250,13 @@ public: pchMessageStart[3] = 0x07; nDefaultPort = 18333; nPruneAfterHeight = 1000; - m_assumed_blockchain_size = 42; - m_assumed_chain_state_size = 3; + m_assumed_blockchain_size = 93; + m_assumed_chain_state_size = 19; 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(); @@ -246,6 +265,7 @@ public: vSeeds.emplace_back("seed.tbtc.petertodd.net."); vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl."); vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9 + vSeeds.emplace_back("seed.testnet.achownodes.xyz."); // Ava Chow, only supports x1, x5, x9, x49, x809, x849, xd, x400, x404, x408, x448, xc08, xc48, x40c base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196); @@ -262,24 +282,123 @@ 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, - .dTxRate = 1.464436832560951, + // Data from RPC: getchaintxstats 4096 000000000000000465b1a66c9f386308e8c75acef9201f3f577811da09fc90ad + .nTime = 1723613341, + .tx_count = 187917082, + .dTxRate = 3.265051477698455, + }; + } +}; + +/** + * 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 = uint256{"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{"00000000000000000000000000000000000000000000005faa15d02e6202f3ba"}; + consensus.defaultAssumeValid = uint256{"000000005be348057db991fa5d89fe7c4695b667cfb311391a8db374b6f681fd"}; // 39550 + + pchMessageStart[0] = 0x1c; + pchMessageStart[1] = 0x16; + pchMessageStart[2] = 0x3f; + pchMessageStart[3] = 0x28; + nDefaultPort = 48333; + nPruneAfterHeight = 1000; + m_assumed_blockchain_size = 1; + m_assumed_chain_state_size = 0; + + const char* testnet4_genesis_msg = "03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e"; + const CScript testnet4_genesis_script = CScript() << "000000000000000000000000000000000000000000000000000000000000000000"_hex << OP_CHECKSIG; + genesis = CreateGenesisBlock(testnet4_genesis_msg, + testnet4_genesis_script, + 1714777860, + 393743547, + 0x1d00ffff, + 1, + 50 * COIN); + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256{"00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043"}); + assert(genesis.hashMerkleRoot == uint256{"7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e"}); + + 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{ + // Data from RPC: getchaintxstats 4096 000000005be348057db991fa5d89fe7c4695b667cfb311391a8db374b6f681fd + .nTime = 1723651702, + .tx_count = 757229, + .dTxRate = 0.01570402633472492, }; } }; @@ -295,22 +414,23 @@ public: vSeeds.clear(); if (!options.challenge) { - bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae"); + bin = "512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae"_hex_v_u8; vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl."); + vSeeds.emplace_back("seed.signet.achownodes.xyz."); // Ava Chow, only supports x1, x5, x9, x49, x809, x849, xd, x400, x404, x408, x448, xc08, xc48, x40c // Hardcoded nodes can be removed once there are more DNS seeds vSeeds.emplace_back("178.128.221.177"); vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333"); - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000206e86f08e8"); - consensus.defaultAssumeValid = uint256S("0x0000000870f15246ba23c16e370a7ffb1fc8a3dcf8cb4492882ed4b0e3d4cd26"); // 180000 - m_assumed_blockchain_size = 1; + consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000000000000025dbd66e58f"}; + consensus.defaultAssumeValid = uint256{"0000014aad1d58dddcb964dd749b073374c6306e716b22f573a2efe68d414539"}; // 208800 + m_assumed_blockchain_size = 2; m_assumed_chain_state_size = 0; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 0000000870f15246ba23c16e370a7ffb1fc8a3dcf8cb4492882ed4b0e3d4cd26 - .nTime = 1706331472, - .nTxCount = 2425380, - .dTxRate = 0.008277759863833788, + // Data from RPC: getchaintxstats 4096 0000014aad1d58dddcb964dd749b073374c6306e716b22f573a2efe68d414539 + .nTime = 1723655233, + .tx_count = 5507045, + .dTxRate = 0.06271073277261494, }; } else { bin = *options.challenge; @@ -343,11 +463,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; @@ -370,17 +491,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"}), } }; @@ -417,10 +538,11 @@ public: consensus.CSVHeight = 1; // Always active unless overridden consensus.SegwitHeight = 0; // Always active unless overridden consensus.MinBIP9WarningHeight = 0; - consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks + consensus.powLimit = uint256{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}; + consensus.nPowTargetTimespan = 24 * 60 * 60; // one day consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; + consensus.enforce_BIP94 = true; consensus.fPowNoRetargeting = true; consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) @@ -475,8 +597,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(); @@ -487,23 +609,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"}), }, }; @@ -543,6 +672,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; @@ -558,16 +692,19 @@ 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(); - if (std::equal(message.begin(), message.end(), mainnet_msg.data())) { + if (std::ranges::equal(message, mainnet_msg)) { return ChainType::MAIN; - } else if (std::equal(message.begin(), message.end(), testnet_msg.data())) { + } else if (std::ranges::equal(message, testnet_msg)) { return ChainType::TESTNET; - } else if (std::equal(message.begin(), message.end(), regtest_msg.data())) { + } else if (std::ranges::equal(message, testnet4_msg)) { + return ChainType::TESTNET4; + } else if (std::ranges::equal(message, regtest_msg)) { return ChainType::REGTEST; - } else if (std::equal(message.begin(), message.end(), signet_msg.data())) { + } else if (std::ranges::equal(message, signet_msg)) { return ChainType::SIGNET; } return std::nullopt; 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 de5f78494a..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> @@ -33,7 +34,7 @@ namespace kernel { struct ChainstateManagerOpts { const CChainParams& chainparams; fs::path datadir; - std::optional<bool> check_block_index{}; + std::optional<int32_t> check_block_index{}; bool checkpoints_enabled{DEFAULT_CHECKPOINTS_ENABLED}; //! If set, it will override the minimum work we will assume exists on some valid chain. std::optional<arith_uint256> minimum_chain_work{}; @@ -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 7283a88e86..ef72d9bdb6 100644 --- a/src/kernel/notifications_interface.h +++ b/src/kernel/notifications_interface.h @@ -16,6 +16,8 @@ namespace kernel { //! Result type for use with std::variant to indicate that an operation should be interrupted. struct Interrupted{}; +enum class Warning; + //! Simple result type for functions that need to propagate an interrupt status and don't have other return values. using InterruptResult = std::variant<std::monostate, Interrupted>; @@ -33,12 +35,13 @@ 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) {} virtual void progress(const bilingual_str& title, int progress_percent, bool resume_possible) {} - virtual void warning(const bilingual_str& warning) {} + virtual void warningSet(Warning id, const bilingual_str& message) {} + virtual void warningUnset(Warning id) {} //! The flush error notification is sent to notify the user that an error //! occurred while flushing block data to disk. Kernel code may ignore flush 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/kernel/warning.h b/src/kernel/warning.h new file mode 100644 index 0000000000..453f36c552 --- /dev/null +++ b/src/kernel/warning.h @@ -0,0 +1,14 @@ +// 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. + +#ifndef BITCOIN_KERNEL_WARNING_H +#define BITCOIN_KERNEL_WARNING_H + +namespace kernel { +enum class Warning { + UNKNOWN_NEW_RULES_ACTIVATED, + LARGE_WORK_INVALID_CHAIN, +}; +} // namespace kernel +#endif // BITCOIN_KERNEL_WARNING_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/leveldb/include/leveldb/status.h b/src/leveldb/include/leveldb/status.h index e3273144e4..68efe3001a 100644 --- a/src/leveldb/include/leveldb/status.h +++ b/src/leveldb/include/leveldb/status.h @@ -103,6 +103,8 @@ class LEVELDB_EXPORT Status { inline Status::Status(const Status& rhs) { state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_); } + +// NOLINTBEGIN(bugprone-unhandled-self-assignment) inline Status& Status::operator=(const Status& rhs) { // The following condition catches both aliasing (when this == &rhs), // and the common case where both rhs and *this are ok. @@ -112,6 +114,8 @@ inline Status& Status::operator=(const Status& rhs) { } return *this; } +// NOLINTEND(bugprone-unhandled-self-assignment) + inline Status& Status::operator=(Status&& rhs) noexcept { std::swap(state_, rhs.state_); return *this; diff --git a/src/logging.cpp b/src/logging.cpp index 578650f856..5f055566ef 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -1,9 +1,11 @@ // 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. #include <logging.h> +#include <memusage.h> +#include <util/check.h> #include <util/fs.h> #include <util/string.h> #include <util/threadnames.h> @@ -13,6 +15,9 @@ #include <map> #include <optional> +using util::Join; +using util::RemovePrefixView; + const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; constexpr auto MAX_USER_SETABLE_SEVERITY_LEVEL{BCLog::Level::Info}; @@ -39,7 +44,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); } @@ -67,17 +72,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; @@ -90,6 +100,22 @@ 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) @@ -97,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; @@ -110,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; @@ -141,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}, @@ -175,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; } @@ -225,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; @@ -252,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; } @@ -272,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; } @@ -306,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; @@ -346,34 +362,70 @@ 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 +{ + if (!str.ends_with('\n')) str.push_back('\n'); + + 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)); +} - m_started_new_line = !str.empty() && str[str.size()-1] == '\n'; +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); if (m_buffering) { - // buffer if we haven't started logging yet - m_msgs_before_open.push_back(str_prefixed); + { + 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; } + 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); @@ -440,7 +492,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; @@ -448,7 +500,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 cfef65221f..fdc12c79b3 100644 --- a/src/logging.h +++ b/src/logging.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. @@ -10,6 +10,7 @@ #include <tinyformat.h> #include <util/fs.h> #include <util/string.h> +#include <util/time.h> #include <atomic> #include <cstdint> @@ -36,40 +37,41 @@ struct LogCategory { }; namespace BCLog { - enum LogFlags : uint32_t { - NONE = 0, - NET = (1 << 0), - TOR = (1 << 1), - MEMPOOL = (1 << 2), - HTTP = (1 << 3), - BENCH = (1 << 4), - ZMQ = (1 << 5), - WALLETDB = (1 << 6), - RPC = (1 << 7), - ESTIMATEFEE = (1 << 8), - ADDRMAN = (1 << 9), - SELECTCOINS = (1 << 10), - REINDEX = (1 << 11), - CMPCTBLOCK = (1 << 12), - RAND = (1 << 13), - PRUNE = (1 << 14), - PROXY = (1 << 15), - MEMPOOLREJ = (1 << 16), - LIBEVENT = (1 << 17), - COINDB = (1 << 18), - QT = (1 << 19), - LEVELDB = (1 << 20), - VALIDATION = (1 << 21), - I2P = (1 << 22), - IPC = (1 << 23), + using CategoryMask = uint64_t; + enum LogFlags : CategoryMask { + NONE = CategoryMask{0}, + NET = (CategoryMask{1} << 0), + TOR = (CategoryMask{1} << 1), + MEMPOOL = (CategoryMask{1} << 2), + HTTP = (CategoryMask{1} << 3), + BENCH = (CategoryMask{1} << 4), + ZMQ = (CategoryMask{1} << 5), + WALLETDB = (CategoryMask{1} << 6), + RPC = (CategoryMask{1} << 7), + ESTIMATEFEE = (CategoryMask{1} << 8), + ADDRMAN = (CategoryMask{1} << 9), + SELECTCOINS = (CategoryMask{1} << 10), + REINDEX = (CategoryMask{1} << 11), + CMPCTBLOCK = (CategoryMask{1} << 12), + RAND = (CategoryMask{1} << 13), + PRUNE = (CategoryMask{1} << 14), + PROXY = (CategoryMask{1} << 15), + MEMPOOLREJ = (CategoryMask{1} << 16), + LIBEVENT = (CategoryMask{1} << 17), + COINDB = (CategoryMask{1} << 18), + QT = (CategoryMask{1} << 19), + LEVELDB = (CategoryMask{1} << 20), + VALIDATION = (CategoryMask{1} << 21), + I2P = (CategoryMask{1} << 22), + IPC = (CategoryMask{1} << 23), #ifdef DEBUG_LOCKCONTENTION - LOCK = (1 << 24), + LOCK = (CategoryMask{1} << 24), #endif - BLOCKSTORAGE = (1 << 25), - TXRECONCILIATION = (1 << 26), - SCAN = (1 << 27), - TXPACKAGES = (1 << 28), - ALL = ~(uint32_t)0, + BLOCKSTORAGE = (CategoryMask{1} << 25), + TXRECONCILIATION = (CategoryMask{1} << 26), + SCAN = (CategoryMask{1} << 27), + TXPACKAGES = (CategoryMask{1} << 28), + ALL = ~NONE, }; enum class Level { Trace = 0, // High-volume or detailed logging for development/debugging @@ -79,22 +81,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. - - /** - * m_started_new_line is a state variable that will suppress printing of - * the timestamp when multiple calls are made that don't end in a - * newline. - */ - std::atomic_bool m_started_new_line{true}; + 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}; //! Category-specific log level. Overrides `m_log_level`. std::unordered_map<LogFlags, Level> m_category_log_levels GUARDED_BY(m_cs); @@ -104,13 +113,21 @@ namespace BCLog { std::atomic<Level> m_log_level{DEFAULT_LOG_LEVEL}; /** Log categories bitfield. */ - std::atomic<uint32_t> m_categories{0}; + std::atomic<CategoryMask> m_categories{BCLog::NONE}; + + 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(const std::string& str); + 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 +141,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,51 +161,59 @@ 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(); } + CategoryMask 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; /** Returns a string with the log categories in alphabetical order. */ std::string LogCategoriesString() const { - return Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; }); + return util::Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; }); }; //! Returns a string with all user-selectable log levels. @@ -212,37 +236,34 @@ 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); - -// 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. +bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str); 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) +inline void LogPrintFormatInternal(std::string_view logging_function, std::string_view source_file, const int source_line, const BCLog::LogFlags flag, const BCLog::Level level, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) { if (LogInstance().Enabled()) { std::string log_msg; try { log_msg = tfm::format(fmt, args...); } catch (tinyformat::format_error& fmterr) { - /* Original format string will have newline so don't add one here */ - log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt; + log_msg = "Error \"" + std::string{fmterr.what()} + "\" while formatting log message: " + fmt.fmt; } LogInstance().LogPrintStr(log_msg, logging_function, source_file, source_line, flag, level); } } -#define LogPrintLevel_(category, level, ...) LogPrintf_(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__) +#define LogPrintLevel_(category, level, ...) LogPrintFormatInternal(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__) // Log unconditionally. +// 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 storage +// with debug.log entries. #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, __VA_ARGS__) #define LogWarning(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Warning, __VA_ARGS__) #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, __VA_ARGS__) // Deprecated unconditional logging. #define LogPrintf(...) LogInfo(__VA_ARGS__) -#define LogPrintfCategory(category, ...) LogPrintLevel_(category, BCLog::Level::Info, __VA_ARGS__) // Use a macro instead of a function for conditional logging to prevent // evaluating arguments when logging for the category is not enabled. @@ -259,7 +280,4 @@ static inline void LogPrintf_(const std::string& logging_function, const std::st #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) #define LogTrace(category, ...) LogPrintLevel(category, BCLog::Level::Trace, __VA_ARGS__) -// Deprecated conditional logging -#define LogPrint(category, ...) LogDebug(category, __VA_ARGS__) - #endif // BITCOIN_LOGGING_H diff --git a/src/logging/timer.h b/src/logging/timer.h index 993ba99c25..0a6813cdd5 100644 --- a/src/logging/timer.h +++ b/src/logging/timer.h @@ -55,7 +55,7 @@ public: if (m_log_category == BCLog::LogFlags::ALL) { LogPrintf("%s\n", full_msg); } else { - LogPrint(m_log_category, "%s\n", full_msg); + LogDebug(m_log_category, "%s\n", full_msg); } } @@ -87,7 +87,7 @@ private: //! A descriptive message of what is being timed. const std::string m_title; - //! Forwarded on to LogPrint if specified - has the effect of only + //! Forwarded on to LogDebug if specified - has the effect of only //! outputting the timing log when a particular debug= category is specified. const BCLog::LogFlags m_log_category; diff --git a/src/mapport.cpp b/src/mapport.cpp index 80670230c7..bdeda6da34 100644 --- a/src/mapport.cpp +++ b/src/mapport.cpp @@ -2,24 +2,22 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <mapport.h> #include <clientversion.h> +#include <common/netif.h> +#include <common/pcp.h> #include <common/system.h> #include <logging.h> #include <net.h> #include <netaddress.h> #include <netbase.h> +#include <random.h> #include <util/thread.h> #include <util/threadinterrupt.h> -#ifdef USE_NATPMP -#include <compat/compat.h> -#include <natpmp.h> -#endif // USE_NATPMP - #ifdef USE_UPNP #include <miniupnpc/miniupnpc.h> #include <miniupnpc/upnpcommands.h> @@ -36,7 +34,6 @@ static_assert(MINIUPNPC_API_VERSION >= 17, "miniUPnPc API version >= 17 assumed" #include <string> #include <thread> -#if defined(USE_NATPMP) || defined(USE_UPNP) static CThreadInterrupt g_mapport_interrupt; static std::thread g_mapport_thread; static std::atomic_uint g_mapport_enabled_protos{MapPortProtoFlag::NONE}; @@ -46,104 +43,96 @@ using namespace std::chrono_literals; static constexpr auto PORT_MAPPING_REANNOUNCE_PERIOD{20min}; static constexpr auto PORT_MAPPING_RETRY_PERIOD{5min}; -#ifdef USE_NATPMP -static uint16_t g_mapport_external_port = 0; -static bool NatpmpInit(natpmp_t* natpmp) +static bool ProcessPCP() { - const int r_init = initnatpmp(natpmp, /* detect gateway automatically */ 0, /* forced gateway - NOT APPLIED*/ 0); - if (r_init == 0) return true; - LogPrintf("natpmp: initnatpmp() failed with %d error.\n", r_init); - return false; -} + // The same nonce is used for all mappings, this is allowed by the spec, and simplifies keeping track of them. + PCPMappingNonce pcp_nonce; + GetRandBytes(pcp_nonce); -static bool NatpmpDiscover(natpmp_t* natpmp, struct in_addr& external_ipv4_addr) -{ - const int r_send = sendpublicaddressrequest(natpmp); - if (r_send == 2 /* OK */) { - int r_read; - natpmpresp_t response; - do { - r_read = readnatpmpresponseorretry(natpmp, &response); - } while (r_read == NATPMP_TRYAGAIN); - - if (r_read == 0) { - external_ipv4_addr = response.pnu.publicaddress.addr; - return true; - } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) { - LogPrintf("natpmp: The gateway does not support NAT-PMP.\n"); + bool ret = false; + bool no_resources = false; + const uint16_t private_port = GetListenPort(); + // Multiply the reannounce period by two, as we'll try to renew approximately halfway. + const uint32_t requested_lifetime = std::chrono::seconds(PORT_MAPPING_REANNOUNCE_PERIOD * 2).count(); + uint32_t actual_lifetime = 0; + std::chrono::milliseconds sleep_time; + + // Local functor to handle result from PCP/NATPMP mapping. + auto handle_mapping = [&](std::variant<MappingResult, MappingError> &res) -> void { + if (MappingResult* mapping = std::get_if<MappingResult>(&res)) { + LogPrintLevel(BCLog::NET, BCLog::Level::Info, "portmap: Added mapping %s\n", mapping->ToString()); + AddLocal(mapping->external, LOCAL_MAPPED); + ret = true; + actual_lifetime = std::min(actual_lifetime, mapping->lifetime); + } else if (MappingError *err = std::get_if<MappingError>(&res)) { + // Detailed error will already have been logged internally in respective Portmap function. + if (*err == MappingError::NO_RESOURCES) { + no_resources = true; + } + } + }; + + do { + actual_lifetime = requested_lifetime; + no_resources = false; // Set to true if there was any "no resources" error. + ret = false; // Set to true if any mapping succeeds. + + // IPv4 + std::optional<CNetAddr> gateway4 = QueryDefaultGateway(NET_IPV4); + if (!gateway4) { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "portmap: Could not determine IPv4 default gateway\n"); } else { - LogPrintf("natpmp: readnatpmpresponseorretry() for public address failed with %d error.\n", r_read); + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "portmap: gateway [IPv4]: %s\n", gateway4->ToStringAddr()); + + // Open a port mapping on whatever local address we have toward the gateway. + struct in_addr inaddr_any; + inaddr_any.s_addr = htonl(INADDR_ANY); + auto res = PCPRequestPortMap(pcp_nonce, *gateway4, CNetAddr(inaddr_any), private_port, requested_lifetime); + MappingError* pcp_err = std::get_if<MappingError>(&res); + if (pcp_err && *pcp_err == MappingError::UNSUPP_VERSION) { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "portmap: Got unsupported PCP version response, falling back to NAT-PMP\n"); + res = NATPMPRequestPortMap(*gateway4, private_port, requested_lifetime); + } + handle_mapping(res); } - } else { - LogPrintf("natpmp: sendpublicaddressrequest() failed with %d error.\n", r_send); - } - return false; -} + // IPv6 + std::optional<CNetAddr> gateway6 = QueryDefaultGateway(NET_IPV6); + if (!gateway6) { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "portmap: Could not determine IPv6 default gateway\n"); + } else { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "portmap: gateway [IPv6]: %s\n", gateway6->ToStringAddr()); -static bool NatpmpMapping(natpmp_t* natpmp, const struct in_addr& external_ipv4_addr, uint16_t private_port, bool& external_ip_discovered) -{ - const uint16_t suggested_external_port = g_mapport_external_port ? g_mapport_external_port : private_port; - const int r_send = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_TCP, private_port, suggested_external_port, 3600 /*seconds*/); - if (r_send == 12 /* OK */) { - int r_read; - natpmpresp_t response; - do { - r_read = readnatpmpresponseorretry(natpmp, &response); - } while (r_read == NATPMP_TRYAGAIN); - - if (r_read == 0) { - auto pm = response.pnu.newportmapping; - if (private_port == pm.privateport && pm.lifetime > 0) { - g_mapport_external_port = pm.mappedpublicport; - const CService external{external_ipv4_addr, pm.mappedpublicport}; - if (!external_ip_discovered && fDiscover) { - AddLocal(external, LOCAL_MAPPED); - external_ip_discovered = true; - } - LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToStringAddrPort()); - return true; - } else { - LogPrintf("natpmp: Port mapping failed.\n"); + // Try to open pinholes for all routable local IPv6 addresses. + for (const auto &addr: GetLocalAddresses()) { + if (!addr.IsRoutable() || !addr.IsIPv6()) continue; + auto res = PCPRequestPortMap(pcp_nonce, *gateway6, addr, private_port, requested_lifetime); + handle_mapping(res); } - } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) { - LogPrintf("natpmp: The gateway does not support NAT-PMP.\n"); - } else { - LogPrintf("natpmp: readnatpmpresponseorretry() for port mapping failed with %d error.\n", r_read); } - } else { - LogPrintf("natpmp: sendnewportmappingrequest() failed with %d error.\n", r_send); - } - - return false; -} -static bool ProcessNatpmp() -{ - bool ret = false; - natpmp_t natpmp; - struct in_addr external_ipv4_addr; - if (NatpmpInit(&natpmp) && NatpmpDiscover(&natpmp, external_ipv4_addr)) { - bool external_ip_discovered = false; - const uint16_t private_port = GetListenPort(); - do { - ret = NatpmpMapping(&natpmp, external_ipv4_addr, private_port, external_ip_discovered); - } while (ret && g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD)); - g_mapport_interrupt.reset(); + // Log message if we got NO_RESOURCES. + if (no_resources) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "portmap: At least one mapping failed because of a NO_RESOURCES error. This usually indicates that the port is already used on the router. If this is the only instance of bitcoin running on the network, this will resolve itself automatically. Otherwise, you might want to choose a different P2P port to prevent this conflict.\n"); + } - const int r_send = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, private_port, g_mapport_external_port, /* remove a port mapping */ 0); - g_mapport_external_port = 0; - if (r_send == 12 /* OK */) { - LogPrintf("natpmp: Port mapping removed successfully.\n"); - } else { - LogPrintf("natpmp: sendnewportmappingrequest(0) failed with %d error.\n", r_send); + // Sanity-check returned lifetime. + if (actual_lifetime < 30) { + LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "portmap: Got impossibly short mapping lifetime of %d seconds\n", actual_lifetime); + return false; } - } + // RFC6887 11.2.1 recommends that clients send their first renewal packet at a time chosen with uniform random + // distribution in the range 1/2 to 5/8 of expiration time. + std::chrono::seconds sleep_time_min(actual_lifetime / 2); + std::chrono::seconds sleep_time_max(actual_lifetime * 5 / 8); + sleep_time = sleep_time_min + FastRandomContext().randrange<std::chrono::milliseconds>(sleep_time_max - sleep_time_min); + } while (ret && g_mapport_interrupt.sleep_for(sleep_time)); + + // We don't delete the mappings when the thread is interrupted because this would add additional complexity, so + // we rather just choose a fairly short expiry time. - closenatpmp(&natpmp); return ret; } -#endif // USE_NATPMP #ifdef USE_UPNP static bool ProcessUpnp() @@ -161,8 +150,11 @@ static bool ProcessUpnp() struct UPNPUrls urls; struct IGDdatas data; int r; - +#if MINIUPNPC_API_VERSION <= 17 r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); +#else + r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr), nullptr, 0); +#endif if (r == 1) { if (fDiscover) { @@ -220,23 +212,21 @@ static void ThreadMapPort() do { ok = false; -#ifdef USE_UPNP // High priority protocol. - if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) { - g_mapport_current_proto = MapPortProtoFlag::UPNP; - ok = ProcessUpnp(); + if (g_mapport_enabled_protos & MapPortProtoFlag::PCP) { + g_mapport_current_proto = MapPortProtoFlag::PCP; + ok = ProcessPCP(); if (ok) continue; } -#endif // USE_UPNP -#ifdef USE_NATPMP +#ifdef USE_UPNP // Low priority protocol. - if (g_mapport_enabled_protos & MapPortProtoFlag::NAT_PMP) { - g_mapport_current_proto = MapPortProtoFlag::NAT_PMP; - ok = ProcessNatpmp(); + if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) { + g_mapport_current_proto = MapPortProtoFlag::UPNP; + ok = ProcessUpnp(); if (ok) continue; } -#endif // USE_NATPMP +#endif // USE_UPNP g_mapport_current_proto = MapPortProtoFlag::NONE; if (g_mapport_enabled_protos == MapPortProtoFlag::NONE) { @@ -278,7 +268,7 @@ static void DispatchMapPort() assert(g_mapport_thread.joinable()); assert(!g_mapport_interrupt); - // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadNatpmp() + // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadPCP() // to force trying the next protocol in the ThreadMapPort() loop. g_mapport_interrupt(); } @@ -292,10 +282,10 @@ static void MapPortProtoSetEnabled(MapPortProtoFlag proto, bool enabled) } } -void StartMapPort(bool use_upnp, bool use_natpmp) +void StartMapPort(bool use_upnp, bool use_pcp) { MapPortProtoSetEnabled(MapPortProtoFlag::UPNP, use_upnp); - MapPortProtoSetEnabled(MapPortProtoFlag::NAT_PMP, use_natpmp); + MapPortProtoSetEnabled(MapPortProtoFlag::PCP, use_pcp); DispatchMapPort(); } @@ -314,18 +304,3 @@ void StopMapPort() g_mapport_interrupt.reset(); } } - -#else // #if defined(USE_NATPMP) || defined(USE_UPNP) -void StartMapPort(bool use_upnp, bool use_natpmp) -{ - // Intentionally left blank. -} -void InterruptMapPort() -{ - // Intentionally left blank. -} -void StopMapPort() -{ - // Intentionally left blank. -} -#endif // #if defined(USE_NATPMP) || defined(USE_UPNP) diff --git a/src/mapport.h b/src/mapport.h index 6f55c46f6c..51202687f2 100644 --- a/src/mapport.h +++ b/src/mapport.h @@ -12,10 +12,10 @@ static constexpr bool DEFAULT_NATPMP = false; enum MapPortProtoFlag : unsigned int { NONE = 0x00, UPNP = 0x01, - NAT_PMP = 0x02, + PCP = 0x02, // PCP with NAT-PMP fallback. }; -void StartMapPort(bool use_upnp, bool use_natpmp); +void StartMapPort(bool use_upnp, bool use_pcp); void InterruptMapPort(); void StopMapPort(); 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/minisketch/configure.ac b/src/minisketch/configure.ac index cd52d7f412..65a47b45c2 100644 --- a/src/minisketch/configure.ac +++ b/src/minisketch/configure.ac @@ -102,6 +102,7 @@ case $host in esac AX_CHECK_COMPILE_FLAG([-Wall],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-Wundef], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wundef"], [], [$CXXFLAG_WERROR]) AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[CXXFLAGS="$CXXFLAGS -fvisibility=hidden"],[],[$CXXFLAG_WERROR]) if test "x$use_ccache" != "xno"; then diff --git a/src/minisketch/include/minisketch.h b/src/minisketch/include/minisketch.h index 24d6b4e1c0..b0571d2788 100644 --- a/src/minisketch/include/minisketch.h +++ b/src/minisketch/include/minisketch.h @@ -239,7 +239,7 @@ public: /** Make this Minisketch a clone of the specified one. */ Minisketch& operator=(const Minisketch& sketch) noexcept { - if (sketch.m_minisketch) { + if (this != &sketch && sketch.m_minisketch) { m_minisketch = std::unique_ptr<minisketch, Deleter>(minisketch_clone(sketch.m_minisketch.get())); } return *this; diff --git a/src/minisketch/src/false_positives.h b/src/minisketch/src/false_positives.h index 44ebb3e94c..9d0358997f 100644 --- a/src/minisketch/src/false_positives.h +++ b/src/minisketch/src/false_positives.h @@ -81,7 +81,8 @@ uint64_t BaseFPBits(uint32_t bits, uint32_t capacity) { size_t ComputeCapacity(uint32_t bits, size_t max_elements, uint32_t fpbits) { if (bits == 0) return 0; - uint64_t base_fpbits = BaseFPBits(bits, max_elements); + if (max_elements > 0xffffffff) return max_elements; + uint64_t base_fpbits = BaseFPBits(bits, static_cast<uint32_t>(max_elements)); // The fpbits provided by the base max_elements==capacity case are sufficient. if (base_fpbits >= fpbits) return max_elements; // Otherwise, increment capacity by ceil(fpbits / bits) beyond that. @@ -90,6 +91,7 @@ size_t ComputeCapacity(uint32_t bits, size_t max_elements, uint32_t fpbits) { size_t ComputeMaxElements(uint32_t bits, size_t capacity, uint32_t fpbits) { if (bits == 0) return 0; + if (capacity > 0xffffffff) return capacity; // Start with max_elements=capacity, and decrease max_elements until the corresponding capacity is capacity. size_t max_elements = capacity; while (true) { diff --git a/src/minisketch/src/int_utils.h b/src/minisketch/src/int_utils.h index 2b3d8cb402..a6b89cd63c 100644 --- a/src/minisketch/src/int_utils.h +++ b/src/minisketch/src/int_utils.h @@ -159,7 +159,7 @@ static inline int CountBits(I val, int max) { } if (!ret) return 0; return index + 1; -#elif HAVE_CLZ +#elif defined(HAVE_CLZ) (void)max; if (val == 0) return 0; if (std::numeric_limits<unsigned>::digits >= std::numeric_limits<I>::digits) { @@ -210,7 +210,7 @@ public: static constexpr inline int TopBits(I val) { static_assert(Count > 0, "BitsInt::TopBits needs Count > 0"); static_assert(Count <= BITS, "BitsInt::TopBits needs Offset <= BITS"); - return val >> (BITS - Count); + return static_cast<int>(val >> (BITS - Count)); } static inline constexpr I CondXorWith(I val, bool cond, I v) { diff --git a/src/minisketch/src/minisketch.cpp b/src/minisketch/src/minisketch.cpp index d003fdf755..2e45409243 100644 --- a/src/minisketch/src/minisketch.cpp +++ b/src/minisketch/src/minisketch.cpp @@ -468,7 +468,7 @@ size_t minisketch_merge(minisketch* sketch, const minisketch* other_sketch) { ssize_t minisketch_decode(const minisketch* sketch, size_t max_elements, uint64_t* output) { const Sketch* s = (const Sketch*)sketch; s->Check(); - return s->Decode(max_elements, output); + return s->Decode(static_cast<int>(max_elements), output); } void minisketch_set_seed(minisketch* sketch, uint64_t seed) { diff --git a/src/minisketch/src/sketch.h b/src/minisketch/src/sketch.h index 3e9bad793d..662b4e982f 100644 --- a/src/minisketch/src/sketch.h +++ b/src/minisketch/src/sketch.h @@ -29,7 +29,7 @@ public: virtual ~Sketch() {} virtual size_t Syndromes() const = 0; - virtual void Init(int syndromes) = 0; + virtual void Init(size_t syndromes) = 0; virtual void Add(uint64_t element) = 0; virtual void Serialize(unsigned char*) const = 0; virtual void Deserialize(const unsigned char*) = 0; diff --git a/src/minisketch/src/sketch_impl.h b/src/minisketch/src/sketch_impl.h index 4547b742f2..c357f0e823 100644 --- a/src/minisketch/src/sketch_impl.h +++ b/src/minisketch/src/sketch_impl.h @@ -92,7 +92,8 @@ template<typename F> void Sqr(std::vector<typename F::Elem>& poly, const F& field) { if (poly.size() == 0) return; poly.resize(poly.size() * 2 - 1); - for (int x = poly.size() - 1; x >= 0; --x) { + for (size_t i = 0; i < poly.size(); ++i) { + auto x = poly.size() - i - 1; poly[x] = (x & 1) ? 0 : field.Sqr(poly[x / 2]); } } @@ -217,7 +218,7 @@ bool RecFindRoots(std::vector<std::vector<typename F::Elem>>& stack, size_t pos, } if (fully_factorizable) { - // Every succesful iteration of this algorithm splits the input + // Every successful iteration of this algorithm splits the input // polynomial further into buckets, each corresponding to a subset // of 2^(BITS-depth) roots. If after depth splits the degree of // the polynomial is >= 2^(BITS-depth), something is wrong. @@ -297,7 +298,7 @@ std::vector<typename F::Elem> BerlekampMassey(const std::vector<typename F::Elem auto discrepancy = syndromes[n]; for (size_t i = 1; i < current.size(); ++i) discrepancy ^= table[n - i](current[i]); if (discrepancy != 0) { - int x = n + 1 - (current.size() - 1) - (prev.size() - 1); + int x = static_cast<int>(n + 1 - (current.size() - 1) - (prev.size() - 1)); if (!b_have_inv) { b_inv = field.Inv(b); b_have_inv = true; @@ -366,7 +367,7 @@ public: } size_t Syndromes() const override { return m_syndromes.size(); } - void Init(int count) override { m_syndromes.assign(count, 0); } + void Init(size_t count) override { m_syndromes.assign(count, 0); } void Add(uint64_t val) override { @@ -405,7 +406,7 @@ public: for (const auto& root : roots) { *(out++) = m_field.ToUint64(root); } - return roots.size(); + return static_cast<int>(roots.size()); } size_t Merge(const Sketch* other_sketch) override diff --git a/src/net.cpp b/src/net.cpp index de974f39cb..477240cdf2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <net.h> @@ -12,6 +12,7 @@ #include <banman.h> #include <clientversion.h> #include <common/args.h> +#include <common/netif.h> #include <compat/compat.h> #include <consensus/consensus.h> #include <crypto/sha256.h> @@ -46,13 +47,12 @@ #include <algorithm> #include <array> +#include <cmath> #include <cstdint> #include <functional> #include <optional> #include <unordered_map> -#include <math.h> - /** Maximum number of block-relay-only anchor connections */ static constexpr size_t MAX_BLOCK_RELAY_ONLY_ANCHORS = 2; static_assert (MAX_BLOCK_RELAY_ONLY_ANCHORS <= static_cast<size_t>(MAX_BLOCK_RELAY_ONLY_CONNECTIONS), "MAX_BLOCK_RELAY_ONLY_ANCHORS must not exceed MAX_BLOCK_RELAY_ONLY_CONNECTIONS."); @@ -65,6 +65,9 @@ static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15}; /** Number of DNS seeds to query when the number of connections is low. */ static constexpr int DNSSEEDS_TO_QUERY_AT_ONCE = 3; +/** Minimum number of outbound connections under which we will keep fetching our address seeds. */ +static constexpr int SEED_OUTBOUND_CONNECTION_THRESHOLD = 2; + /** How long to delay before querying DNS seeds * * If we have more than THRESHOLD entries in addrman, then it's likely @@ -202,7 +205,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn) s >> endpoint; CAddress addr{endpoint, SeedsServiceFlags()}; addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week); - LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort()); + LogDebug(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort()); vSeedsOut.push_back(addr); } return vSeedsOut; @@ -255,7 +258,7 @@ std::optional<CService> GetLocalAddrForPeer(CNode& node) } } if (addrLocal.IsRoutable()) { - LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToStringAddrPort(), node.GetId()); + LogDebug(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToStringAddrPort(), node.GetId()); return addrLocal; } // Address is unroutable. Don't advertise. @@ -415,13 +418,13 @@ 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) { addrConnect = CAddress{MaybeFlipIPv6toCJDNS(r), NODE_NONE}; if (!addrConnect.IsValid()) { - LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToStringAddrPort(), pszDest); + LogDebug(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToStringAddrPort(), pszDest); return nullptr; } // It is possible that we already have a connection to the IP/port pszDest resolved to. @@ -551,7 +554,7 @@ void CNode::CloseSocketDisconnect() fDisconnect = true; LOCK(m_sock_mutex); if (m_sock) { - LogPrint(BCLog::NET, "disconnecting peer=%d\n", id); + LogDebug(BCLog::NET, "disconnecting peer=%d\n", id); m_sock.reset(); } m_i2p_sam_session.reset(); @@ -576,16 +579,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; } } @@ -722,19 +723,19 @@ int V1Transport::readHeader(Span<const uint8_t> msg_bytes) hdrbuf >> hdr; } catch (const std::exception&) { - LogPrint(BCLog::NET, "Header error: Unable to deserialize, peer=%d\n", m_node_id); + LogDebug(BCLog::NET, "Header error: Unable to deserialize, peer=%d\n", m_node_id); return -1; } // Check start string, network magic if (hdr.pchMessageStart != m_magic_bytes) { - LogPrint(BCLog::NET, "Header error: Wrong MessageStart %s received, peer=%d\n", HexStr(hdr.pchMessageStart), m_node_id); + LogDebug(BCLog::NET, "Header error: Wrong MessageStart %s received, peer=%d\n", HexStr(hdr.pchMessageStart), m_node_id); return -1; } // reject messages larger than MAX_SIZE or MAX_PROTOCOL_MESSAGE_LENGTH if (hdr.nMessageSize > MAX_SIZE || hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) { - LogPrint(BCLog::NET, "Header error: Size too large (%s, %u bytes), peer=%d\n", SanitizeString(hdr.GetCommand()), hdr.nMessageSize, m_node_id); + LogDebug(BCLog::NET, "Header error: Size too large (%s, %u bytes), peer=%d\n", SanitizeString(hdr.GetCommand()), hdr.nMessageSize, m_node_id); return -1; } @@ -793,14 +794,14 @@ CNetMessage V1Transport::GetReceivedMessage(const std::chrono::microseconds time // Check checksum and header message type string if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) { - LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n", + LogDebug(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n", SanitizeString(msg.m_type), msg.m_message_size, HexStr(Span{hash}.first(CMessageHeader::CHECKSUM_SIZE)), HexStr(hdr.pchChecksum), m_node_id); reject_message = true; } else if (!hdr.IsCommandValid()) { - LogPrint(BCLog::NET, "Header error: Invalid message type (%s, %u bytes), peer=%d\n", + LogDebug(BCLog::NET, "Header error: Invalid message type (%s, %u bytes), peer=%d\n", SanitizeString(hdr.GetCommand()), msg.m_message_size, m_node_id); reject_message = true; } @@ -1103,7 +1104,7 @@ bool V2Transport::ProcessReceivedKeyBytes() noexcept static constexpr size_t OFFSET = std::tuple_size_v<MessageStartChars>; if (!m_initiating && m_recv_buffer.size() >= OFFSET + MATCH.size()) { if (std::equal(MATCH.begin(), MATCH.end(), m_recv_buffer.begin() + OFFSET)) { - LogPrint(BCLog::NET, "V2 transport error: V1 peer with wrong MessageStart %s\n", + LogDebug(BCLog::NET, "V2 transport error: V1 peer with wrong MessageStart %s\n", HexStr(Span(m_recv_buffer).first(OFFSET))); return false; } @@ -1152,7 +1153,7 @@ bool V2Transport::ProcessReceivedGarbageBytes() noexcept Assume(m_recv_state == RecvState::GARB_GARBTERM); Assume(m_recv_buffer.size() <= MAX_GARBAGE_LEN + BIP324Cipher::GARBAGE_TERMINATOR_LEN); if (m_recv_buffer.size() >= BIP324Cipher::GARBAGE_TERMINATOR_LEN) { - if (MakeByteSpan(m_recv_buffer).last(BIP324Cipher::GARBAGE_TERMINATOR_LEN) == m_cipher.GetReceiveGarbageTerminator()) { + if (std::ranges::equal(MakeByteSpan(m_recv_buffer).last(BIP324Cipher::GARBAGE_TERMINATOR_LEN), m_cipher.GetReceiveGarbageTerminator())) { // Garbage terminator received. Store garbage to authenticate it as AAD later. m_recv_aad = std::move(m_recv_buffer); m_recv_aad.resize(m_recv_aad.size() - BIP324Cipher::GARBAGE_TERMINATOR_LEN); @@ -1161,7 +1162,7 @@ bool V2Transport::ProcessReceivedGarbageBytes() noexcept } else if (m_recv_buffer.size() == MAX_GARBAGE_LEN + BIP324Cipher::GARBAGE_TERMINATOR_LEN) { // We've reached the maximum length for garbage + garbage terminator, and the // terminator still does not match. Abort. - LogPrint(BCLog::NET, "V2 transport error: missing garbage terminator, peer=%d\n", m_nodeid); + LogDebug(BCLog::NET, "V2 transport error: missing garbage terminator, peer=%d\n", m_nodeid); return false; } else { // We still need to receive more garbage and/or garbage terminator bytes. @@ -1190,7 +1191,7 @@ bool V2Transport::ProcessReceivedPacketBytes() noexcept // Length descriptor received. m_recv_len = m_cipher.DecryptLength(MakeByteSpan(m_recv_buffer)); if (m_recv_len > MAX_CONTENTS_LEN) { - LogPrint(BCLog::NET, "V2 transport error: packet too large (%u bytes), peer=%d\n", m_recv_len, m_nodeid); + LogDebug(BCLog::NET, "V2 transport error: packet too large (%u bytes), peer=%d\n", m_recv_len, m_nodeid); return false; } } else if (m_recv_buffer.size() > BIP324Cipher::LENGTH_LEN && m_recv_buffer.size() == m_recv_len + BIP324Cipher::EXPANSION) { @@ -1205,7 +1206,7 @@ bool V2Transport::ProcessReceivedPacketBytes() noexcept /*ignore=*/ignore, /*contents=*/MakeWritableByteSpan(m_recv_decode_buffer)); if (!ret) { - LogPrint(BCLog::NET, "V2 transport error: packet decryption failure (%u bytes), peer=%d\n", m_recv_len, m_nodeid); + LogDebug(BCLog::NET, "V2 transport error: packet decryption failure (%u bytes), peer=%d\n", m_recv_len, m_nodeid); return false; } // We have decrypted a valid packet with the AAD we expected, so clear the expected AAD. @@ -1441,7 +1442,7 @@ CNetMessage V2Transport::GetReceivedMessage(std::chrono::microseconds time, bool msg.m_recv.resize(contents.size()); std::copy(contents.begin(), contents.end(), UCharCast(msg.m_recv.data())); } else { - LogPrint(BCLog::NET, "V2 transport error: invalid message type (%u bytes contents), peer=%d\n", m_recv_decode_buffer.size(), m_nodeid); + LogDebug(BCLog::NET, "V2 transport error: invalid message type (%u bytes contents), peer=%d\n", m_recv_decode_buffer.size(), m_nodeid); reject_message = true; } ClearShrink(m_recv_decode_buffer); @@ -1506,7 +1507,7 @@ void V2Transport::MarkBytesSent(size_t bytes_sent) noexcept if (m_send_state == SendState::V1) return m_v1_fallback.MarkBytesSent(bytes_sent); if (m_send_state == SendState::AWAITING_KEY && m_send_pos == 0 && bytes_sent > 0) { - LogPrint(BCLog::NET, "start sending v2 handshake to peer=%d\n", m_nodeid); + LogDebug(BCLog::NET, "start sending v2 handshake to peer=%d\n", m_nodeid); } m_send_pos += bytes_sent; @@ -1630,7 +1631,7 @@ std::pair<size_t, bool> CConnman::SocketSendData(CNode& node) const // error int nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) { - LogPrint(BCLog::NET, "socket send error for peer=%d: %s\n", node.GetId(), NetworkErrorString(nErr)); + LogDebug(BCLog::NET, "socket send error for peer=%d: %s\n", node.GetId(), NetworkErrorString(nErr)); node.CloseSocketDisconnect(); } } @@ -1690,7 +1691,7 @@ bool CConnman::AttemptToEvictConnection() LOCK(m_nodes_mutex); for (CNode* pnode : m_nodes) { if (pnode->GetId() == *node_id_to_evict) { - LogPrint(BCLog::NET, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId()); + LogDebug(BCLog::NET, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId()); pnode->fDisconnect = true; return true; } @@ -1743,7 +1744,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, } if (!fNetworkActive) { - LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToStringAddrPort()); + LogDebug(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToStringAddrPort()); return; } @@ -1756,7 +1757,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, // on all platforms. Set it again here just to be sure. const int on{1}; if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { - LogPrint(BCLog::NET, "connection from %s: unable to set TCP_NODELAY, continuing anyway\n", + LogDebug(BCLog::NET, "connection from %s: unable to set TCP_NODELAY, continuing anyway\n", addr.ToStringAddrPort()); } @@ -1764,7 +1765,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, bool banned = m_banman && m_banman->IsBanned(addr); if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && banned) { - LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToStringAddrPort()); + LogDebug(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToStringAddrPort()); return; } @@ -1772,7 +1773,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, bool discouraged = m_banman && m_banman->IsDiscouraged(addr); if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= m_max_inbound && discouraged) { - LogPrint(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToStringAddrPort()); + LogDebug(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToStringAddrPort()); return; } @@ -1780,7 +1781,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, { if (!AttemptToEvictConnection()) { // No connection to evict, disconnect the new connection - LogPrint(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n"); + LogDebug(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n"); return; } } @@ -1791,7 +1792,8 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end(); // The V2Transport transparently falls back to V1 behavior when an incoming V1 connection is // detected, so use it whenever we signal NODE_P2P_V2. - const bool use_v2transport(nLocalServices & NODE_P2P_V2); + ServiceFlags local_services = GetLocalServices(); + const bool use_v2transport(local_services & NODE_P2P_V2); CNode* pnode = new CNode(id, std::move(sock), @@ -1809,14 +1811,12 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, .use_v2transport = use_v2transport, }); pnode->AddRef(); - m_msgproc->InitializeNode(*pnode, nLocalServices); - - LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToStringAddrPort()); - + m_msgproc->InitializeNode(*pnode, local_services); { 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); @@ -1875,7 +1875,7 @@ void CConnman::DisconnectNodes() // Disconnect any connected nodes for (CNode* pnode : m_nodes) { if (!pnode->fDisconnect) { - LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId()); + LogDebug(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId()); pnode->fDisconnect = true; } } @@ -1900,7 +1900,7 @@ void CConnman::DisconnectNodes() .destination = pnode->m_dest, .conn_type = pnode->m_conn_type, .use_v2transport = false}); - LogPrint(BCLog::NET, "retrying with v1 transport protocol for peer=%d\n", pnode->GetId()); + LogDebug(BCLog::NET, "retrying with v1 transport protocol for peer=%d\n", pnode->GetId()); } // release outbound grant (if any) @@ -1968,22 +1968,26 @@ bool CConnman::InactivityCheck(const CNode& node) const if (!ShouldRunInactivityChecks(node, now)) return false; if (last_recv.count() == 0 || last_send.count() == 0) { - LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", count_seconds(m_peer_connect_timeout), last_recv.count() != 0, last_send.count() != 0, node.GetId()); + LogDebug(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", count_seconds(m_peer_connect_timeout), last_recv.count() != 0, last_send.count() != 0, node.GetId()); return true; } if (now > last_send + TIMEOUT_INTERVAL) { - LogPrint(BCLog::NET, "socket sending timeout: %is peer=%d\n", count_seconds(now - last_send), node.GetId()); + LogDebug(BCLog::NET, "socket sending timeout: %is peer=%d\n", count_seconds(now - last_send), node.GetId()); return true; } if (now > last_recv + TIMEOUT_INTERVAL) { - LogPrint(BCLog::NET, "socket receive timeout: %is peer=%d\n", count_seconds(now - last_recv), node.GetId()); + LogDebug(BCLog::NET, "socket receive timeout: %is peer=%d\n", count_seconds(now - last_recv), node.GetId()); return true; } if (!node.fSuccessfullyConnected) { - LogPrint(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId()); + if (node.m_transport->GetInfo().transport_type == TransportProtocolType::DETECTING) { + LogDebug(BCLog::NET, "V2 handshake timeout peer=%d\n", node.GetId()); + } else { + LogDebug(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId()); + } return true; } @@ -2122,7 +2126,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes, { // socket closed gracefully if (!pnode->fDisconnect) { - LogPrint(BCLog::NET, "socket closed for peer=%d\n", pnode->GetId()); + LogDebug(BCLog::NET, "socket closed for peer=%d\n", pnode->GetId()); } pnode->CloseSocketDisconnect(); } @@ -2133,7 +2137,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes, if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) { if (!pnode->fDisconnect) { - LogPrint(BCLog::NET, "socket recv error for peer=%d: %s\n", pnode->GetId(), NetworkErrorString(nErr)); + LogDebug(BCLog::NET, "socket recv error for peer=%d: %s\n", pnode->GetId(), NetworkErrorString(nErr)); } pnode->CloseSocketDisconnect(); } @@ -2180,7 +2184,6 @@ void CConnman::WakeMessageHandler() void CConnman::ThreadDNSAddressSeed() { - constexpr int TARGET_OUTBOUND_CONNECTIONS = 2; int outbound_connection_count = 0; if (gArgs.IsArgSet("-seednode")) { @@ -2199,7 +2202,7 @@ void CConnman::ThreadDNSAddressSeed() } outbound_connection_count = GetFullOutboundConnCount(); - if (outbound_connection_count >= TARGET_OUTBOUND_CONNECTIONS) { + if (outbound_connection_count >= SEED_OUTBOUND_CONNECTION_THRESHOLD) { LogPrintf("P2P peers available. Finished fetching data from seed nodes.\n"); break; } @@ -2208,7 +2211,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)) { @@ -2222,7 +2225,7 @@ void CConnman::ThreadDNSAddressSeed() } // Proceed with dnsseeds if seednodes hasn't reached the target or if forcednsseed is set - if (outbound_connection_count < TARGET_OUTBOUND_CONNECTIONS || seeds_right_now) { + if (outbound_connection_count < SEED_OUTBOUND_CONNECTION_THRESHOLD || seeds_right_now) { // goal: only query DNS seed if address need is acute // * If we have a reasonable number of peers in addrman, spend // some time trying them first. This improves user privacy by @@ -2253,7 +2256,7 @@ void CConnman::ThreadDNSAddressSeed() if (!interruptNet.sleep_for(w)) return; to_wait -= w; - if (GetFullOutboundConnCount() >= TARGET_OUTBOUND_CONNECTIONS) { + if (GetFullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) { if (found > 0) { LogPrintf("%d addresses found from DNS seeds\n", found); LogPrintf("P2P peers available. Finished DNS seeding.\n"); @@ -2324,7 +2327,7 @@ void CConnman::DumpAddresses() DumpPeerAddresses(::gArgs, addrman); - LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n", + LogDebug(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n", addrman.Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } @@ -2357,12 +2360,12 @@ bool CConnman::GetTryNewOutboundPeer() const void CConnman::SetTryNewOutboundPeer(bool flag) { m_try_another_outbound_peer = flag; - LogPrint(BCLog::NET, "setting try another outbound peer=%s\n", flag ? "true" : "false"); + LogDebug(BCLog::NET, "setting try another outbound peer=%s\n", flag ? "true" : "false"); } void CConnman::StartExtraBlockRelayPeers() { - LogPrint(BCLog::NET, "enabling extra block-relay-only peers\n"); + LogDebug(BCLog::NET, "enabling extra block-relay-only peers\n"); m_start_extra_block_relay_peers = true; } @@ -2435,7 +2438,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) { @@ -2448,7 +2451,7 @@ bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network) return false; } -void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) +void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, Span<const std::string> seed_nodes) { AssertLockNotHeld(m_unused_i2p_sessions_mutex); AssertLockNotHeld(m_reconnections_mutex); @@ -2481,19 +2484,35 @@ 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")}; + auto seed_node_timer = NodeClock::now(); + bool add_addr_fetch{addrman.Size() == 0 && !seed_nodes.empty()}; + constexpr std::chrono::seconds ADD_NEXT_SEEDNODE = 10s; + if (!add_fixed_seeds) { LogPrintf("Fixed seeds are disabled\n"); } while (!interruptNet) { + if (add_addr_fetch) { + add_addr_fetch = false; + const auto& seed{SpanPopBack(seed_nodes)}; + AddAddrFetch(seed); + + if (addrman.Size() == 0) { + LogInfo("Empty addrman, adding seednode (%s) to addrfetch\n", seed); + } else { + LogInfo("Couldn't connect to peers from addrman after %d seconds. Adding seednode (%s) to addrfetch\n", ADD_NEXT_SEEDNODE.count(), seed); + } + } + ProcessAddrFetch(); if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) @@ -2594,6 +2613,13 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) } } + if (!seed_nodes.empty() && nOutboundFullRelay < SEED_OUTBOUND_CONNECTION_THRESHOLD) { + if (NodeClock::now() > seed_node_timer + ADD_NEXT_SEEDNODE) { + seed_node_timer = NodeClock::now(); + add_addr_fetch = true; + } + } + ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY; auto now = GetTime<std::chrono::microseconds>(); bool anchor = false; @@ -2642,10 +2668,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 +2684,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; @@ -2668,6 +2694,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) const auto current_time{NodeClock::now()}; int nTries = 0; + const auto reachable_nets{g_reachable_nets.All()}; + while (!interruptNet) { if (anchor && !m_anchors.empty()) { @@ -2677,7 +2705,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) !m_msgproc->HasAllDesirableServiceFlags(addr.nServices) || outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) continue; addrConnect = addr; - LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort()); + LogDebug(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort()); break; } @@ -2699,7 +2727,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) if (!addr.IsValid()) { // No tried table collisions. Select a new table address // for our feeler. - std::tie(addr, addr_last_try) = addrman.Select(true); + std::tie(addr, addr_last_try) = addrman.Select(true, reachable_nets); } else if (AlreadyConnectedToAddress(addr)) { // If test-before-evict logic would have us connect to a // peer that we're already connected to, just mark that @@ -2708,14 +2736,16 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) // a currently-connected peer. addrman.Good(addr); // Select a new table address for our feeler instead. - std::tie(addr, addr_last_try) = addrman.Select(true); + std::tie(addr, addr_last_try) = addrman.Select(true, reachable_nets); } } else { // Not a feeler // If preferred_net has a value set, pick an extra outbound // peer from that network. The eviction logic in net_processing // ensures that a peer from another network will be evicted. - std::tie(addr, addr_last_try) = addrman.Select(false, preferred_net); + std::tie(addr, addr_last_try) = preferred_net.has_value() + ? addrman.Select(false, {*preferred_net}) + : addrman.Select(false, reachable_nets); } // Require outbound IPv4/IPv6 connections, other than feelers, to be to distinct network groups @@ -2772,10 +2802,10 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) { return; } - LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort()); + LogDebug(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort()); } - if (preferred_net != std::nullopt) LogPrint(BCLog::NET, "Making network specific connection to %s on %s.\n", addrConnect.ToStringAddrPort(), GetNetworkName(preferred_net.value())); + if (preferred_net != std::nullopt) LogDebug(BCLog::NET, "Making network specific connection to %s on %s.\n", addrConnect.ToStringAddrPort(), GetNetworkName(preferred_net.value())); // Record addrman failure attempts when node has at least 2 persistent outbound connections to peers with // different netgroups in ipv4/ipv6 networks + all peers in Tor/I2P/CJDNS networks. @@ -2920,7 +2950,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai return; pnode->grantOutbound = std::move(grant_outbound); - m_msgproc->InitializeNode(*pnode, nLocalServices); + m_msgproc->InitializeNode(*pnode, m_local_services); { LOCK(m_nodes_mutex); m_nodes.push_back(pnode); @@ -3029,7 +3059,7 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, return false; } - std::unique_ptr<Sock> sock = CreateSock(addrBind.GetSAFamily()); + std::unique_ptr<Sock> sock = CreateSock(addrBind.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP); if (!sock) { strError = strprintf(Untranslated("Couldn't open socket for incoming connections (socket returned error %s)"), NetworkErrorString(WSAGetLastError())); LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original); @@ -3089,46 +3119,10 @@ void Discover() if (!fDiscover) return; -#ifdef WIN32 - // Get local host IP - char pszHostName[256] = ""; - if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) - { - const std::vector<CNetAddr> addresses{LookupHost(pszHostName, 0, true)}; - for (const CNetAddr& addr : addresses) - { - if (AddLocal(addr, LOCAL_IF)) - LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToStringAddr()); - } + for (const CNetAddr &addr: GetLocalAddresses()) { + if (AddLocal(addr, LOCAL_IF)) + LogPrintf("%s: %s\n", __func__, addr.ToStringAddr()); } -#elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS) - // Get local host ip - struct ifaddrs* myaddrs; - if (getifaddrs(&myaddrs) == 0) - { - for (struct ifaddrs* ifa = myaddrs; ifa != nullptr; ifa = ifa->ifa_next) - { - if (ifa->ifa_addr == nullptr) continue; - if ((ifa->ifa_flags & IFF_UP) == 0) continue; - if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) continue; - if (ifa->ifa_addr->sa_family == AF_INET) - { - struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); - CNetAddr addr(s4->sin_addr); - if (AddLocal(addr, LOCAL_IF)) - LogPrintf("%s: IPv4 %s: %s\n", __func__, ifa->ifa_name, addr.ToStringAddr()); - } - else if (ifa->ifa_addr->sa_family == AF_INET6) - { - struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); - CNetAddr addr(s6->sin6_addr); - if (AddLocal(addr, LOCAL_IF)) - LogPrintf("%s: IPv6 %s: %s\n", __func__, ifa->ifa_name, addr.ToStringAddr()); - } - } - freeifaddrs(myaddrs); - } -#endif } void CConnman::SetNetworkActive(bool active) @@ -3198,24 +3192,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) @@ -3238,8 +3244,10 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) i2p_sam, &interruptNet); } - for (const auto& strDest : connOptions.vSeedNodes) { - AddAddrFetch(strDest); + // Randomize the order in which we may query seednode to potentially prevent connecting to the same one every restart (and signal that we have restarted) + std::vector<std::string> seed_nodes = connOptions.vSeedNodes; + if (!seed_nodes.empty()) { + std::shuffle(seed_nodes.begin(), seed_nodes.end(), FastRandomContext{}); } if (m_use_addrman_outgoing) { @@ -3300,7 +3308,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty()) { threadOpenConnections = std::thread( &util::TraceThread, "opencon", - [this, connect = connOptions.m_specified_outgoing] { ThreadOpenConnections(connect); }); + [this, connect = connOptions.m_specified_outgoing, seed_nodes = std::move(seed_nodes)] { ThreadOpenConnections(connect, seed_nodes); }); } // Process messages @@ -3475,7 +3483,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 +3542,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); @@ -3554,7 +3570,7 @@ bool CConnman::DisconnectNode(const std::string& strNode) { LOCK(m_nodes_mutex); if (CNode* pnode = FindNode(strNode)) { - LogPrint(BCLog::NET, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId()); + LogDebug(BCLog::NET, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId()); pnode->fDisconnect = true; return true; } @@ -3567,7 +3583,7 @@ bool CConnman::DisconnectNode(const CSubNet& subnet) LOCK(m_nodes_mutex); for (CNode* pnode : m_nodes) { if (subnet.Match(pnode->addr)) { - LogPrint(BCLog::NET, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId()); + LogDebug(BCLog::NET, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId()); pnode->fDisconnect = true; disconnected = true; } @@ -3585,7 +3601,7 @@ bool CConnman::DisconnectNode(NodeId id) LOCK(m_nodes_mutex); for(CNode* pnode : m_nodes) { if (id == pnode->GetId()) { - LogPrint(BCLog::NET, "disconnect by id peer=%d; disconnecting\n", pnode->GetId()); + LogDebug(BCLog::NET, "disconnect by id peer=%d; disconnecting\n", pnode->GetId()); pnode->fDisconnect = true; return true; } @@ -3695,7 +3711,7 @@ uint64_t CConnman::GetTotalBytesSent() const ServiceFlags CConnman::GetLocalServices() const { - return nLocalServices; + return m_local_services; } static std::unique_ptr<Transport> MakeTransport(NodeId id, bool use_v2transport, bool inbound) noexcept @@ -3742,9 +3758,9 @@ CNode::CNode(NodeId idIn, mapRecvBytesPerMsgType[NET_MESSAGE_TYPE_OTHER] = 0; if (fLogIPs) { - LogPrint(BCLog::NET, "Added connection to %s peer=%d\n", m_addr_name, id); + LogDebug(BCLog::NET, "Added connection to %s peer=%d\n", m_addr_name, id); } else { - LogPrint(BCLog::NET, "Added connection peer=%d\n", id); + LogDebug(BCLog::NET, "Added connection peer=%d\n", id); } } @@ -3788,7 +3804,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) { AssertLockNotHeld(m_total_bytes_sent_mutex); size_t nMessageSize = msg.data.size(); - LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId()); + LogDebug(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId()); if (gArgs.GetBoolArg("-capturemessages", false)) { CaptureMessage(pnode->addr, msg.m_type, msg.data, /*is_incoming=*/false); } @@ -148,7 +148,7 @@ enum LOCAL_NONE, // unknown LOCAL_IF, // address a local interface listens on LOCAL_BIND, // address explicit bound to - LOCAL_MAPPED, // address reported by UPnP or NAT-PMP + LOCAL_MAPPED, // address reported by UPnP or PCP LOCAL_MANUAL, // address explicitly specified (-externalip=) LOCAL_MAX @@ -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; @@ -1035,7 +1035,7 @@ public: struct Options { - ServiceFlags nLocalServices = NODE_NONE; + ServiceFlags m_local_services = NODE_NONE; int m_max_automatic_connections = 0; CClientUIInterface* uiInterface = nullptr; NetEventsInterface* m_msgproc = nullptr; @@ -1065,7 +1065,7 @@ public: { AssertLockNotHeld(m_total_bytes_sent_mutex); - nLocalServices = connOptions.nLocalServices; + m_local_services = connOptions.m_local_services; m_max_automatic_connections = connOptions.m_max_automatic_connections; m_max_outbound_full_relay = std::min(MAX_OUTBOUND_FULL_RELAY_CONNECTIONS, m_max_automatic_connections); m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, m_max_automatic_connections - m_max_outbound_full_relay); @@ -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); @@ -1220,6 +1221,11 @@ public: //! that peer during `net_processing.cpp:PushNodeVersion()`. ServiceFlags GetLocalServices() const; + //! Updates the local services that this node advertises to other peers + //! during connection handshake. + void AddLocalServices(ServiceFlags services) { m_local_services = ServiceFlags(m_local_services | services); }; + void RemoveLocalServices(ServiceFlags services) { m_local_services = ServiceFlags(m_local_services & ~services); } + uint64_t GetMaxOutboundTarget() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex); std::chrono::seconds GetMaxOutboundTimeframe() const; @@ -1272,7 +1278,7 @@ private: void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex); void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex); void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex); - void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex); + void ThreadOpenConnections(std::vector<std::string> connect, Span<const std::string> seed_nodes) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex); void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); void ThreadI2PAcceptIncoming(); void AcceptConnection(const ListenSocket& hListenSocket); @@ -1459,11 +1465,12 @@ private: * This data is replicated in each Peer instance we create. * * This data is not marked const, but after being set it should not - * change. + * change. Unless AssumeUTXO is started, in which case, the peer + * will be limited until the background chain sync finishes. * * \sa Peer::our_services */ - ServiceFlags nLocalServices; + std::atomic<ServiceFlags> m_local_services; std::unique_ptr<CSemaphore> semOutbound; std::unique_ptr<CSemaphore> semAddnode; @@ -1625,7 +1632,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_permissions.cpp b/src/net_permissions.cpp index b01b2f643d..8f0042c141 100644 --- a/src/net_permissions.cpp +++ b/src/net_permissions.cpp @@ -2,12 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/messages.h> #include <common/system.h> #include <net_permissions.h> #include <netbase.h> -#include <util/error.h> #include <util/translation.h> +using common::ResolveErrMsg; + const std::vector<std::string> NET_PERMISSIONS_DOC{ "bloomfilter (allow requesting BIP37 filtered blocks and transactions)", "noban (do not ban for misbehavior; implies download)", diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6374cb52c1..be16884011 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -25,13 +25,13 @@ #include <node/blockstorage.h> #include <node/timeoffsets.h> #include <node/txreconciliation.h> +#include <node/warnings.h> #include <policy/fees.h> #include <policy/policy.h> #include <policy/settings.h> #include <primitives/block.h> #include <primitives/transaction.h> #include <random.h> -#include <reverse_iterator.h> #include <scheduler.h> #include <streams.h> #include <sync.h> @@ -50,9 +50,12 @@ #include <future> #include <memory> #include <optional> +#include <ranges> #include <typeinfo> #include <utility> +using namespace util::hex_literals; + /** Headers download timeout. * Timeout = base + per_header * (expected number of headers) */ static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_BASE = 15min; @@ -110,9 +113,6 @@ static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16; static constexpr auto BLOCK_STALLING_TIMEOUT_DEFAULT{2s}; /** Maximum timeout for stalling block download. */ static constexpr auto BLOCK_STALLING_TIMEOUT_MAX{64s}; -/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends - * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ -static const unsigned int MAX_HEADERS_RESULTS = 2000; /** Maximum depth of blocks we're willing to serve as compact blocks to peers * when requested. For older blocks, a regular BLOCK response will be sent. */ static const int MAX_CMPCTBLOCK_DEPTH = 5; @@ -130,8 +130,6 @@ static constexpr double BLOCK_DOWNLOAD_TIMEOUT_BASE = 1; static constexpr double BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 0.5; /** Maximum number of headers to announce when relaying blocks with headers message.*/ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; -/** Maximum number of unconnecting headers announcements before DoS score */ -static const int MAX_NUM_UNCONNECTING_HEADERS_MSGS = 10; /** Minimum blocks required to signal NODE_NETWORK_LIMITED */ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; /** Window, in blocks, for connecting to NODE_NETWORK_LIMITED peers */ @@ -223,10 +221,11 @@ struct Peer { /** Services this peer offered to us. */ std::atomic<ServiceFlags> m_their_services{NODE_NONE}; + //! Whether this peer is an inbound connection + const bool m_is_inbound; + /** Protects misbehavior data members */ Mutex m_misbehavior_mutex; - /** Accumulated misbehavior score for this peer */ - int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0}; /** Whether this peer should be disconnected and marked as discouraged (unless it has NetPermissionFlags::NoBan permission). */ bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false}; @@ -246,6 +245,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}; @@ -382,9 +384,6 @@ struct Peer { /** Whether we've sent our peer a sendheaders message. **/ std::atomic<bool> m_sent_sendheaders{false}; - /** Length of current-streak of unconnecting headers announcements */ - int m_num_unconnecting_headers_msgs GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0}; - /** When to potentially disconnect peer for stalling headers download */ std::chrono::microseconds m_headers_sync_timeout GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0us}; @@ -395,9 +394,10 @@ struct Peer { * timestamp the peer sent in the version message. */ std::atomic<std::chrono::seconds> m_time_offset{0s}; - explicit Peer(NodeId id, ServiceFlags our_services) + explicit Peer(NodeId id, ServiceFlags our_services, bool is_inbound) : m_id{id} , m_our_services{our_services} + , m_is_inbound{is_inbound} {} private: @@ -477,11 +477,6 @@ struct CNodeState { //! Time of last new block announcement int64_t m_last_block_announcement{0}; - - //! Whether this peer is an inbound connection - const bool m_is_inbound; - - CNodeState(bool is_inbound) : m_is_inbound(is_inbound) {} }; class PeerManagerImpl final : public PeerManager @@ -489,13 +484,15 @@ class PeerManagerImpl final : public PeerManager public: PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* banman, ChainstateManager& chainman, - CTxMemPool& pool, Options opts); + 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 @@ -504,13 +501,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; @@ -518,6 +515,7 @@ public: std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() override EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); @@ -526,10 +524,10 @@ public: m_best_height = height; m_best_block_time = time; }; - void UnitTestMisbehaving(NodeId peer_id, int howmuch) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving(*Assert(GetPeerRef(peer_id)), howmuch, ""); }; + 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; @@ -551,11 +549,9 @@ private: * May return an empty shared_ptr if the Peer object can't be found. */ PeerRef RemovePeer(NodeId id) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - /** - * Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node - * to be discouraged, meaning the peer might be disconnected and added to the discouragement filter. - */ - void Misbehaving(Peer& peer, int howmuch, const std::string& message); + /** Mark a peer as misbehaving, which will cause it to be disconnected and its + * address discouraged. */ + void Misbehaving(Peer& peer, const std::string& message); /** * Potentially mark a node discouraged based on the contents of a BlockValidationState object @@ -564,19 +560,15 @@ private: * punish peers differently depending on whether the data was provided in a compact * block message or not. If the compact block had a valid header, but contained invalid * txs, the peer should not be punished. See BIP 152. - * - * @return Returns true if the peer was punished (probably disconnected) */ - bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, + void MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message = "") EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** * Potentially disconnect and discourage a node based on the contents of a TxValidationState object - * - * @return Returns true if the peer was punished (probably disconnected) */ - bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state) + void MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Maybe disconnect a peer and discourage future connections from its address. @@ -591,15 +583,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; @@ -629,13 +621,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. @@ -649,7 +641,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. * @@ -667,10 +659,10 @@ private: bool CheckHeadersPoW(const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams, Peer& peer); /** Calculate an anti-DoS work threshold for headers chains */ arith_uint256 GetAntiDoSWorkThreshold(); - /** Deal with state tracking and headers sync for peers that send the - * occasional non-connecting header (this can happen due to BIP 130 headers + /** Deal with state tracking and headers sync for peers that send + * non-connecting headers (this can happen due to BIP 130 headers * announcements for blocks interacting with the 2hr (MAX_FUTURE_BLOCK_TIME) rule). */ - void HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer, const std::vector<CBlockHeader>& headers) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); + void HandleUnconnectingHeaders(CNode& pfrom, Peer& peer, const std::vector<CBlockHeader>& headers) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); /** Return true if the headers connect to each other, false otherwise */ bool CheckHeadersAreContinuous(const std::vector<CBlockHeader>& headers) const; /** Try to continue a low-work headers sync that has already begun. @@ -731,7 +723,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)); } @@ -779,7 +771,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 */ @@ -790,7 +792,8 @@ private: /** Next time to check for stale tip */ std::chrono::seconds m_stale_tip_check_time GUARDED_BY(cs_main){0s}; - TimeOffsets m_outbound_time_offsets; + node::Warnings& m_warnings; + TimeOffsets m_outbound_time_offsets{m_warnings}; const Options m_opts; @@ -852,14 +855,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. @@ -895,10 +896,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: @@ -906,7 +915,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 @@ -918,9 +927,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. @@ -937,8 +957,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 @@ -947,7 +977,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 @@ -982,7 +1012,7 @@ private: bool IsBlockRequested(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Have we requested this block from an outbound peer */ - bool IsBlockRequestedFromOutbound(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool IsBlockRequestedFromOutbound(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); /** Remove this block from our tracked requested blocks. Called if: * - the block has been received from a peer @@ -1066,7 +1096,7 @@ private: * lNodesAnnouncingHeaderAndIDs, and keeping that list under a certain size by * removing the first element if necessary. */ - void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); /** Stack of nodes which we have set to announce using compact blocks */ std::list<NodeId> lNodesAnnouncingHeaderAndIDs GUARDED_BY(cs_main); @@ -1075,7 +1105,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); @@ -1107,7 +1137,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. @@ -1175,7 +1205,7 @@ private: void PushAddress(Peer& peer, const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); }; -const CNodeState* PeerManagerImpl::State(NodeId pnode) const EXCLUSIVE_LOCKS_REQUIRED(cs_main) +const CNodeState* PeerManagerImpl::State(NodeId pnode) const { std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode); if (it == m_node_states.end()) @@ -1183,7 +1213,7 @@ const CNodeState* PeerManagerImpl::State(NodeId pnode) const EXCLUSIVE_LOCKS_REQ return &it->second; } -CNodeState* PeerManagerImpl::State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +CNodeState* PeerManagerImpl::State(NodeId pnode) { return const_cast<CNodeState*>(std::as_const(*this).State(pnode)); } @@ -1255,7 +1285,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; } @@ -1269,8 +1299,8 @@ bool PeerManagerImpl::IsBlockRequestedFromOutbound(const uint256& hash) { for (auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) { auto [nodeid, block_it] = range.first->second; - CNodeState& nodestate = *Assert(State(nodeid)); - if (!nodestate.m_is_inbound) return true; + PeerRef peer{GetPeerRef(nodeid)}; + if (peer && !peer->m_is_inbound) return true; } return false; @@ -1359,6 +1389,7 @@ void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) if (m_opts.ignore_incoming_txs) return; CNodeState* nodestate = State(nodeid); + PeerRef peer{GetPeerRef(nodeid)}; if (!nodestate || !nodestate->m_provides_cmpctblocks) { // Don't request compact blocks if the peer has not signalled support return; @@ -1371,15 +1402,15 @@ void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) lNodesAnnouncingHeaderAndIDs.push_back(nodeid); return; } - CNodeState *state = State(*it); - if (state != nullptr && !state->m_is_inbound) ++num_outbound_hb_peers; + PeerRef peer_ref{GetPeerRef(*it)}; + if (peer_ref && !peer_ref->m_is_inbound) ++num_outbound_hb_peers; } - if (nodestate->m_is_inbound) { + if (peer && peer->m_is_inbound) { // If we're adding an inbound HB peer, make sure we're not removing // our last outbound HB peer in the process. if (lNodesAnnouncingHeaderAndIDs.size() >= 3 && num_outbound_hb_peers == 1) { - CNodeState *remove_node = State(lNodesAnnouncingHeaderAndIDs.front()); - if (remove_node != nullptr && !remove_node->m_is_inbound) { + PeerRef remove_peer{GetPeerRef(lNodesAnnouncingHeaderAndIDs.front())}; + if (remove_peer && !remove_peer->m_is_inbound) { // Put the HB outbound peer in the second slot, so that it // doesn't get removed. std::swap(lNodesAnnouncingHeaderAndIDs.front(), *std::next(lNodesAnnouncingHeaderAndIDs.begin())); @@ -1487,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())]; } @@ -1630,15 +1672,16 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer) nonce, strSubVersion, nNodeStartingHeight, tx_relay); if (fLogIPs) { - LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, them=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addr_you.ToStringAddrPort(), tx_relay, nodeid); + LogDebug(BCLog::NET, "send version message: version %d, blocks=%d, them=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addr_you.ToStringAddrPort(), tx_relay, nodeid); } else { - LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, tx_relay, nodeid); + LogDebug(BCLog::NET, "send version message: version %d, blocks=%d, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, tx_relay, nodeid); } } 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 @@ -1670,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); - m_node_states.emplace_hint(m_node_states.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(node.IsInboundConn())); + LOCK(cs_main); // For m_node_states + m_node_states.try_emplace(m_node_states.end(), nodeid); + } + { + LOCK(m_tx_download_mutex); assert(m_txrequest.Count(nodeid) == 0); } @@ -1683,14 +1729,11 @@ void PeerManagerImpl::InitializeNode(CNode& node, ServiceFlags our_services) our_services = static_cast<ServiceFlags>(our_services | NODE_BLOOM); } - PeerRef peer = std::make_shared<Peer>(nodeid, our_services); + PeerRef peer = std::make_shared<Peer>(nodeid, our_services, node.IsInboundConn()); { 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) @@ -1709,14 +1752,13 @@ 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); } void PeerManagerImpl::FinalizeNode(const CNode& node) { NodeId nodeid = node.GetId(); - int misbehavior{0}; { LOCK(cs_main); { @@ -1727,7 +1769,6 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) // destructed. PeerRef peer = RemovePeer(nodeid); assert(peer != nullptr); - misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score); m_wtxid_relay_peers -= peer->m_wtxid_relay; assert(m_wtxid_relay_peers >= 0); } @@ -1748,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()); @@ -1766,11 +1810,12 @@ 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); } } // cs_main - if (node.fSuccessfullyConnected && misbehavior == 0 && + if (node.fSuccessfullyConnected && !node.IsBlockOnlyConn() && !node.IsInboundConn()) { // Only change visible addrman state for full outbound peers. We don't // call Connected() for feeler connections since they don't have @@ -1781,7 +1826,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) LOCK(m_headers_presync_mutex); m_headers_presync_stats.erase(nodeid); } - LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); + LogDebug(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); } bool PeerManagerImpl::HasAllDesirableServiceFlags(ServiceFlags services) const @@ -1873,6 +1918,12 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c return true; } +std::vector<TxOrphanage::OrphanTxBase> PeerManagerImpl::GetOrphanTransactions() +{ + LOCK(m_tx_download_mutex); + return m_orphanage.GetOrphanTransactions(); +} + PeerManagerInfo PeerManagerImpl::GetInfo() const { return PeerManagerInfo{ @@ -1891,28 +1942,16 @@ void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx) vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs; } -void PeerManagerImpl::Misbehaving(Peer& peer, int howmuch, const std::string& message) +void PeerManagerImpl::Misbehaving(Peer& peer, const std::string& message) { - assert(howmuch > 0); - LOCK(peer.m_misbehavior_mutex); - const int score_before{peer.m_misbehavior_score}; - peer.m_misbehavior_score += howmuch; - const int score_now{peer.m_misbehavior_score}; const std::string message_prefixed = message.empty() ? "" : (": " + message); - std::string warning; - - if (score_now >= DISCOURAGEMENT_THRESHOLD && score_before < DISCOURAGEMENT_THRESHOLD) { - warning = " DISCOURAGE THRESHOLD EXCEEDED"; - peer.m_should_discourage = true; - } - - LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d)%s%s\n", - peer.m_id, score_before, score_now, warning, message_prefixed); + peer.m_should_discourage = true; + LogDebug(BCLog::NET, "Misbehaving: peer=%d%s\n", peer.m_id, message_prefixed); } -bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, +void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message) { PeerRef peer{GetPeerRef(nodeid)}; @@ -1927,47 +1966,39 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati case BlockValidationResult::BLOCK_CONSENSUS: case BlockValidationResult::BLOCK_MUTATED: if (!via_compact_block) { - if (peer) Misbehaving(*peer, 100, message); - return true; + if (peer) Misbehaving(*peer, message); + return; } break; case BlockValidationResult::BLOCK_CACHED_INVALID: { - LOCK(cs_main); - CNodeState *node_state = State(nodeid); - if (node_state == nullptr) { - break; - } - // Discourage outbound (but not inbound) peers if on an invalid chain. // Exempt HB compact block peers. Manual connections are always protected from discouragement. - if (!via_compact_block && !node_state->m_is_inbound) { - if (peer) Misbehaving(*peer, 100, message); - return true; + if (peer && !via_compact_block && !peer->m_is_inbound) { + if (peer) Misbehaving(*peer, message); + return; } break; } case BlockValidationResult::BLOCK_INVALID_HEADER: case BlockValidationResult::BLOCK_CHECKPOINT: case BlockValidationResult::BLOCK_INVALID_PREV: - if (peer) Misbehaving(*peer, 100, message); - return true; + if (peer) Misbehaving(*peer, message); + return; // Conflicting (but not necessarily invalid) data or different policy: case BlockValidationResult::BLOCK_MISSING_PREV: - // TODO: Handle this much more gracefully (10 DoS points is super arbitrary) - if (peer) Misbehaving(*peer, 10, message); - return true; + if (peer) Misbehaving(*peer, message); + return; case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE: case BlockValidationResult::BLOCK_TIME_FUTURE: break; } if (message != "") { - LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message); + LogDebug(BCLog::NET, "peer=%d: %s\n", nodeid, message); } - return false; } -bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state) +void PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state) { PeerRef peer{GetPeerRef(nodeid)}; switch (state.GetResult()) { @@ -1975,8 +2006,8 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat break; // The node is providing invalid data: case TxValidationResult::TX_CONSENSUS: - if (peer) Misbehaving(*peer, 100, ""); - return true; + if (peer) Misbehaving(*peer, ""); + return; // Conflicting (but not necessarily invalid) data or different policy: case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE: case TxValidationResult::TX_INPUTS_NOT_STANDARD: @@ -1992,7 +2023,6 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat case TxValidationResult::TX_UNKNOWN: break; } - return false; } bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex) @@ -2035,21 +2065,21 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl if (!success) return "Peer not fully connected"; - LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", + LogDebug(BCLog::NET, "Requesting block %s from peer=%d\n", hash.ToString(), peer_id); return std::nullopt; } std::unique_ptr<PeerManager> PeerManager::make(CConnman& connman, AddrMan& addrman, BanMan* banman, ChainstateManager& chainman, - CTxMemPool& pool, Options opts) + CTxMemPool& pool, node::Warnings& warnings, Options opts) { - return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, opts); + return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, warnings, opts); } PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* banman, ChainstateManager& chainman, - CTxMemPool& pool, Options opts) + CTxMemPool& pool, node::Warnings& warnings, Options opts) : m_rng{opts.deterministic_rng}, m_fee_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}, m_rng}, m_chainparams(chainman.GetParams()), @@ -2058,6 +2088,7 @@ PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman, m_banman(banman), m_chainman(chainman), m_mempool(pool), + m_warnings{warnings}, m_opts{opts} { // While Erlay support is incomplete, it must be enabled explicitly via -txreconciliation. @@ -2077,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 @@ -2102,7 +2150,7 @@ void PeerManagerImpl::BlockConnected( if (stalling_timeout != BLOCK_STALLING_TIMEOUT_DEFAULT) { const auto new_timeout = std::max(std::chrono::duration_cast<std::chrono::seconds>(stalling_timeout * 0.85), BLOCK_STALLING_TIMEOUT_DEFAULT); if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) { - LogPrint(BCLog::NET, "Decreased stalling timeout to %d seconds\n", count_seconds(new_timeout)); + LogDebug(BCLog::NET, "Decreased stalling timeout to %d seconds\n", count_seconds(new_timeout)); } } @@ -2111,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()); } } @@ -2141,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(); } /** @@ -2151,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); + auto pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock, FastRandomContext().rand64()); LOCK(cs_main); @@ -2190,7 +2231,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha // but we don't think they have this one, go ahead and announce it if (state.m_requested_hb_cmpctblocks && !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) { - LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerManager::NewPoWValidBlock", + LogDebug(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerManager::NewPoWValidBlock", hashBlock.ToString(), pnode->GetId()); const CSerializedNetMsg& ser_cmpctblock{lazy_ser.get()}; @@ -2229,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); } } @@ -2281,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(); @@ -2311,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) @@ -2433,7 +2463,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& if (need_activate_chain) { BlockValidationState state; if (!m_chainman.ActiveChainstate().ActivateBestChain(state, a_recent_block)) { - LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString()); + LogDebug(BCLog::NET, "failed to activate chain (%s)\n", state.ToString()); } } @@ -2448,7 +2478,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& return; } if (!BlockRequestAllowed(pindex)) { - LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId()); + LogDebug(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId()); return; } // disconnect node in case we have reached the outbound limit for serving historical blocks @@ -2456,7 +2486,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& (((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) && !pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target ) { - LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -2465,7 +2495,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& if (!pfrom.HasPermission(NetPermissionFlags::NoBan) && ( (((peer.m_our_services & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((peer.m_our_services & NODE_NETWORK) != NODE_NETWORK) && (tip->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) ) )) { - LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n", pfrom.GetId()); //disconnect node and prevent it from stalling (would otherwise wait for the missing block) pfrom.fDisconnect = true; return; @@ -2488,7 +2518,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& std::vector<uint8_t> block_data; if (!m_chainman.m_blockman.ReadRawBlockFromDisk(block_data, block_pos)) { if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) { - LogPrint(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId()); } else { LogError("Cannot load block from disk, disconnect peer=%d\n", pfrom.GetId()); } @@ -2502,7 +2532,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>(); if (!m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, block_pos)) { if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) { - LogPrint(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId()); } else { LogError("Cannot load block from disk, disconnect peer=%d\n", pfrom.GetId()); } @@ -2549,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}; + CBlockHeaderAndShortTxIDs cmpctblock{*pblock, m_rng.rand64()}; MakeAndPushMessage(pfrom, NetMsgType::CMPCTBLOCK, cmpctblock); } } else { @@ -2676,7 +2706,7 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlo BlockTransactions resp(req); for (size_t i = 0; i < req.indexes.size(); i++) { if (req.indexes[i] >= block.vtx.size()) { - Misbehaving(peer, 100, "getblocktxn with out-of-bounds tx indices"); + Misbehaving(peer, "getblocktxn with out-of-bounds tx indices"); return; } resp.txn[i] = block.vtx[req.indexes[i]]; @@ -2689,13 +2719,13 @@ bool PeerManagerImpl::CheckHeadersPoW(const std::vector<CBlockHeader>& headers, { // Do these headers have proof-of-work matching what's claimed? if (!HasValidProofOfWork(headers, consensusParams)) { - Misbehaving(peer, 100, "header with invalid proof of work"); + Misbehaving(peer, "header with invalid proof of work"); return false; } // Are these headers connected to each other? if (!CheckHeadersAreContinuous(headers)) { - Misbehaving(peer, 20, "non-continuous headers sequence"); + Misbehaving(peer, "non-continuous headers sequence"); return false; } return true; @@ -2719,37 +2749,24 @@ arith_uint256 PeerManagerImpl::GetAntiDoSWorkThreshold() * announcement. * * We'll send a getheaders message in response to try to connect the chain. - * - * The peer can send up to MAX_NUM_UNCONNECTING_HEADERS_MSGS in a row that - * don't connect before given DoS points. - * - * Once a headers message is received that is valid and does connect, - * m_num_unconnecting_headers_msgs gets reset back to 0. */ -void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer, +void PeerManagerImpl::HandleUnconnectingHeaders(CNode& pfrom, Peer& peer, const std::vector<CBlockHeader>& headers) { - peer.m_num_unconnecting_headers_msgs++; // Try to fill in the missing headers. const CBlockIndex* best_header{WITH_LOCK(cs_main, return m_chainman.m_best_header)}; if (MaybeSendGetHeaders(pfrom, GetLocator(best_header), peer)) { - LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, m_num_unconnecting_headers_msgs=%d)\n", + LogDebug(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d)\n", headers[0].GetHash().ToString(), headers[0].hashPrevBlock.ToString(), best_header->nHeight, - pfrom.GetId(), peer.m_num_unconnecting_headers_msgs); + pfrom.GetId()); } // Set hashLastUnknownBlock for this peer, so that if we // eventually get the headers - even from a different peer - // we can use this peer to download. WITH_LOCK(cs_main, UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash())); - - // The peer may just be broken, so periodically assign DoS points if this - // condition persists. - if (peer.m_num_unconnecting_headers_msgs % MAX_NUM_UNCONNECTING_HEADERS_MSGS == 0) { - Misbehaving(peer, 20, strprintf("%d non-connecting headers", peer.m_num_unconnecting_headers_msgs)); - } } bool PeerManagerImpl::CheckHeadersAreContinuous(const std::vector<CBlockHeader>& headers) const @@ -2767,26 +2784,22 @@ bool PeerManagerImpl::CheckHeadersAreContinuous(const std::vector<CBlockHeader>& bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(Peer& peer, CNode& pfrom, std::vector<CBlockHeader>& headers) { if (peer.m_headers_sync) { - auto result = peer.m_headers_sync->ProcessNextHeaders(headers, headers.size() == MAX_HEADERS_RESULTS); + auto result = peer.m_headers_sync->ProcessNextHeaders(headers, headers.size() == m_opts.max_headers_result); + // If it is a valid continuation, we should treat the existing getheaders request as responded to. + if (result.success) peer.m_last_getheaders_timestamp = {}; if (result.request_more) { auto locator = peer.m_headers_sync->NextHeadersRequestLocator(); // If we were instructed to ask for a locator, it should not be empty. Assume(!locator.vHave.empty()); + // We can only be instructed to request more if processing was successful. + Assume(result.success); if (!locator.vHave.empty()) { // It should be impossible for the getheaders request to fail, - // because we should have cleared the last getheaders timestamp - // when processing the headers that triggered this call. But - // it may be possible to bypass this via compactblock - // processing, so check the result before logging just to be - // safe. + // because we just cleared the last getheaders timestamp. bool sent_getheaders = MaybeSendGetHeaders(pfrom, locator, peer); - if (sent_getheaders) { - LogPrint(BCLog::NET, "more getheaders (from %s) to peer=%d\n", - locator.vHave.front().ToString(), pfrom.GetId()); - } else { - LogPrint(BCLog::NET, "error sending next getheaders (from %s) to continue sync with peer=%d\n", - locator.vHave.front().ToString(), pfrom.GetId()); - } + Assume(sent_getheaders); + LogDebug(BCLog::NET, "more getheaders (from %s) to peer=%d\n", + locator.vHave.front().ToString(), pfrom.GetId()); } } @@ -2865,7 +2878,7 @@ bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer, CNode& pfrom, const CBlo // Only try to sync with this peer if their headers message was full; // otherwise they don't have more headers after this so no point in // trying to sync their too-little-work chain. - if (headers.size() == MAX_HEADERS_RESULTS) { + if (headers.size() == m_opts.max_headers_result) { // Note: we could advance to the last header in this set that is // known to us, rather than starting at the first header (which we // may already have); however this is unlikely to matter much since @@ -2884,7 +2897,7 @@ bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer, CNode& pfrom, const CBlo // handled inside of IsContinuationOfLowWorkHeadersSync. (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers); } else { - LogPrint(BCLog::NET, "Ignoring low-work chain (height=%u) from peer=%d\n", chain_start_header->nHeight + headers.size(), pfrom.GetId()); + LogDebug(BCLog::NET, "Ignoring low-work chain (height=%u) from peer=%d\n", chain_start_header->nHeight + headers.size(), pfrom.GetId()); } // The peer has not yet given us a chain that meets our work threshold, @@ -2950,13 +2963,13 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c // the main chain -- this shouldn't really happen. Bail out on the // direct fetch and rely on parallel download instead. if (!m_chainman.ActiveChain().Contains(pindexWalk)) { - LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", + LogDebug(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", last_header.GetBlockHash().ToString(), last_header.nHeight); } 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; @@ -2964,11 +2977,11 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c uint32_t nFetchFlags = GetFetchFlags(peer); vGetData.emplace_back(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()); BlockRequested(pfrom.GetId(), *pindex); - LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", + LogDebug(BCLog::NET, "Requesting block %s from peer=%d\n", pindex->GetBlockHash().ToString(), pfrom.GetId()); } if (vGetData.size() > 1) { - LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n", + LogDebug(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n", last_header.GetBlockHash().ToString(), last_header.nHeight); } @@ -2995,11 +3008,6 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, Peer& peer, const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers) { - if (peer.m_num_unconnecting_headers_msgs > 0) { - LogPrint(BCLog::NET, "peer=%d: resetting m_num_unconnecting_headers_msgs (%d -> 0)\n", pfrom.GetId(), peer.m_num_unconnecting_headers_msgs); - } - peer.m_num_unconnecting_headers_msgs = 0; - LOCK(cs_main); CNodeState *nodestate = State(pfrom.GetId()); @@ -3041,7 +3049,7 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, Peer& peer // See ChainSyncTimeoutState. if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) { if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { - LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId()); nodestate->m_chain_sync.m_protect = true; ++m_outbound_peers_with_protect_from_disconnect; } @@ -3065,6 +3073,9 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer, LOCK(m_headers_presync_mutex); m_headers_presync_stats.erase(pfrom.GetId()); } + // A headers message with no headers cannot be an announcement, so assume + // it is a response to our last getheaders request, if there is one. + peer.m_last_getheaders_timestamp = {}; return; } @@ -3118,17 +3129,18 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer, bool headers_connect_blockindex{chain_start_header != nullptr}; if (!headers_connect_blockindex) { - if (nCount <= MAX_BLOCKS_TO_ANNOUNCE) { - // If this looks like it could be a BIP 130 block announcement, use - // special logic for handling headers that don't connect, as this - // could be benign. - HandleFewUnconnectingHeaders(pfrom, peer, headers); - } else { - Misbehaving(peer, 10, "invalid header received"); - } + // This could be a BIP 130 block announcement, use + // special logic for handling headers that don't connect, as this + // could be benign. + HandleUnconnectingHeaders(pfrom, peer, headers); return; } + // If headers connect, assume that this is in response to any outstanding getheaders + // request we may have sent, and clear out the time of our last request. Non-connecting + // headers cannot be a response to a getheaders request. + peer.m_last_getheaders_timestamp = {}; + // If the headers we received are already in memory and an ancestor of // m_best_header or our tip, skip anti-DoS checks. These headers will not // use any more memory (and we are not leaking information that could be @@ -3178,15 +3190,15 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer, assert(pindexLast); // Consider fetching more headers if we are not using our headers-sync mechanism. - if (nCount == MAX_HEADERS_RESULTS && !have_headers_sync) { + if (nCount == m_opts.max_headers_result && !have_headers_sync) { // Headers message had its maximum size; the peer may have more headers. if (MaybeSendGetHeaders(pfrom, GetLocator(pindexLast), peer)) { - LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", + LogDebug(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height); } } - UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS); + UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast, received_new_header, nCount == m_opts.max_headers_result); // Consider immediately downloading blocks. HeadersDirectFetchBlocks(pfrom, peer, *pindexLast); @@ -3199,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(), @@ -3224,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, @@ -3243,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) { @@ -3264,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. @@ -3292,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; @@ -3348,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 @@ -3364,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}; } } @@ -3384,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}; } } @@ -3401,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; @@ -3412,11 +3424,11 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer) const Wtxid& orphan_wtxid = porphanTx->GetWitnessHash(); if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { - LogPrint(BCLog::TXPACKAGES, " accepted orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString()); + LogDebug(BCLog::TXPACKAGES, " accepted orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString()); ProcessValidTx(peer.m_id, porphanTx, result.m_replaced_transactions); return true; } else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) { - LogPrint(BCLog::TXPACKAGES, " invalid orphan tx %s (wtxid=%s) from peer=%d. %s\n", + LogDebug(BCLog::TXPACKAGES, " invalid orphan tx %s (wtxid=%s) from peer=%d. %s\n", orphanHash.ToString(), orphan_wtxid.ToString(), peer.m_id, @@ -3445,7 +3457,7 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer, (filter_type == BlockFilterType::BASIC && (peer.m_our_services & NODE_COMPACT_FILTERS)); if (!supported_filter_type) { - LogPrint(BCLog::NET, "peer %d requested unsupported block filter type: %d\n", + LogDebug(BCLog::NET, "peer %d requested unsupported block filter type: %d\n", node.GetId(), static_cast<uint8_t>(filter_type)); node.fDisconnect = true; return false; @@ -3457,7 +3469,7 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer, // Check that the stop block exists and the peer would be allowed to fetch it. if (!stop_index || !BlockRequestAllowed(stop_index)) { - LogPrint(BCLog::NET, "peer %d requested invalid block hash: %s\n", + LogDebug(BCLog::NET, "peer %d requested invalid block hash: %s\n", node.GetId(), stop_hash.ToString()); node.fDisconnect = true; return false; @@ -3466,14 +3478,14 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer, uint32_t stop_height = stop_index->nHeight; if (start_height > stop_height) { - LogPrint(BCLog::NET, "peer %d sent invalid getcfilters/getcfheaders with " + LogDebug(BCLog::NET, "peer %d sent invalid getcfilters/getcfheaders with " "start height %d and stop height %d\n", node.GetId(), start_height, stop_height); node.fDisconnect = true; return false; } if (stop_height - start_height >= max_height_diff) { - LogPrint(BCLog::NET, "peer %d requested too many cfilters/cfheaders: %d / %d\n", + LogDebug(BCLog::NET, "peer %d requested too many cfilters/cfheaders: %d / %d\n", node.GetId(), stop_height - start_height + 1, max_height_diff); node.fDisconnect = true; return false; @@ -3481,7 +3493,7 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer, filter_index = GetBlockFilterIndex(filter_type); if (!filter_index) { - LogPrint(BCLog::NET, "Filter index for supported type %s not found\n", BlockFilterTypeName(filter_type)); + LogDebug(BCLog::NET, "Filter index for supported type %s not found\n", BlockFilterTypeName(filter_type)); return false; } @@ -3507,7 +3519,7 @@ void PeerManagerImpl::ProcessGetCFilters(CNode& node, Peer& peer, DataStream& vR std::vector<BlockFilter> filters; if (!filter_index->LookupFilterRange(start_height, stop_index, filters)) { - LogPrint(BCLog::NET, "Failed to find block filter in index: filter_type=%s, start_height=%d, stop_hash=%s\n", + LogDebug(BCLog::NET, "Failed to find block filter in index: filter_type=%s, start_height=%d, stop_hash=%s\n", BlockFilterTypeName(filter_type), start_height, stop_hash.ToString()); return; } @@ -3539,7 +3551,7 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& node, Peer& peer, DataStream& v const CBlockIndex* const prev_block = stop_index->GetAncestor(static_cast<int>(start_height - 1)); if (!filter_index->LookupFilterHeader(prev_block, prev_header)) { - LogPrint(BCLog::NET, "Failed to find block filter header in index: filter_type=%s, block_hash=%s\n", + LogDebug(BCLog::NET, "Failed to find block filter header in index: filter_type=%s, block_hash=%s\n", BlockFilterTypeName(filter_type), prev_block->GetBlockHash().ToString()); return; } @@ -3547,7 +3559,7 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& node, Peer& peer, DataStream& v std::vector<uint256> filter_hashes; if (!filter_index->LookupFilterHashRange(start_height, stop_index, filter_hashes)) { - LogPrint(BCLog::NET, "Failed to find block filter hashes in index: filter_type=%s, start_height=%d, stop_hash=%s\n", + LogDebug(BCLog::NET, "Failed to find block filter hashes in index: filter_type=%s, start_height=%d, stop_hash=%s\n", BlockFilterTypeName(filter_type), start_height, stop_hash.ToString()); return; } @@ -3585,7 +3597,7 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& node, Peer& peer, DataStream& v block_index = block_index->GetAncestor(height); if (!filter_index->LookupFilterHeader(block_index, headers[i])) { - LogPrint(BCLog::NET, "Failed to find block filter header in index: filter_type=%s, block_hash=%s\n", + LogDebug(BCLog::NET, "Failed to find block filter header in index: filter_type=%s, block_hash=%s\n", BlockFilterTypeName(filter_type), block_index->GetBlockHash().ToString()); return; } @@ -3638,7 +3650,7 @@ void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const Bl } if (!requested_block_from_this_peer) { - LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId()); return; } @@ -3646,7 +3658,7 @@ void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const Bl ReadStatus status = partialBlock.FillBlock(*pblock, block_transactions.txn); if (status == READ_STATUS_INVALID) { RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect - Misbehaving(peer, 100, "invalid compact block/non-matching block transactions"); + Misbehaving(peer, "invalid compact block/non-matching block transactions"); return; } else if (status == READ_STATUS_FAILED) { if (first_in_flight) { @@ -3656,7 +3668,7 @@ void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const Bl MakeAndPushMessage(pfrom, NetMsgType::GETDATA, invs); } else { RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); - LogPrint(BCLog::NET, "Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.GetId()); return; } } else { @@ -3706,14 +3718,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, { AssertLockHeld(g_msgproc_mutex); - LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId()); + LogDebug(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId()); PeerRef peer = GetPeerRef(pfrom.GetId()); if (peer == nullptr) return; if (msg_type == NetMsgType::VERSION) { if (pfrom.nVersion != 0) { - LogPrint(BCLog::NET, "redundant version message from peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "redundant version message from peer=%d\n", pfrom.GetId()); return; } @@ -3741,14 +3753,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } if (pfrom.ExpectServicesFromConn() && !HasAllDesirableServiceFlags(nServices)) { - LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom.GetId(), nServices, GetDesirableServiceFlags(nServices)); + LogDebug(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom.GetId(), nServices, GetDesirableServiceFlags(nServices)); pfrom.fDisconnect = true; return; } if (nVersion < MIN_PEER_PROTO_VERSION) { // disconnect from peers older than this proto version - LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom.GetId(), nVersion); + LogDebug(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom.GetId(), nVersion); pfrom.fDisconnect = true; return; } @@ -3904,7 +3916,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, remoteAddr = ", peeraddr=" + pfrom.addr.ToStringAddrPort(); const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)}; - LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s%s\n", + LogDebug(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s%s\n", cleanSubVer, pfrom.nVersion, peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(), remoteAddr, (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : "")); @@ -3919,13 +3931,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // If the peer is old enough to have the old alert system, send it the final alert. if (greatest_common_version <= 70012) { - const auto finalAlert{ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50")}; - MakeAndPushMessage(pfrom, "alert", Span{finalAlert}); + constexpr auto finalAlert{"60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"_hex}; + MakeAndPushMessage(pfrom, "alert", finalAlert); } // Feeler connections exist only to verify if address is online. if (pfrom.IsFeelerConn()) { - LogPrint(BCLog::NET, "feeler connection completed peer=%d; disconnecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "feeler connection completed peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; } return; @@ -3933,13 +3945,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (pfrom.nVersion == 0) { // Must have a version message before anything else - LogPrint(BCLog::NET, "non-version message before version handshake. Message \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); + LogDebug(BCLog::NET, "non-version message before version handshake. Message \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); return; } if (msg_type == NetMsgType::VERACK) { if (pfrom.fSuccessfullyConnected) { - LogPrint(BCLog::NET, "ignoring redundant verack message from peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "ignoring redundant verack message from peer=%d\n", pfrom.GetId()); return; } @@ -4019,7 +4031,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (msg_type == NetMsgType::WTXIDRELAY) { if (pfrom.fSuccessfullyConnected) { // Disconnect peers that send a wtxidrelay message after VERACK. - LogPrint(BCLog::NET, "wtxidrelay received after verack from peer=%d; disconnecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "wtxidrelay received after verack from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -4028,10 +4040,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, peer->m_wtxid_relay = true; m_wtxid_relay_peers++; } else { - LogPrint(BCLog::NET, "ignoring duplicate wtxidrelay from peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "ignoring duplicate wtxidrelay from peer=%d\n", pfrom.GetId()); } } else { - LogPrint(BCLog::NET, "ignoring wtxidrelay due to old common version=%d from peer=%d\n", pfrom.GetCommonVersion(), pfrom.GetId()); + LogDebug(BCLog::NET, "ignoring wtxidrelay due to old common version=%d from peer=%d\n", pfrom.GetCommonVersion(), pfrom.GetId()); } return; } @@ -4041,7 +4053,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (msg_type == NetMsgType::SENDADDRV2) { if (pfrom.fSuccessfullyConnected) { // Disconnect peers that send a SENDADDRV2 message after VERACK. - LogPrint(BCLog::NET, "sendaddrv2 received after verack from peer=%d; disconnecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "sendaddrv2 received after verack from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -4106,7 +4118,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } if (!pfrom.fSuccessfullyConnected) { - LogPrint(BCLog::NET, "Unsupported message \"%s\" prior to verack from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); + LogDebug(BCLog::NET, "Unsupported message \"%s\" prior to verack from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); return; } @@ -4124,13 +4136,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, vRecv >> ser_params(vAddr); if (!SetupAddressRelay(pfrom, *peer)) { - LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId()); + LogDebug(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId()); return; } if (vAddr.size() > MAX_ADDR_TO_SEND) { - Misbehaving(*peer, 20, strprintf("%s message size = %u", msg_type, vAddr.size())); + Misbehaving(*peer, strprintf("%s message size = %u", msg_type, vAddr.size())); return; } @@ -4151,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) @@ -4193,7 +4205,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } peer->m_addr_processed += num_proc; peer->m_addr_rate_limited += num_rate_limit; - LogPrint(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n", + LogDebug(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n", vAddr.size(), num_proc, num_rate_limit, pfrom.GetId()); m_addrman.Add(vAddrOk, pfrom.addr, 2h); @@ -4201,7 +4213,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements if (pfrom.IsAddrFetchConn() && vAddr.size() > 1) { - LogPrint(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; } return; @@ -4212,13 +4224,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) { - Misbehaving(*peer, 20, strprintf("inv message size = %u", vInv.size())); + Misbehaving(*peer, strprintf("inv message size = %u", vInv.size())); return; } 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}; @@ -4237,7 +4249,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (inv.IsMsgBlk()) { const bool fAlreadyHave = AlreadyHaveBlock(inv.hash); - LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId()); + LogDebug(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId()); UpdateBlockAvailability(pfrom.GetId(), inv.hash); if (!fAlreadyHave && !m_chainman.m_blockman.LoadingBlocks() && !IsBlockRequested(inv.hash)) { @@ -4251,20 +4263,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } } else if (inv.IsGenTxMsg()) { if (reject_tx_invs) { - LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId()); + LogDebug(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId()); pfrom.fDisconnect = true; return; } const GenTxid gtxid = ToGenTxid(inv); const bool fAlreadyHave = AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true); - LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId()); + LogDebug(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId()); AddKnownTx(*peer, inv.hash); if (!fAlreadyHave && !m_chainman.IsInitialBlockDownload()) { AddTxAnnouncement(pfrom, gtxid, current_time); } } else { - LogPrint(BCLog::NET, "Unknown inv type \"%s\" received from peer=%d\n", inv.ToString(), pfrom.GetId()); + LogDebug(BCLog::NET, "Unknown inv type \"%s\" received from peer=%d\n", inv.ToString(), pfrom.GetId()); } } @@ -4282,7 +4294,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CNodeState& state{*Assert(State(pfrom.GetId()))}; if (state.fSyncStarted || (!peer->m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) { if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer)) { - LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", + LogDebug(BCLog::NET, "getheaders (%d) %s to peer=%d\n", m_chainman.m_best_header->nHeight, best_block->ToString(), pfrom.GetId()); } @@ -4304,14 +4316,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) { - Misbehaving(*peer, 20, strprintf("getdata message size = %u", vInv.size())); + Misbehaving(*peer, strprintf("getdata message size = %u", vInv.size())); return; } - LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom.GetId()); + LogDebug(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom.GetId()); if (vInv.size() > 0) { - LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom.GetId()); + LogDebug(BCLog::NET, "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom.GetId()); } { @@ -4329,7 +4341,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, vRecv >> locator >> hashStop; if (locator.vHave.size() > MAX_LOCATOR_SZ) { - LogPrint(BCLog::NET, "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId()); + LogDebug(BCLog::NET, "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -4349,7 +4361,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } BlockValidationState state; if (!m_chainman.ActiveChainstate().ActivateBestChain(state, a_recent_block)) { - LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString()); + LogDebug(BCLog::NET, "failed to activate chain (%s)\n", state.ToString()); } } @@ -4362,26 +4374,26 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (pindex) pindex = m_chainman.ActiveChain().Next(pindex); int nLimit = 500; - LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom.GetId()); + LogDebug(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom.GetId()); for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex)) { if (pindex->GetBlockHash() == hashStop) { - LogPrint(BCLog::NET, " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + LogDebug(BCLog::NET, " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); break; } // If pruning, don't inv blocks unless we have on disk and are likely to still have // for some reasonable time window (1 hour) that block relay might require. const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing; if (m_chainman.m_blockman.IsPruneMode() && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= m_chainman.ActiveChain().Tip()->nHeight - nPrunedBlocksLikelyToHave)) { - LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + LogDebug(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); break; } WITH_LOCK(peer->m_block_inv_mutex, peer->m_blocks_for_inv_relay.push_back(pindex->GetBlockHash())); if (--nLimit <= 0) { // When this block is requested, we'll send an inv that'll // trigger the peer to getblocks the next batch of inventory. - LogPrint(BCLog::NET, " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + LogDebug(BCLog::NET, " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); WITH_LOCK(peer->m_block_inv_mutex, {peer->m_continuation_block = pindex->GetBlockHash();}); break; } @@ -4411,7 +4423,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(req.blockhash); if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) { - LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId()); return; } @@ -4438,7 +4450,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // might maliciously send lots of getblocktxn requests to trigger // expensive disk reads, because it will require the peer to // actually receive all the data read from disk over the network. - LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom.GetId(), MAX_BLOCKTXN_DEPTH); + LogDebug(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom.GetId(), MAX_BLOCKTXN_DEPTH); CInv inv{MSG_WITNESS_BLOCK, req.blockhash}; WITH_LOCK(peer->m_getdata_requests_mutex, peer->m_getdata_requests.push_back(inv)); // The message processing loop will go around again (without pausing) and we'll respond then @@ -4451,13 +4463,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, vRecv >> locator >> hashStop; if (locator.vHave.size() > MAX_LOCATOR_SZ) { - LogPrint(BCLog::NET, "getheaders locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId()); + LogDebug(BCLog::NET, "getheaders locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId()); pfrom.fDisconnect = true; return; } if (m_chainman.m_blockman.LoadingBlocks()) { - LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d while importing/reindexing\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Ignoring getheaders from peer=%d while importing/reindexing\n", pfrom.GetId()); return; } @@ -4472,7 +4484,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // others. if (m_chainman.ActiveTip() == nullptr || (m_chainman.ActiveTip()->nChainWork < m_chainman.MinimumChainWork() && !pfrom.HasPermission(NetPermissionFlags::Download))) { - LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because active chain has too little work; sending empty response\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Ignoring getheaders from peer=%d because active chain has too little work; sending empty response\n", pfrom.GetId()); // Just respond with an empty headers message, to tell the peer to // go away but not treat us as unresponsive. MakeAndPushMessage(pfrom, NetMsgType::HEADERS, std::vector<CBlockHeader>()); @@ -4490,7 +4502,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } if (!BlockRequestAllowed(pindex)) { - LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.GetId()); + LogDebug(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.GetId()); return; } } @@ -4504,8 +4516,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end std::vector<CBlock> vHeaders; - int nLimit = MAX_HEADERS_RESULTS; - LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom.GetId()); + int nLimit = m_opts.max_headers_result; + LogDebug(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom.GetId()); for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex)) { vHeaders.emplace_back(pindex->GetBlockHeader()); @@ -4531,7 +4543,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (msg_type == NetMsgType::TX) { if (RejectIncomingTxs(pfrom)) { - LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -4551,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); @@ -4583,11 +4595,11 @@ 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", + LogDebug(BCLog::TXPACKAGES, "found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n", txid.ToString(), wtxid.ToString()); if (auto package_to_validate{Find1P1CPackage(ptx, pfrom.GetId())}) { const auto package_result{ProcessNewPackage(m_chainman.ActiveChainstate(), m_mempool, package_to_validate->m_txns, /*test_accept=*/false, /*client_maxfeerate=*/std::nullopt)}; @@ -4596,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; } @@ -4636,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; @@ -4665,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); } @@ -4681,7 +4693,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789) m_orphanage.LimitOrphans(m_opts.max_orphan_txs, m_rng); } else { - LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n", + LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n", tx.GetHash().ToString(), tx.GetWitnessHash().ToString()); // We will continue to reject this tx since it has rejected @@ -4690,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()); } @@ -4702,7 +4714,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the // orphanage, as it is possible that they succeed as a package. if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) { - LogPrint(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n", + LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n", txid.ToString(), wtxid.ToString()); if (auto package_to_validate{Find1P1CPackage(ptx, pfrom.GetId())}) { const auto package_result{ProcessNewPackage(m_chainman.ActiveChainstate(), m_mempool, package_to_validate->m_txns, /*test_accept=*/false, /*client_maxfeerate=*/std::nullopt)}; @@ -4719,7 +4731,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, { // Ignore cmpctblock received while importing if (m_chainman.m_blockman.LoadingBlocks()) { - LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom.GetId()); return; } @@ -4739,9 +4751,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer); } return; - } else if (prev_block->nChainWork + CalculateClaimedHeadersWork({cmpctblock.header}) < GetAntiDoSWorkThreshold()) { + } else if (prev_block->nChainWork + CalculateClaimedHeadersWork({{cmpctblock.header}}) < GetAntiDoSWorkThreshold()) { // If we get a low-work header in a compact block, we can ignore it. - LogPrint(BCLog::NET, "Ignoring low-work compact block from peer %d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Ignoring low-work compact block from peer %d\n", pfrom.GetId()); return; } @@ -4752,7 +4764,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const CBlockIndex *pindex = nullptr; BlockValidationState state; - if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, /*min_pow_checked=*/true, state, &pindex)) { + if (!m_chainman.ProcessNewBlockHeaders({{cmpctblock.header}}, /*min_pow_checked=*/true, state, &pindex)) { if (state.IsInvalid()) { MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block=*/true, "invalid header via cmpctblock"); return; @@ -4835,7 +4847,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, (*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&m_mempool)); else { // The block was already in flight using compact blocks from the same peer - LogPrint(BCLog::NET, "Peer sent us compact block we were already syncing!\n"); + LogDebug(BCLog::NET, "Peer sent us compact block we were already syncing!\n"); return; } } @@ -4844,7 +4856,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact); if (status == READ_STATUS_INVALID) { RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect - Misbehaving(*peer, 100, "invalid compact block"); + Misbehaving(*peer, "invalid compact block"); return; } else if (status == READ_STATUS_FAILED) { if (first_in_flight) { @@ -4966,7 +4978,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, { // Ignore blocktxn received while importing if (m_chainman.m_blockman.LoadingBlocks()) { - LogPrint(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom.GetId()); return; } @@ -4980,20 +4992,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, { // Ignore headers received while importing if (m_chainman.m_blockman.LoadingBlocks()) { - LogPrint(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom.GetId()); return; } - // Assume that this is in response to any outstanding getheaders - // request we may have sent, and clear out the time of our last request - peer->m_last_getheaders_timestamp = {}; - std::vector<CBlockHeader> headers; // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks. unsigned int nCount = ReadCompactSize(vRecv); - if (nCount > MAX_HEADERS_RESULTS) { - Misbehaving(*peer, 20, strprintf("headers message size = %u", nCount)); + if (nCount > m_opts.max_headers_result) { + Misbehaving(*peer, strprintf("headers message size = %u", nCount)); return; } headers.resize(nCount); @@ -5025,14 +5033,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, { // Ignore block received while importing if (m_chainman.m_blockman.LoadingBlocks()) { - LogPrint(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom.GetId()); return; } std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); vRecv >> TX_WITH_WITNESS(*pblock); - LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom.GetId()); + LogDebug(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom.GetId()); const CBlockIndex* prev_block{WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.LookupBlockIndex(pblock->hashPrevBlock))}; @@ -5040,7 +5048,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (prev_block && IsBlockMutated(/*block=*/*pblock, /*check_witness_root=*/DeploymentActiveAfter(prev_block, m_chainman, Consensus::DEPLOYMENT_SEGWIT))) { LogDebug(BCLog::NET, "Received mutated block from peer=%d\n", peer->m_id); - Misbehaving(*peer, 100, "mutated block"); + Misbehaving(*peer, "mutated block"); WITH_LOCK(cs_main, RemoveBlockRequest(pblock->GetHash(), peer->m_id)); return; } @@ -5060,7 +5068,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true)); // Check claimed work on this block against our anti-dos thresholds. - if (prev_block && prev_block->nChainWork + CalculateClaimedHeadersWork({pblock->GetBlockHeader()}) >= GetAntiDoSWorkThreshold()) { + if (prev_block && prev_block->nChainWork + CalculateClaimedHeadersWork({{pblock->GetBlockHeader()}}) >= GetAntiDoSWorkThreshold()) { min_pow_checked = true; } } @@ -5075,7 +5083,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // Making nodes which are behind NAT and can only make outgoing connections ignore // the getaddr message mitigates the attack. if (!pfrom.IsInboundConn()) { - LogPrint(BCLog::NET, "Ignoring \"getaddr\" from %s connection. peer=%d\n", pfrom.ConnectionTypeAsString(), pfrom.GetId()); + LogDebug(BCLog::NET, "Ignoring \"getaddr\" from %s connection. peer=%d\n", pfrom.ConnectionTypeAsString(), pfrom.GetId()); return; } @@ -5086,7 +5094,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // Only send one GetAddr response per connection to reduce resource waste // and discourage addr stamping of INV announcements. if (peer->m_getaddr_recvd) { - LogPrint(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom.GetId()); return; } peer->m_getaddr_recvd = true; @@ -5111,7 +5119,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, { if (!pfrom.HasPermission(NetPermissionFlags::NoBan)) { - LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom.GetId()); pfrom.fDisconnect = true; } return; @@ -5121,7 +5129,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, { if (!pfrom.HasPermission(NetPermissionFlags::NoBan)) { - LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom.GetId()); + LogDebug(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom.GetId()); pfrom.fDisconnect = true; } return; @@ -5196,7 +5204,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } if (!(sProblem.empty())) { - LogPrint(BCLog::NET, "pong peer=%d: %s, %x expected, %x received, %u bytes\n", + LogDebug(BCLog::NET, "pong peer=%d: %s, %x expected, %x received, %u bytes\n", pfrom.GetId(), sProblem, peer->m_ping_nonce_sent, @@ -5211,7 +5219,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (msg_type == NetMsgType::FILTERLOAD) { if (!(peer->m_our_services & NODE_BLOOM)) { - LogPrint(BCLog::NET, "filterload received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "filterload received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -5221,7 +5229,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (!filter.IsWithinSizeConstraints()) { // There is no excuse for sending a too-large filter - Misbehaving(*peer, 100, "too-large bloom filter"); + Misbehaving(*peer, "too-large bloom filter"); } else if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) { { LOCK(tx_relay->m_bloom_filter_mutex); @@ -5236,7 +5244,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (msg_type == NetMsgType::FILTERADD) { if (!(peer->m_our_services & NODE_BLOOM)) { - LogPrint(BCLog::NET, "filteradd received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "filteradd received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -5257,14 +5265,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } } if (bad) { - Misbehaving(*peer, 100, "bad filteradd message"); + Misbehaving(*peer, "bad filteradd message"); } return; } if (msg_type == NetMsgType::FILTERCLEAR) { if (!(peer->m_our_services & NODE_BLOOM)) { - LogPrint(BCLog::NET, "filterclear received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); + LogDebug(BCLog::NET, "filterclear received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -5288,7 +5296,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) { tx_relay->m_fee_filter_received = newFeeFilter; } - LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId()); + LogDebug(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId()); } return; } @@ -5312,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 @@ -5325,7 +5333,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } // Ignore unknown commands for extensibility - LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); + LogDebug(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); return; } @@ -5355,14 +5363,14 @@ bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer) if (pnode.addr.IsLocal()) { // We disconnect local peers for bad behavior but don't discourage (since that would discourage // all peers on the same local address) - LogPrint(BCLog::NET, "Warning: disconnecting but not discouraging %s peer %d!\n", + LogDebug(BCLog::NET, "Warning: disconnecting but not discouraging %s peer %d!\n", pnode.m_inbound_onion ? "inbound onion" : "local", peer.m_id); pnode.fDisconnect = true; return true; } // Normal case: Disconnect the peer and discourage all nodes sharing the address - LogPrint(BCLog::NET, "Disconnecting and discouraging peer %d!\n", peer.m_id); + LogDebug(BCLog::NET, "Disconnecting and discouraging peer %d!\n", peer.m_id); if (m_banman) m_banman->Discourage(pnode.addr); m_connman.DisconnectNode(pnode.addr); return true; @@ -5370,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()) { @@ -5433,11 +5446,12 @@ 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()); + LogDebug(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(msg.m_type), msg.m_message_size, e.what(), typeid(e).name()); } catch (...) { - LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(msg.m_type), msg.m_message_size); + LogDebug(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(msg.m_type), msg.m_message_size); } return fMoreWork; @@ -5490,7 +5504,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, Peer& peer, std::chrono::seco MaybeSendGetHeaders(pto, GetLocator(state.m_chain_sync.m_work_header->pprev), peer); - LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); + LogDebug(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); state.m_chain_sync.m_sent_getheaders = true; // Bump the timeout to allow a response, which could clear the timeout // (if the response shows the peer has synced), reset the timeout (if @@ -5539,11 +5553,11 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) if (node_state == nullptr || (now - pnode->m_connected >= MINIMUM_CONNECT_TIME && node_state->vBlocksInFlight.empty())) { pnode->fDisconnect = true; - LogPrint(BCLog::NET, "disconnecting extra block-relay-only peer=%d (last block received at time %d)\n", + LogDebug(BCLog::NET, "disconnecting extra block-relay-only peer=%d (last block received at time %d)\n", pnode->GetId(), count_seconds(pnode->m_last_block_time)); return true; } else { - LogPrint(BCLog::NET, "keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", + LogDebug(BCLog::NET, "keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", pnode->GetId(), count_seconds(pnode->m_connected), node_state->vBlocksInFlight.size()); } return false; @@ -5590,11 +5604,11 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) // block from. CNodeState &state = *State(pnode->GetId()); if (now - pnode->m_connected > MINIMUM_CONNECT_TIME && state.vBlocksInFlight.empty()) { - LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement); + LogDebug(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement); pnode->fDisconnect = true; return true; } else { - LogPrint(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", + LogDebug(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", pnode->GetId(), count_seconds(pnode->m_connected), state.vBlocksInFlight.size()); return false; } @@ -5646,7 +5660,7 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::mic { // The ping timeout is using mocktime. To disable the check during // testing, increase -peertimeout. - LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), peer.m_id); + LogDebug(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), peer.m_id); node_to.fDisconnect = true; return; } @@ -5666,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; @@ -5703,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 @@ -5796,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); } } @@ -5856,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()); @@ -5866,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; @@ -5873,7 +5894,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) const auto current_time{GetTime<std::chrono::microseconds>()}; if (pto->IsAddrFetchConn() && current_time - pto->m_connected > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) { - LogPrint(BCLog::NET, "addrfetch connection timeout; disconnecting peer=%d\n", pto->GetId()); + LogDebug(BCLog::NET, "addrfetch connection timeout; disconnecting peer=%d\n", pto->GetId()); pto->fDisconnect = true; return true; } @@ -5932,7 +5953,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) if (pindexStart->pprev) pindexStart = pindexStart->pprev; if (MaybeSendGetHeaders(*pto, GetLocator(pindexStart), *peer)) { - LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height); + LogDebug(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height); state.fSyncStarted = true; peer->m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE + @@ -6017,7 +6038,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) { // We only send up to 1 block as header-and-ids, as otherwise // probably means we're doing an initial-ish-sync or they're slow - LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", __func__, + LogDebug(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", __func__, vHeaders.front().GetHash().ToString(), pto->GetId()); std::optional<CSerializedNetMsg> cached_cmpctblock_msg; @@ -6033,18 +6054,18 @@ bool PeerManagerImpl::SendMessages(CNode* pto) CBlock block; const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pBestIndex)}; assert(ret); - CBlockHeaderAndShortTxIDs cmpctblock{block}; + CBlockHeaderAndShortTxIDs cmpctblock{block, m_rng.rand64()}; MakeAndPushMessage(*pto, NetMsgType::CMPCTBLOCK, cmpctblock); } state.pindexBestHeaderSent = pBestIndex; } else if (peer->m_prefers_headers) { if (vHeaders.size() > 1) { - LogPrint(BCLog::NET, "%s: %u headers, range (%s, %s), to peer=%d\n", __func__, + LogDebug(BCLog::NET, "%s: %u headers, range (%s, %s), to peer=%d\n", __func__, vHeaders.size(), vHeaders.front().GetHash().ToString(), vHeaders.back().GetHash().ToString(), pto->GetId()); } else { - LogPrint(BCLog::NET, "%s: sending header %s to peer=%d\n", __func__, + LogDebug(BCLog::NET, "%s: sending header %s to peer=%d\n", __func__, vHeaders.front().GetHash().ToString(), pto->GetId()); } MakeAndPushMessage(*pto, NetMsgType::HEADERS, TX_WITH_WITNESS(vHeaders)); @@ -6065,14 +6086,14 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // This should be very rare and could be optimized out. // Just log for now. if (m_chainman.ActiveChain()[pindex->nHeight] != pindex) { - LogPrint(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n", + LogDebug(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n", hashToAnnounce.ToString(), m_chainman.ActiveChain().Tip()->GetBlockHash().ToString()); } // If the peer's chain has this block, don't inv it back. if (!PeerHasHeader(&state, pindex)) { peer->m_blocks_for_inv_relay.push_back(hashToAnnounce); - LogPrint(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", __func__, + LogDebug(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", __func__, pto->GetId(), hashToAnnounce.ToString()); } } @@ -6108,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); } } @@ -6223,7 +6244,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // bandwidth is insufficient. const auto new_timeout = std::min(2 * stalling_timeout, BLOCK_STALLING_TIMEOUT_MAX); if (stalling_timeout != new_timeout && m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) { - LogPrint(BCLog::NET, "Increased stalling timeout temporarily to %d seconds\n", count_seconds(new_timeout)); + LogDebug(BCLog::NET, "Increased stalling timeout temporarily to %d seconds\n", count_seconds(new_timeout)); } return true; } @@ -6293,23 +6314,26 @@ 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) { uint32_t nFetchFlags = GetFetchFlags(*peer); vGetData.emplace_back(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()); BlockRequested(pto->GetId(), *pindex); - LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), + LogDebug(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), pindex->nHeight, pto->GetId()); } if (state.vBlocksInFlight.empty() && staller != -1) { if (State(staller)->m_stalling_since == 0us) { State(staller)->m_stalling_since = current_time; - LogPrint(BCLog::NET, "Stall started peer=%d\n", staller); + LogDebug(BCLog::NET, "Stall started peer=%d\n", staller); } } } @@ -6317,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) { + LogDebug(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)) { + LogDebug(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 85e399d948..0d2dc59c5a 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -7,6 +7,7 @@ #define BITCOIN_NET_PROCESSING_H #include <net.h> +#include <txorphanage.h> #include <validationinterface.h> #include <chrono> @@ -16,6 +17,10 @@ class CChainParams; class CTxMemPool; class ChainstateManager; +namespace node { +class Warnings; +} // namespace node + /** Whether transaction reconciliation protocol should be enabled by default. */ static constexpr bool DEFAULT_TXRECONCILIATION_ENABLE{false}; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ @@ -25,10 +30,11 @@ static const uint32_t DEFAULT_MAX_ORPHAN_TRANSACTIONS{100}; static const uint32_t DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN{100}; static const bool DEFAULT_PEERBLOOMFILTERS = false; static const bool DEFAULT_PEERBLOCKFILTERS = false; -/** Threshold for marking a node to be discouraged, e.g. disconnected and added to the discouragement filter. */ -static const int DISCOURAGEMENT_THRESHOLD{100}; /** Maximum number of outstanding CMPCTBLOCK requests for the same block. */ static const unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK = 3; +/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends + * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ +static const unsigned int MAX_HEADERS_RESULTS = 2000; struct CNodeStateStats { int nSyncHeight = -1; @@ -69,12 +75,15 @@ public: //! Whether or not the internal RNG behaves deterministically (this is //! a test-only option). bool deterministic_rng{false}; + //! Number of headers sent in one getheaders message result (this is + //! a test-only option). + uint32_t max_headers_result{MAX_HEADERS_RESULTS}; }; static std::unique_ptr<PeerManager> make(CConnman& connman, AddrMan& addrman, BanMan* banman, ChainstateManager& chainman, - CTxMemPool& pool, Options opts); - virtual ~PeerManager() { } + CTxMemPool& pool, node::Warnings& warnings, Options opts); + virtual ~PeerManager() = default; /** * Attempt to manually fetch block from a given peer. We must already have the header. @@ -91,6 +100,8 @@ public: /** Get statistics from node state */ virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const = 0; + virtual std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() = 0; + /** Get peer manager info. */ virtual PeerManagerInfo GetInfo() const = 0; @@ -104,7 +115,7 @@ public: virtual void SetBestBlock(int height, std::chrono::seconds time) = 0; /* Public for unit testing. */ - virtual void UnitTestMisbehaving(NodeId peer_id, int howmuch) = 0; + virtual void UnitTestMisbehaving(NodeId peer_id) = 0; /** * Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound. 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.cpp b/src/netaddress.cpp index 74ab6dd8d8..bd2353a712 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -20,6 +20,9 @@ #include <iterator> #include <tuple> +using util::ContainsNoNUL; +using util::HasPrefix; + CNetAddr::BIP155Network CNetAddr::GetBIP155Network() const { switch (m_net) { @@ -242,14 +245,14 @@ bool CNetAddr::SetTor(const std::string& addr) Span<const uint8_t> input_checksum{input->data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN}; Span<const uint8_t> input_version{input->data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)}; - if (input_version != torv3::VERSION) { + if (!std::ranges::equal(input_version, torv3::VERSION)) { return false; } uint8_t calculated_checksum[torv3::CHECKSUM_LEN]; torv3::Checksum(input_pubkey, calculated_checksum); - if (input_checksum != calculated_checksum) { + if (!std::ranges::equal(input_checksum, calculated_checksum)) { return false; } diff --git a/src/netaddress.h b/src/netaddress.h index ea2d14336e..24f5c3fb96 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -448,7 +448,7 @@ private: // Recognize NET_INTERNAL embedded in IPv6, such addresses are not // gossiped but could be coming from addrman, when unserializing from // disk. - if (HasPrefix(m_addr, INTERNAL_IN_IPV6_PREFIX)) { + if (util::HasPrefix(m_addr, INTERNAL_IN_IPV6_PREFIX)) { m_net = NET_INTERNAL; memmove(m_addr.data(), m_addr.data() + INTERNAL_IN_IPV6_PREFIX.size(), ADDR_INTERNAL_SIZE); @@ -456,8 +456,8 @@ private: return; } - if (!HasPrefix(m_addr, IPV4_IN_IPV6_PREFIX) && - !HasPrefix(m_addr, TORV2_IN_IPV6_PREFIX)) { + if (!util::HasPrefix(m_addr, IPV4_IN_IPV6_PREFIX) && + !util::HasPrefix(m_addr, TORV2_IN_IPV6_PREFIX)) { return; } @@ -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 22326b0e98..eaca5a16c1 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <netbase.h> @@ -23,10 +23,12 @@ #include <limits> #include <memory> -#if HAVE_SOCKADDR_UN +#ifdef HAVE_SOCKADDR_UN #include <sys/un.h> #endif +using util::ContainsNoNUL; + // Settings static GlobalMutex g_proxyinfo_mutex; static Proxy proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex); @@ -227,8 +229,8 @@ CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupF bool IsUnixSocketPath(const std::string& name) { -#if HAVE_SOCKADDR_UN - if (name.find(ADDR_PREFIX_UNIX) != 0) return false; +#ifdef HAVE_SOCKADDR_UN + if (!name.starts_with(ADDR_PREFIX_UNIX)) return false; // Split off "unix:" prefix std::string str{name.substr(ADDR_PREFIX_UNIX.length())}; @@ -371,7 +373,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a { try { IntrRecvError recvr; - LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest); + LogDebug(BCLog::NET, "SOCKS5 connecting %s\n", strDest); if (strDest.size() > 255) { LogError("Hostname too long\n"); return false; @@ -410,7 +412,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a vAuth.push_back(auth->password.size()); vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); sock.SendComplete(vAuth, g_socks5_recv_timeout, g_socks5_interrupt); - LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); + LogDebug(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); uint8_t pchRetA[2]; if (InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { LogError("Error reading proxy authentication response\n"); @@ -454,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 @@ -488,7 +491,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a LogError("Error reading from proxy\n"); return false; } - LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest); + LogDebug(BCLog::NET, "SOCKS5 connected %s\n", strDest); return true; } catch (const std::runtime_error& e) { LogError("Error during SOCKS5 proxy handshake: %s\n", e.what()); @@ -496,24 +499,23 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a } } -std::unique_ptr<Sock> CreateSockOS(sa_family_t address_family) +std::unique_ptr<Sock> CreateSockOS(int domain, int type, int protocol) { // Not IPv4, IPv6 or UNIX - if (address_family == AF_UNSPEC) return nullptr; - - int protocol{IPPROTO_TCP}; -#if HAVE_SOCKADDR_UN - if (address_family == AF_UNIX) protocol = 0; -#endif + if (domain == AF_UNSPEC) return nullptr; // Create a socket in the specified address family. - SOCKET hSocket = socket(address_family, SOCK_STREAM, protocol); + SOCKET hSocket = socket(domain, type, protocol); if (hSocket == INVALID_SOCKET) { return nullptr; } auto sock = std::make_unique<Sock>(hSocket); + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNIX) { + return sock; + } + // Ensure that waiting for I/O on this socket won't result in undefined // behavior. if (!sock->IsSelectable()) { @@ -537,27 +539,31 @@ std::unique_ptr<Sock> CreateSockOS(sa_family_t address_family) return nullptr; } -#if HAVE_SOCKADDR_UN - if (address_family == AF_UNIX) return sock; +#ifdef HAVE_SOCKADDR_UN + if (domain == AF_UNIX) return sock; #endif - // Set the no-delay option (disable Nagle's algorithm) on the TCP socket. - const int on{1}; - if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { - LogPrint(BCLog::NET, "Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n"); + if (protocol == IPPROTO_TCP) { + // Set the no-delay option (disable Nagle's algorithm) on the TCP socket. + const int on{1}; + if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { + LogDebug(BCLog::NET, "Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n"); + } } + return sock; } -std::function<std::unique_ptr<Sock>(const sa_family_t&)> CreateSock = CreateSockOS; +std::function<std::unique_ptr<Sock>(int, int, int)> CreateSock = CreateSockOS; template<typename... Args> -static void LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args) { +static void LogConnectFailure(bool manual_connection, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) +{ std::string error_message = tfm::format(fmt, args...); if (manual_connection) { LogPrintf("%s\n", error_message); } else { - LogPrint(BCLog::NET, "%s\n", error_message); + LogDebug(BCLog::NET, "%s\n", error_message); } } @@ -580,7 +586,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; } @@ -618,7 +624,7 @@ static bool ConnectToSocket(const Sock& sock, struct sockaddr* sockaddr, socklen std::unique_ptr<Sock> ConnectDirectly(const CService& dest, bool manual_connection) { - auto sock = CreateSock(dest.GetSAFamily()); + auto sock = CreateSock(dest.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP); if (!sock) { LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Cannot create a socket for connecting to %s\n", dest.ToStringAddrPort()); return {}; @@ -645,8 +651,8 @@ std::unique_ptr<Sock> Proxy::Connect() const if (!m_is_unix_socket) return ConnectDirectly(proxy, /*manual_connection=*/true); -#if HAVE_SOCKADDR_UN - auto sock = CreateSock(AF_UNIX); +#ifdef HAVE_SOCKADDR_UN + auto sock = CreateSock(AF_UNIX, SOCK_STREAM, 0); if (!sock) { LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Cannot create a socket for connecting to %s\n", m_unix_socket_path); return {}; diff --git a/src/netbase.h b/src/netbase.h index 321c288f67..bf4d7ececc 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -134,6 +134,13 @@ public: return Contains(addr.GetNetwork()); } + [[nodiscard]] std::unordered_set<Network> All() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + { + AssertLockNotHeld(m_mutex); + LOCK(m_mutex); + return m_reachable; + } + private: mutable Mutex m_mutex; @@ -262,16 +269,18 @@ CService LookupNumeric(const std::string& name, uint16_t portDefault = 0, DNSLoo CSubNet LookupSubNet(const std::string& subnet_str); /** - * Create a TCP or UNIX socket in the given address family. - * @param[in] address_family to use for the socket. + * Create a real socket from the operating system. + * @param[in] domain Communications domain, first argument to the socket(2) syscall. + * @param[in] type Type of the socket, second argument to the socket(2) syscall. + * @param[in] protocol The particular protocol to be used with the socket, third argument to the socket(2) syscall. * @return pointer to the created Sock object or unique_ptr that owns nothing in case of failure */ -std::unique_ptr<Sock> CreateSockOS(sa_family_t address_family); +std::unique_ptr<Sock> CreateSockOS(int domain, int type, int protocol); /** * Socket factory. Defaults to `CreateSockOS()`, but can be overridden by unit tests. */ -extern std::function<std::unique_ptr<Sock>(const sa_family_t&)> CreateSock; +extern std::function<std::unique_ptr<Sock>(int, int, int)> CreateSock; /** * Create a socket and try to connect to the specified service. diff --git a/src/node/abort.cpp b/src/node/abort.cpp index b727608384..c15bf047c8 100644 --- a/src/node/abort.cpp +++ b/src/node/abort.cpp @@ -6,22 +6,21 @@ #include <logging.h> #include <node/interface_ui.h> +#include <node/warnings.h> #include <util/signalinterrupt.h> #include <util/translation.h> -#include <warnings.h> #include <atomic> #include <cstdlib> -#include <string> namespace node { -void AbortNode(util::SignalInterrupt* shutdown, std::atomic<int>& exit_status, const bilingual_str& message) +void AbortNode(const std::function<bool()>& shutdown_request, std::atomic<int>& exit_status, const bilingual_str& message, node::Warnings* warnings) { - SetMiscWarning(message); + if (warnings) warnings->Set(Warning::FATAL_INTERNAL_ERROR, message); InitError(_("A fatal internal error occurred, see debug.log for details: ") + message); exit_status.store(EXIT_FAILURE); - if (shutdown && !(*shutdown)()) { + if (shutdown_request && !shutdown_request()) { LogError("Failed to send shutdown signal\n"); }; } diff --git a/src/node/abort.h b/src/node/abort.h index 1092279142..c8514628bc 100644 --- a/src/node/abort.h +++ b/src/node/abort.h @@ -6,15 +6,13 @@ #define BITCOIN_NODE_ABORT_H #include <atomic> +#include <functional> struct bilingual_str; -namespace util { -class SignalInterrupt; -} // namespace util - namespace node { -void AbortNode(util::SignalInterrupt* shutdown, std::atomic<int>& exit_status, const bilingual_str& message); +class Warnings; +void AbortNode(const std::function<bool()>& shutdown_request, std::atomic<int>& exit_status, const bilingual_str& message, node::Warnings* warnings); } // namespace node #endif // BITCOIN_NODE_ABORT_H diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp index dd8419a68a..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) { @@ -33,8 +34,6 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Op if (auto value{args.GetBoolArg("-fastprune")}) opts.fast_prune = *value; - if (auto value{args.GetBoolArg("-reindex")}) opts.reindex = *value; - return {}; } } // namespace node diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 4067ccee51..07878a5602 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 { @@ -366,7 +367,7 @@ void BlockManager::FindFilesToPrune( } } - LogPrint(BCLog::PRUNE, "[%s] target=%dMiB actual=%dMiB diff=%dMiB min_height=%d max_prune_height=%d removed %d blk/rev pairs\n", + LogDebug(BCLog::PRUNE, "[%s] target=%dMiB actual=%dMiB diff=%dMiB min_height=%d max_prune_height=%d removed %d blk/rev pairs\n", chain.GetRole(), target / 1024 / 1024, nCurrentUsage / 1024 / 1024, (int64_t(target) - int64_t(nCurrentUsage)) / 1024 / 1024, min_block_to_prune, last_block_can_prune, count); @@ -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)) { @@ -551,7 +552,7 @@ bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_block // Check whether we need to continue reindexing bool fReindexing = false; m_block_tree_db->ReadReindexing(fReindexing); - if (fReindexing) m_reindexing = true; + if (fReindexing) m_blockfiles_indexed = false; return true; } @@ -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 @@ -682,11 +683,7 @@ bool BlockManager::UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos fileout << GetParams().MessageStart() << nSize; // Write undo data - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) { - LogError("%s: ftell failed\n", __func__); - return false; - } + long fileOutPos = fileout.tell(); pos.nPos = (unsigned int)fileOutPos; fileout << blockundo; @@ -703,15 +700,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 +715,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 +731,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 +753,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 +805,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); + LogDebug(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) @@ -858,7 +840,7 @@ FlatFilePos BlockManager::FindNextBlockPos(unsigned int nAddSize, unsigned int n assert(chain_type == BlockfileType::ASSUMED); const auto new_cursor = BlockfileCursor{this->MaxBlockfileNum() + 1}; m_blockfile_cursors[chain_type] = new_cursor; - LogPrint(BCLog::BLOCKSTORAGE, "[%s] initializing blockfile cursor to %s\n", chain_type, new_cursor); + LogDebug(BCLog::BLOCKSTORAGE, "[%s] initializing blockfile cursor to %s\n", chain_type, new_cursor); } const int last_blockfile = m_blockfile_cursors[chain_type]->file_num; @@ -901,7 +883,7 @@ FlatFilePos BlockManager::FindNextBlockPos(unsigned int nAddSize, unsigned int n pos.nPos = m_blockfile_info[nFile].nSize; if (nFile != last_blockfile) { - LogPrint(BCLog::BLOCKSTORAGE, "Leaving block file %i: %s (onto %i) (height %i)\n", + LogDebug(BCLog::BLOCKSTORAGE, "Leaving block file %i: %s (onto %i) (height %i)\n", last_blockfile, m_blockfile_info[last_blockfile].ToString(), nFile, nHeight); // Do not propagate the return code. The flush concerns a previous block @@ -924,7 +906,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 +952,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 +968,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; } @@ -995,11 +977,7 @@ bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const fileout << GetParams().MessageStart() << nSize; // Write block - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) { - LogError("WriteBlockToDisk: ftell failed\n"); - return false; - } + long fileOutPos = fileout.tell(); pos.nPos = (unsigned int)fileOutPos; fileout << TX_WITH_WITNESS(block); @@ -1016,7 +994,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 +1033,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 +1047,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 +1068,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 +1137,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; @@ -1177,12 +1202,12 @@ public: } }; -void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFiles) +void ImportBlocks(ChainstateManager& chainman, std::span<const fs::path> import_paths) { ImportingNow imp{chainman.m_blockman.m_importing}; // -reindex - if (chainman.m_blockman.m_reindexing) { + if (!chainman.m_blockman.m_blockfiles_indexed) { int nFile = 0; // Map of disk positions for blocks with unknown parent (only used for reindex); // parent hash -> child disk position, multiple children can have the same parent. @@ -1205,14 +1230,14 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile nFile++; } WITH_LOCK(::cs_main, chainman.m_blockman.m_block_tree_db->WriteReindexing(false)); - chainman.m_blockman.m_reindexing = false; + chainman.m_blockman.m_blockfiles_indexed = true; LogPrintf("Reindexing finished\n"); // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): chainman.ActiveChainstate().LoadGenesisBlock(); } // -loadblock= - for (const fs::path& path : vImportFiles) { + for (const fs::path& path : import_paths) { AutoFile file{fsbridge::fopen(path, "rb")}; if (!file.IsNull()) { LogPrintf("Importing blocks file %s...\n", fs::PathToString(path)); diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index a501067091..03bc5f4600 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -29,6 +29,7 @@ #include <memory> #include <optional> #include <set> +#include <span> #include <string> #include <unordered_map> #include <utility> @@ -166,9 +167,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 +241,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,24 +261,24 @@ 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}, - m_reindexing{m_opts.reindex} {}; + explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts); const util::SignalInterrupt& m_interrupt; std::atomic<bool> m_importing{false}; /** - * Tracks if a reindex is currently in progress. Set to true when a reindex - * is requested and false when reindexing completes. Its value is persisted - * in the BlockTreeDB across restarts. + * Whether all blockfiles have been added to the block tree database. + * Normally true, but set to false when a reindex is requested and the + * database is wiped. The value is persisted in the database across restarts + * and will be false until reindexing completes. */ - std::atomic_bool m_reindexing; + std::atomic_bool m_blockfiles_indexed{true}; BlockMap m_block_index GUARDED_BY(cs_main); @@ -359,7 +359,7 @@ public: [[nodiscard]] uint64_t GetPruneTarget() const { return m_opts.prune_target; } static constexpr auto PRUNE_TARGET_MANUAL{std::numeric_limits<uint64_t>::max()}; - [[nodiscard]] bool LoadingBlocks() const { return m_importing || m_reindexing; } + [[nodiscard]] bool LoadingBlocks() const { return m_importing || !m_blockfiles_indexed; } /** Calculate the amount of disk space the block & undo files currently use */ uint64_t CalculateCurrentUsage(); @@ -372,16 +372,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); @@ -407,7 +430,7 @@ public: void CleanupBlockRevFiles() const; }; -void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFiles); +void ImportBlocks(ChainstateManager& chainman, std::span<const fs::path> import_paths); } // namespace node #endif // BITCOIN_NODE_BLOCKSTORAGE_H diff --git a/src/node/caches.cpp b/src/node/caches.cpp index 7403f7ddea..dc4d98f592 100644 --- a/src/node/caches.cpp +++ b/src/node/caches.cpp @@ -13,7 +13,6 @@ CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes) { int64_t nTotalCache = (args.GetIntArg("-dbcache", nDefaultDbCache) << 20); nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache - nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache CacheSizes sizes; sizes.block_tree_db = std::min(nTotalCache / 8, nMaxBlockDBCache << 20); nTotalCache -= sizes.block_tree_db; diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index d6eb14f513..d7e6176be1 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -45,11 +45,12 @@ static ChainstateLoadResult CompleteChainstateInitialization( .path = chainman.m_options.datadir / "blocks" / "index", .cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db), .memory_only = options.block_tree_db_in_memory, - .wipe_data = options.reindex, + .wipe_data = options.wipe_block_tree_db, .options = chainman.m_options.block_tree_db}); - if (options.reindex) { + if (options.wipe_block_tree_db) { pblocktree->WriteReindexing(true); + chainman.m_blockman.m_blockfiles_indexed = false; //If we're reindexing in prune mode, wipe away unusable block files and all undo data files if (options.prune) { chainman.m_blockman.CleanupBlockRevFiles(); @@ -60,8 +61,7 @@ static ChainstateLoadResult CompleteChainstateInitialization( // LoadBlockIndex will load m_have_pruned if we've ever removed a // block file from disk. - // Note that it also sets m_reindexing based on the disk flag! - // From here on, m_reindexing and options.reindex values may be different! + // Note that it also sets m_blockfiles_indexed based on the disk flag! if (!chainman.LoadBlockIndex()) { if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}}; return {ChainstateLoadStatus::FAILURE, _("Error loading block database")}; @@ -84,12 +84,12 @@ static ChainstateLoadResult CompleteChainstateInitialization( // If we're not mid-reindex (based on disk + args), add a genesis block on disk // (otherwise we use the one already on disk). // This is called again in ImportBlocks after the reindex completes. - if (!chainman.m_blockman.m_reindexing && !chainman.ActiveChainstate().LoadGenesisBlock()) { + if (chainman.m_blockman.m_blockfiles_indexed && !chainman.ActiveChainstate().LoadGenesisBlock()) { return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")}; } auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { - return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull(); + return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull(); }; assert(chainman.m_total_coinstip_cache > 0); @@ -110,7 +110,7 @@ static ChainstateLoadResult CompleteChainstateInitialization( chainstate->InitCoinsDB( /*cache_size_bytes=*/chainman.m_total_coinsdb_cache * init_cache_fraction, /*in_memory=*/options.coins_db_in_memory, - /*should_wipe=*/options.reindex || options.reindex_chainstate); + /*should_wipe=*/options.wipe_chainstate_db); if (options.coins_error_cb) { chainstate->CoinsErrorCatcher().AddReadErrCallback(options.coins_error_cb); @@ -142,7 +142,7 @@ static ChainstateLoadResult CompleteChainstateInitialization( } } - if (!options.reindex) { + if (!options.wipe_block_tree_db) { auto chainstates{chainman.GetAll()}; if (std::any_of(chainstates.begin(), chainstates.end(), [](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) { @@ -188,7 +188,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize // Load a chain created from a UTXO snapshot, if any exist. bool has_snapshot = chainman.DetectSnapshotChainstate(); - if (has_snapshot && (options.reindex || options.reindex_chainstate)) { + if (has_snapshot && options.wipe_chainstate_db) { LogPrintf("[snapshot] deleting snapshot chainstate due to reindexing\n"); if (!chainman.DeleteSnapshotChainstate()) { return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Couldn't remove snapshot chainstate.")}; @@ -247,7 +247,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options) { auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { - return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull(); + return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull(); }; LOCK(cs_main); diff --git a/src/node/chainstate.h b/src/node/chainstate.h index a6e9a0331b..bb0c4f2b87 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -22,8 +22,13 @@ struct ChainstateLoadOptions { CTxMemPool* mempool{nullptr}; bool block_tree_db_in_memory{false}; bool coins_db_in_memory{false}; - bool reindex{false}; - bool reindex_chainstate{false}; + // Whether to wipe the block tree database when loading it. If set, this + // will also set a reindexing flag so any existing block data files will be + // scanned and added to the database. + bool wipe_block_tree_db{false}; + // Whether to wipe the chainstate database when loading it. If set, this + // will cause the chainstate database to be rebuilt starting from genesis. + bool wipe_chainstate_db{false}; bool prune{false}; //! Setting require_full_verification to true will require all checks at //! check_level (below) to succeed for loading to succeed. Setting it to diff --git a/src/node/chainstatemanager_args.cpp b/src/node/chainstatemanager_args.cpp index 1cc126cb05..b86d0b2991 100644 --- a/src/node/chainstatemanager_args.cpp +++ b/src/node/chainstatemanager_args.cpp @@ -24,18 +24,28 @@ namespace node { util::Result<void> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts) { - if (auto value{args.GetBoolArg("-checkblockindex")}) opts.check_block_index = *value; + if (auto value{args.GetIntArg("-checkblockindex")}) { + // Interpret bare -checkblockindex argument as 1 instead of 0. + opts.check_block_index = args.GetArg("-checkblockindex")->empty() ? 1 : *value; + } if (auto value{args.GetBoolArg("-checkpoints")}) opts.checkpoints_enabled = *value; if (auto value{args.GetArg("-minimumchainwork")}) { - if (!IsHexNumber(*value)) { - return util::Error{strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), *value)}; + if (auto min_work{uint256::FromUserHex(*value)}) { + opts.minimum_chain_work = UintToArith256(*min_work); + } else { + return util::Error{strprintf(Untranslated("Invalid minimum work specified (%s), must be up to %d hex digits"), *value, uint256::size() * 2)}; } - opts.minimum_chain_work = UintToArith256(uint256S(*value)); } - if (auto value{args.GetArg("-assumevalid")}) opts.assumed_valid_block = uint256S(*value); + if (auto value{args.GetArg("-assumevalid")}) { + if (auto block_hash{uint256::FromUserHex(*value)}) { + opts.assumed_valid_block = *block_hash; + } else { + return util::Error{strprintf(Untranslated("Invalid assumevalid block hash specified (%s), must be up to %d hex digits (or 0 to disable)"), *value, uint256::size() * 2)}; + } + } if (auto value{args.GetIntArg("-maxtipage")}) opts.max_tip_age = std::chrono::seconds{*value}; @@ -53,6 +63,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/context.cpp b/src/node/context.cpp index e32d21b383..75dfaee866 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -7,12 +7,14 @@ #include <addrman.h> #include <banman.h> #include <interfaces/chain.h> +#include <interfaces/mining.h> #include <kernel/context.h> #include <key.h> #include <net.h> #include <net_processing.h> #include <netgroup.h> #include <node/kernel_notifications.h> +#include <node/warnings.h> #include <policy/fees.h> #include <scheduler.h> #include <txmempool.h> diff --git a/src/node/context.h b/src/node/context.h index a7d92989dd..debc122120 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -9,6 +9,7 @@ #include <cstdlib> #include <functional> #include <memory> +#include <thread> #include <vector> class ArgsManager; @@ -27,6 +28,7 @@ class PeerManager; namespace interfaces { class Chain; class ChainClient; +class Mining; class Init; class WalletLoader; } // namespace interfaces @@ -39,6 +41,7 @@ class SignalInterrupt; namespace node { class KernelNotifications; +class Warnings; //! NodeContext struct containing references to chain state and connection //! state. @@ -56,8 +59,10 @@ struct NodeContext { std::unique_ptr<ECC_Context> ecc_context; //! Init interface for initializing current process and connecting to other processes. interfaces::Init* init{nullptr}; + //! Function to request a shutdown. + std::function<bool()> shutdown_request; //! Interrupt object used to track whether node shutdown was requested. - util::SignalInterrupt* shutdown{nullptr}; + util::SignalInterrupt* shutdown_signal{nullptr}; std::unique_ptr<AddrMan> addrman; std::unique_ptr<CConnman> connman; std::unique_ptr<CTxMemPool> mempool; @@ -73,6 +78,7 @@ struct NodeContext { std::vector<std::unique_ptr<interfaces::ChainClient>> chain_clients; //! Reference to chain client that should used to load or create wallets //! opened by the gui. + std::unique_ptr<interfaces::Mining> mining; interfaces::WalletLoader* wallet_loader{nullptr}; std::unique_ptr<CScheduler> scheduler; std::function<void()> rpc_interruption_point = [] {}; @@ -81,6 +87,9 @@ struct NodeContext { //! Issues calls about blocks and transactions std::unique_ptr<ValidationSignals> validation_signals; std::atomic<int> exit_status{EXIT_SUCCESS}; + //! Manages all the node warnings + std::unique_ptr<node::Warnings> warnings; + std::thread background_init_thread; //! Declare default constructor and destructor that are not inline, so code //! instantiating the NodeContext struct doesn't need to #include class diff --git a/src/node/interface_ui.cpp b/src/node/interface_ui.cpp index 9dd1e7d9cf..4f4d240d1b 100644 --- a/src/node/interface_ui.cpp +++ b/src/node/interface_ui.cpp @@ -10,6 +10,8 @@ #include <boost/signals2/optional_last_value.hpp> #include <boost/signals2/signal.hpp> +using util::MakeUnorderedList; + CClientUIInterface uiInterface; struct UISignals { 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 216f44ab9e..0010c104a8 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -8,13 +8,17 @@ #include <chain.h> #include <chainparams.h> #include <common/args.h> +#include <consensus/merkle.h> +#include <consensus/validation.h> #include <deploymentstatus.h> #include <external_signer.h> #include <index/blockfilterindex.h> #include <init.h> #include <interfaces/chain.h> #include <interfaces/handler.h> +#include <interfaces/mining.h> #include <interfaces/node.h> +#include <interfaces/types.h> #include <interfaces/wallet.h> #include <kernel/chain.h> #include <kernel/context.h> @@ -30,7 +34,11 @@ #include <node/context.h> #include <node/interface_ui.h> #include <node/mini_miner.h> +#include <node/miner.h> +#include <node/kernel_notifications.h> #include <node/transaction.h> +#include <node/types.h> +#include <node/warnings.h> #include <policy/feerate.h> #include <policy/fees.h> #include <policy/policy.h> @@ -52,9 +60,8 @@ #include <util/translation.h> #include <validation.h> #include <validationinterface.h> -#include <warnings.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <any> #include <memory> @@ -63,13 +70,18 @@ #include <boost/signals2/signal.hpp> +using interfaces::BlockRef; +using interfaces::BlockTemplate; using interfaces::BlockTip; using interfaces::Chain; using interfaces::FoundBlock; using interfaces::Handler; using interfaces::MakeSignalHandler; +using interfaces::Mining; using interfaces::Node; using interfaces::WalletLoader; +using node::BlockAssembler; +using util::Join; namespace node { // All members of the classes in this namespace are intentionally public, as the @@ -91,14 +103,15 @@ public: explicit NodeImpl(NodeContext& context) { setContext(&context); } void initLogging() override { InitLogging(args()); } void initParameterInteraction() override { InitParameterInteraction(args()); } - bilingual_str getWarnings() override { return Join(GetWarnings(), Untranslated("<hr />")); } + bilingual_str getWarnings() override { return Join(Assert(m_context->warnings)->GetMessages(), Untranslated("<hr />")); } int getExitStatus() override { return Assert(m_context)->exit_status.load(); } - uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); } + BCLog::CategoryMask getLogCategories() override { return LogInstance().GetCategoryMask(); } bool baseInitialize() override { if (!AppInitBasicSetup(args(), Assert(context())->exit_status)) return false; if (!AppInitParameterInteraction(args())) return false; + m_context->warnings = std::make_unique<node::Warnings>(); m_context->kernel = std::make_unique<kernel::Context>(); m_context->ecc_context = std::make_unique<ECC_Context>(); if (!AppInitSanityChecks(*m_context->kernel)) return false; @@ -122,9 +135,11 @@ public: } void startShutdown() override { - if (!(*Assert(Assert(m_context)->shutdown))()) { - LogPrintf("Error: failed to send shutdown signal\n"); + NodeContext& ctx{*Assert(m_context)}; + if (!(Assert(ctx.shutdown_request))()) { + LogError("Failed to send shutdown signal\n"); } + // Stop RPC for clean shutdown if any of waitfor* commands is executed. if (args().GetBoolArg("-server", false)) { InterruptRPC(); @@ -172,7 +187,7 @@ public: }); args().WriteSettingsFile(); } - void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); } + void mapPort(bool use_upnp, bool use_pcp) override { StartMapPort(use_upnp, use_pcp); } bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); } size_t getNodeCount(ConnectionDirection flags) override { @@ -270,6 +285,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); @@ -281,6 +297,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); @@ -798,16 +821,34 @@ public: }); return result; } - bool updateRwSetting(const std::string& name, const common::SettingsValue& value, bool write) override + bool updateRwSetting(const std::string& name, + const interfaces::SettingsUpdate& update_settings_func) override { + std::optional<interfaces::SettingsAction> action; args().LockSettings([&](common::Settings& settings) { - if (value.isNull()) { - settings.rw_settings.erase(name); + if (auto* value = common::FindKey(settings.rw_settings, name)) { + action = update_settings_func(*value); + if (value->isNull()) settings.rw_settings.erase(name); } else { - settings.rw_settings[name] = value; + UniValue new_value; + action = update_settings_func(new_value); + if (!new_value.isNull()) settings.rw_settings[name] = std::move(new_value); } }); - return !write || args().WriteSettingsFile(); + if (!action) return false; + // Now dump value to disk if requested + return *action != interfaces::SettingsAction::WRITE || args().WriteSettingsFile(); + } + bool overwriteRwSetting(const std::string& name, common::SettingsValue value, interfaces::SettingsAction action) override + { + return updateRwSetting(name, [&](common::SettingsValue& settings) { + settings = std::move(value); + return action; + }); + } + bool deleteRwSettings(const std::string& name, interfaces::SettingsAction action) override + { + return overwriteRwSetting(name, {}, action); } void requestMempoolTransactions(Notifications& notifications) override { @@ -828,10 +869,160 @@ public: ValidationSignals& validation_signals() { return *Assert(m_node.validation_signals); } NodeContext& m_node; }; + +class BlockTemplateImpl : public BlockTemplate +{ +public: + explicit BlockTemplateImpl(std::unique_ptr<CBlockTemplate> block_template, NodeContext& node) : m_block_template(std::move(block_template)), m_node(node) + { + assert(m_block_template); + } + + CBlockHeader getBlockHeader() override + { + return m_block_template->block; + } + + CBlock getBlock() override + { + return m_block_template->block; + } + + std::vector<CAmount> getTxFees() override + { + return m_block_template->vTxFees; + } + + std::vector<int64_t> getTxSigops() override + { + return m_block_template->vTxSigOpsCost; + } + + CTransactionRef getCoinbaseTx() override + { + return m_block_template->block.vtx[0]; + } + + std::vector<unsigned char> getCoinbaseCommitment() override + { + return m_block_template->vchCoinbaseCommitment; + } + + int getWitnessCommitmentIndex() override + { + return GetWitnessCommitmentIndex(m_block_template->block); + } + + std::vector<uint256> getCoinbaseMerklePath() override + { + return BlockMerkleBranch(m_block_template->block); + } + + bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CMutableTransaction coinbase) override + { + CBlock block{m_block_template->block}; + + auto cb = MakeTransactionRef(std::move(coinbase)); + + if (block.vtx.size() == 0) { + block.vtx.push_back(cb); + } else { + block.vtx[0] = cb; + } + + block.nVersion = version; + block.nTime = timestamp; + block.nNonce = nonce; + + block.hashMerkleRoot = BlockMerkleRoot(block); + + auto block_ptr = std::make_shared<const CBlock>(block); + return chainman().ProcessNewBlock(block_ptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/nullptr); + } + + const std::unique_ptr<CBlockTemplate> m_block_template; + + ChainstateManager& chainman() { return *Assert(m_node.chainman); } + NodeContext& m_node; +}; + +class MinerImpl : public Mining +{ +public: + explicit MinerImpl(NodeContext& node) : m_node(node) {} + + bool isTestChain() override + { + return chainman().GetParams().IsTestChain(); + } + + bool isInitialBlockDownload() override + { + return chainman().IsInitialBlockDownload(); + } + + std::optional<BlockRef> getTip() override + { + LOCK(::cs_main); + CBlockIndex* tip{chainman().ActiveChain().Tip()}; + if (!tip) return {}; + return BlockRef{tip->GetBlockHash(), tip->nHeight}; + } + + BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override + { + if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono + { + WAIT_LOCK(notifications().m_tip_block_mutex, lock); + notifications().m_tip_block_cv.wait_for(lock, timeout, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) { + return (notifications().m_tip_block != current_tip && notifications().m_tip_block != uint256::ZERO) || chainman().m_interrupt; + }); + } + // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks. + LOCK(::cs_main); + return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight}; + } + + bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override + { + return chainman().ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/new_block); + } + + unsigned int getTransactionsUpdated() override + { + return context()->mempool->GetTransactionsUpdated(); + } + + bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override + { + LOCK(cs_main); + CBlockIndex* tip{chainman().ActiveChain().Tip()}; + // Fail if the tip updated before the lock was taken + if (block.hashPrevBlock != tip->GetBlockHash()) { + state.Error("Block does not connect to current chain tip."); + return false; + } + + return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root); + } + + std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override + { + BlockAssembler::Options assemble_options{options}; + ApplyArgsManOptions(*Assert(m_node.args), assemble_options); + return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key), m_node); + } + + NodeContext* context() override { return &m_node; } + ChainstateManager& chainman() { return *Assert(m_node.chainman); } + KernelNotifications& notifications() { return *Assert(m_node.notifications); } + NodeContext& m_node; +}; } // namespace } // namespace node namespace interfaces { std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); } std::unique_ptr<Chain> MakeChain(node::NodeContext& context) { return std::make_unique<node::ChainImpl>(context); } +std::unique_ptr<Mining> MakeMining(node::NodeContext& context) { return std::make_unique<node::MinerImpl>(context); } } // namespace interfaces diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp index e326d4a1f2..a09803165c 100644 --- a/src/node/kernel_notifications.cpp +++ b/src/node/kernel_notifications.cpp @@ -4,29 +4,31 @@ #include <node/kernel_notifications.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <chain.h> #include <common/args.h> #include <common/system.h> #include <kernel/context.h> +#include <kernel/warning.h> #include <logging.h> #include <node/abort.h> #include <node/interface_ui.h> +#include <node/warnings.h> #include <util/check.h> #include <util/signalinterrupt.h> #include <util/strencodings.h> #include <util/string.h> #include <util/translation.h> -#include <warnings.h> #include <cstdint> #include <string> #include <thread> +using util::ReplaceAll; + static void AlertNotify(const std::string& strMessage) { - uiInterface.NotifyAlertChanged(); #if HAVE_SYSTEM std::string strCmd = gArgs.GetArg("-alertnotify", ""); if (strCmd.empty()) return; @@ -44,24 +46,20 @@ static void AlertNotify(const std::string& strMessage) #endif } -static void DoWarning(const bilingual_str& warning) -{ - static bool fWarned = false; - SetMiscWarning(warning); - if (!fWarned) { - AlertNotify(warning.original); - fWarned = true; - } -} - namespace node { kernel::InterruptResult KernelNotifications::blockTip(SynchronizationState state, CBlockIndex& index) { + { + LOCK(m_tip_block_mutex); + m_tip_block = index.GetBlockHash(); + m_tip_block_cv.notify_all(); + } + uiInterface.NotifyBlockTip(state, &index); if (m_stop_at_height && index.nHeight >= m_stop_at_height) { - if (!m_shutdown()) { - LogPrintf("Error: failed to send shutdown signal after reaching stop height\n"); + if (!m_shutdown_request()) { + LogError("Failed to send shutdown signal after reaching stop height\n"); } return kernel::Interrupted{}; } @@ -78,20 +76,27 @@ void KernelNotifications::progress(const bilingual_str& title, int progress_perc uiInterface.ShowProgress(title.translated, progress_percent, resume_possible); } -void KernelNotifications::warning(const bilingual_str& warning) +void KernelNotifications::warningSet(kernel::Warning id, const bilingual_str& message) +{ + if (m_warnings.Set(id, message)) { + AlertNotify(message.original); + } +} + +void KernelNotifications::warningUnset(kernel::Warning id) { - DoWarning(warning); + m_warnings.Unset(id); } void KernelNotifications::flushError(const bilingual_str& message) { - AbortNode(&m_shutdown, m_exit_status, message); + AbortNode(m_shutdown_request, m_exit_status, message, &m_warnings); } void KernelNotifications::fatalError(const bilingual_str& message) { - node::AbortNode(m_shutdown_on_fatal_error ? &m_shutdown : nullptr, - m_exit_status, message); + node::AbortNode(m_shutdown_on_fatal_error ? m_shutdown_request : nullptr, + m_exit_status, message, &m_warnings); } void ReadNotificationArgs(const ArgsManager& args, KernelNotifications& notifications) diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h index f4d97a0fff..296b9c426d 100644 --- a/src/node/kernel_notifications.h +++ b/src/node/kernel_notifications.h @@ -7,34 +7,43 @@ #include <kernel/notifications_interface.h> +#include <sync.h> +#include <threadsafety.h> +#include <uint256.h> + #include <atomic> #include <cstdint> +#include <functional> class ArgsManager; class CBlockIndex; enum class SynchronizationState; struct bilingual_str; -namespace util { -class SignalInterrupt; -} // namespace util +namespace kernel { +enum class Warning; +} // namespace kernel namespace node { +class Warnings; static constexpr int DEFAULT_STOPATHEIGHT{0}; class KernelNotifications : public kernel::Notifications { public: - KernelNotifications(util::SignalInterrupt& shutdown, std::atomic<int>& exit_status) : m_shutdown(shutdown), m_exit_status{exit_status} {} + KernelNotifications(const std::function<bool()>& shutdown_request, std::atomic<int>& exit_status, node::Warnings& warnings) + : m_shutdown_request(shutdown_request), m_exit_status{exit_status}, m_warnings{warnings} {} - [[nodiscard]] kernel::InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) override; + [[nodiscard]] kernel::InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) override EXCLUSIVE_LOCKS_REQUIRED(!m_tip_block_mutex); void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) override; void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override; - void warning(const bilingual_str& warning) override; + void warningSet(kernel::Warning id, const bilingual_str& message) override; + + void warningUnset(kernel::Warning id) override; void flushError(const bilingual_str& message) override; @@ -44,9 +53,18 @@ public: int m_stop_at_height{DEFAULT_STOPATHEIGHT}; //! Useful for tests, can be set to false to avoid shutdown on fatal error. bool m_shutdown_on_fatal_error{true}; + + Mutex m_tip_block_mutex; + std::condition_variable m_tip_block_cv GUARDED_BY(m_tip_block_mutex); + //! The block for which the last blockTip notification was received for. + //! The initial ZERO means that no block has been connected yet, which may + //! be true even long after startup, until shutdown. + uint256 m_tip_block GUARDED_BY(m_tip_block_mutex){uint256::ZERO}; + private: - util::SignalInterrupt& m_shutdown; + const std::function<bool()>& m_shutdown_request; std::atomic<int>& m_exit_status; + node::Warnings& m_warnings; }; void ReadNotificationArgs(const ArgsManager& args, KernelNotifications& notifications); diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index ac26600919..a488c1b149 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -8,19 +8,20 @@ #include <kernel/mempool_options.h> #include <common/args.h> +#include <common/messages.h> #include <consensus/amount.h> #include <kernel/chainparams.h> #include <logging.h> #include <policy/feerate.h> #include <policy/policy.h> #include <tinyformat.h> -#include <util/error.h> #include <util/moneystr.h> #include <util/translation.h> #include <chrono> #include <memory> +using common::AmountErrMsg; using kernel::MemPoolLimits; using kernel::MemPoolOptions; @@ -92,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/kernel/mempool_persist.cpp b/src/node/mempool_persist.cpp index 53028a45ae..ff7de8c64a 100644 --- a/src/kernel/mempool_persist.cpp +++ b/src/node/mempool_persist.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <kernel/mempool_persist.h> +#include <node/mempool_persist.h> #include <clientversion.h> #include <consensus/amount.h> @@ -33,7 +33,7 @@ using fsbridge::FopenFn; -namespace kernel { +namespace node { static const uint64_t MEMPOOL_DUMP_VERSION_NO_XOR_KEY{1}; static const uint64_t MEMPOOL_DUMP_VERSION{2}; @@ -199,8 +199,8 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock LogInfo("Writing %d unbroadcast transactions to file.\n", unbroadcast_txids.size()); file << unbroadcast_txids; - if (!skip_file_commit && !FileCommit(file.Get())) - throw std::runtime_error("FileCommit failed"); + if (!skip_file_commit && !file.Commit()) + throw std::runtime_error("Commit failed"); file.fclose(); if (!RenameOver(dump_path + ".new", dump_path)) { throw std::runtime_error("Rename failed"); @@ -218,4 +218,4 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock return true; } -} // namespace kernel +} // namespace node diff --git a/src/kernel/mempool_persist.h b/src/node/mempool_persist.h index e124a8eadf..7c5754a90c 100644 --- a/src/kernel/mempool_persist.h +++ b/src/node/mempool_persist.h @@ -2,15 +2,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_KERNEL_MEMPOOL_PERSIST_H -#define BITCOIN_KERNEL_MEMPOOL_PERSIST_H +#ifndef BITCOIN_NODE_MEMPOOL_PERSIST_H +#define BITCOIN_NODE_MEMPOOL_PERSIST_H #include <util/fs.h> class Chainstate; class CTxMemPool; -namespace kernel { +namespace node { /** Dump the mempool to a file. */ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, @@ -28,7 +28,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active_chainstate, ImportMempoolOptions&& opts); -} // namespace kernel +} // namespace node -#endif // BITCOIN_KERNEL_MEMPOOL_PERSIST_H +#endif // BITCOIN_NODE_MEMPOOL_PERSIST_H diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 87f40e993f..181ae2ef05 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -33,6 +33,14 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam int64_t nOldTime = pblock->nTime; int64_t nNewTime{std::max<int64_t>(pindexPrev->GetMedianTimePast() + 1, TicksSinceEpoch<std::chrono::seconds>(NodeClock::now()))}; + if (consensusParams.enforce_BIP94) { + // Height of block to be mined. + const int height{pindexPrev->nHeight + 1}; + if (height % consensusParams.DifficultyAdjustmentInterval() == 0) { + nNewTime = std::max<int64_t>(nNewTime, pindexPrev->GetBlockTime() - MAX_TIMEWARP); + } + } + if (nOldTime < nNewTime) { pblock->nTime = nNewTime; } @@ -59,14 +67,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)} { @@ -79,24 +90,16 @@ void ApplyArgsManOptions(const ArgsManager& args, BlockAssembler::Options& optio if (const auto blockmintxfee{args.GetArg("-blockmintxfee")}) { if (const auto parsed{ParseMoney(*blockmintxfee)}) options.blockMinFeeRate = CFeeRate{*parsed}; } + options.print_modified_fee = args.GetBoolArg("-printpriority", options.print_modified_fee); } -static BlockAssembler::Options ConfiguredOptions() -{ - BlockAssembler::Options options; - ApplyArgsManOptions(gArgs, options); - return options; -} - -BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool) - : BlockAssembler(chainstate, mempool, ConfiguredOptions()) {} 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; @@ -110,10 +113,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc resetBlock(); pblocktemplate.reset(new CBlockTemplate()); - - if (!pblocktemplate.get()) { - return nullptr; - } CBlock* const pblock = &pblocktemplate->block; // pointer for convenience // Add dummy coinbase tx as first transaction @@ -176,7 +175,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc } const auto time_2{SteadyClock::now()}; - LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", + LogDebug(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", Ticks<MillisecondsDouble>(time_1 - time_start), nPackagesSelected, nDescendantsUpdated, Ticks<MillisecondsDouble>(time_2 - time_1), Ticks<MillisecondsDouble>(time_2 - time_start)); @@ -231,8 +230,7 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) nFees += iter->GetFee(); inBlock.insert(iter->GetSharedTx()->GetHash()); - bool fPrintPriority = gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); - if (fPrintPriority) { + if (m_options.print_modified_fee) { LogPrintf("fee rate %s txid %s\n", CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(), iter->GetTx().GetHash().ToString()); @@ -388,7 +386,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 06a917228d..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> @@ -30,7 +31,7 @@ class ChainstateManager; namespace Consensus { struct Params; }; namespace node { -static const bool DEFAULT_PRINTPRIORITY = false; +static const bool DEFAULT_PRINT_MODIFIED_FEE = false; struct CBlockTemplate { @@ -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,15 +158,15 @@ 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}; // Whether to call TestBlockValidity() at the end of CreateNewBlock(). bool test_block_validity{true}; + bool print_modified_fee{DEFAULT_PRINT_MODIFIED_FEE}; }; - explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool); explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ 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/mini_miner.h b/src/node/mini_miner.h index de62c0af75..aec2aaf6b6 100644 --- a/src/node/mini_miner.h +++ b/src/node/mini_miner.h @@ -63,7 +63,7 @@ struct IteratorComparator template<typename I> bool operator()(const I& a, const I& b) const { - return &(*a) < &(*b); + return a->first < b->first; } }; diff --git a/src/node/timeoffsets.cpp b/src/node/timeoffsets.cpp index 62f527be8a..002c00d245 100644 --- a/src/node/timeoffsets.cpp +++ b/src/node/timeoffsets.cpp @@ -3,13 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <logging.h> -#include <node/interface_ui.h> #include <node/timeoffsets.h> +#include <node/warnings.h> #include <sync.h> #include <tinyformat.h> #include <util/time.h> #include <util/translation.h> -#include <warnings.h> #include <algorithm> #include <chrono> @@ -49,8 +48,7 @@ bool TimeOffsets::WarnIfOutOfSync() const // when median == std::numeric_limits<int64_t>::min(), calling std::chrono::abs is UB auto median{std::max(Median(), std::chrono::seconds(std::numeric_limits<int64_t>::min() + 1))}; if (std::chrono::abs(median) <= WARN_THRESHOLD) { - SetMedianTimeOffsetWarning(std::nullopt); - uiInterface.NotifyAlertChanged(); + m_warnings.Unset(node::Warning::CLOCK_OUT_OF_SYNC); return false; } @@ -63,7 +61,6 @@ bool TimeOffsets::WarnIfOutOfSync() const "RPC methods to get more info." ), Ticks<std::chrono::minutes>(WARN_THRESHOLD))}; LogWarning("%s\n", msg.original); - SetMedianTimeOffsetWarning(msg); - uiInterface.NotifyAlertChanged(); + m_warnings.Set(node::Warning::CLOCK_OUT_OF_SYNC, msg); return true; } diff --git a/src/node/timeoffsets.h b/src/node/timeoffsets.h index 2b12584e12..eba706ac1e 100644 --- a/src/node/timeoffsets.h +++ b/src/node/timeoffsets.h @@ -11,8 +11,16 @@ #include <cstddef> #include <deque> +namespace node { +class Warnings; +} // namespace node + class TimeOffsets { +public: + TimeOffsets(node::Warnings& warnings) : m_warnings{warnings} {} + +private: //! Maximum number of timeoffsets stored. static constexpr size_t MAX_SIZE{50}; //! Minimum difference between system and network time for a warning to be raised. @@ -23,6 +31,8 @@ class TimeOffsets * positive offset means our peer's clock is ahead of our local clock. */ std::deque<std::chrono::seconds> m_offsets GUARDED_BY(m_mutex){}; + node::Warnings& m_warnings; + public: /** Add a new time offset sample. */ void Add(std::chrono::seconds offset) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index b66a4f2f39..0f45da45db 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -9,6 +9,7 @@ #include <net_processing.h> #include <node/blockstorage.h> #include <node/context.h> +#include <node/types.h> #include <txmempool.h> #include <validation.h> #include <validationinterface.h> @@ -54,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/transaction.h b/src/node/transaction.h index 6782536ace..5f524f4e28 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -5,9 +5,9 @@ #ifndef BITCOIN_NODE_TRANSACTION_H #define BITCOIN_NODE_TRANSACTION_H +#include <common/messages.h> #include <policy/feerate.h> #include <primitives/transaction.h> -#include <util/error.h> class CBlockIndex; class CTxMemPool; 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 new file mode 100644 index 0000000000..1302f1b127 --- /dev/null +++ b/src/node/types.h @@ -0,0 +1,49 @@ +// Copyright (c) 2010-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +//! @file node/types.h is a home for public enum and struct type definitions +//! that are used by internally by node code, but also used externally by wallet +//! or GUI code. +//! +//! This file is intended to define only simple types that do not have external +//! dependencies. More complicated types should be defined in dedicated header +//! files. + +#ifndef BITCOIN_NODE_TYPES_H +#define BITCOIN_NODE_TYPES_H + +#include <cstddef> + +namespace node { +enum class TransactionError { + OK, //!< No error + MISSING_INPUTS, + 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.cpp b/src/node/utxo_snapshot.cpp index 976421e455..ca5491bdc2 100644 --- a/src/node/utxo_snapshot.cpp +++ b/src/node/utxo_snapshot.cpp @@ -73,10 +73,10 @@ std::optional<uint256> ReadSnapshotBaseBlockhash(fs::path chaindir) } afile >> base_blockhash; - if (std::fgetc(afile.Get()) != EOF) { + int64_t position = afile.tell(); + afile.seek(0, SEEK_END); + if (position != afile.tell()) { LogPrintf("[snapshot] warning: unexpected trailing data in %s\n", read_from_str); - } else if (std::ferror(afile.Get())) { - LogPrintf("[snapshot] warning: i/o error reading %s\n", read_from_str); } return base_blockhash; } 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 new file mode 100644 index 0000000000..255d8dba6e --- /dev/null +++ b/src/node/warnings.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <bitcoin-build-config.h> // IWYU pragma: keep + +#include <node/warnings.h> + +#include <common/system.h> +#include <node/interface_ui.h> +#include <sync.h> +#include <univalue.h> +#include <util/translation.h> + +#include <utility> +#include <vector> + +namespace node { +Warnings::Warnings() +{ + // Pre-release build warning + if (!CLIENT_VERSION_IS_RELEASE) { + m_warnings.insert( + {Warning::PRE_RELEASE_TEST_BUILD, + _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications")}); + } +} +bool Warnings::Set(warning_type id, bilingual_str message) +{ + const auto& [_, inserted]{WITH_LOCK(m_mutex, return m_warnings.insert({id, std::move(message)}))}; + if (inserted) uiInterface.NotifyAlertChanged(); + return inserted; +} + +bool Warnings::Unset(warning_type id) +{ + auto success{WITH_LOCK(m_mutex, return m_warnings.erase(id))}; + if (success) uiInterface.NotifyAlertChanged(); + return success; +} + +std::vector<bilingual_str> Warnings::GetMessages() const +{ + LOCK(m_mutex); + std::vector<bilingual_str> messages; + messages.reserve(m_warnings.size()); + for (const auto& [id, msg] : m_warnings) { + messages.push_back(msg); + } + return messages; +} + +UniValue GetWarningsForRpc(const Warnings& warnings, bool use_deprecated) +{ + if (use_deprecated) { + const auto all_messages{warnings.GetMessages()}; + return all_messages.empty() ? "" : all_messages.back().original; + } + + UniValue messages{UniValue::VARR}; + for (auto&& message : warnings.GetMessages()) { + messages.push_back(std::move(message.original)); + } + return messages; +} +} // namespace node diff --git a/src/node/warnings.h b/src/node/warnings.h new file mode 100644 index 0000000000..24aeb8a922 --- /dev/null +++ b/src/node/warnings.h @@ -0,0 +1,90 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_NODE_WARNINGS_H +#define BITCOIN_NODE_WARNINGS_H + +#include <sync.h> +#include <util/translation.h> + +#include <map> +#include <variant> +#include <vector> + +class UniValue; + +namespace kernel { +enum class Warning; +} // namespace kernel + +namespace node { +enum class Warning { + CLOCK_OUT_OF_SYNC, + PRE_RELEASE_TEST_BUILD, + FATAL_INTERNAL_ERROR, +}; + +/** + * @class Warnings + * @brief Manages warning messages within a node. + * + * The Warnings class provides mechanisms to set, unset, and retrieve + * warning messages. It updates the GUI when warnings are changed. + * + * This class is designed to be non-copyable to ensure warnings + * are managed centrally. + */ +class Warnings +{ + typedef std::variant<kernel::Warning, node::Warning> warning_type; + + mutable Mutex m_mutex; + std::map<warning_type, bilingual_str> m_warnings GUARDED_BY(m_mutex); + +public: + Warnings(); + //! A warnings instance should always be passed by reference, never copied. + Warnings(const Warnings&) = delete; + Warnings& operator=(const Warnings&) = delete; + /** + * @brief Set a warning message. If a warning with the specified + * `id` is already active, false is returned and the new + * warning is ignored. If `id` does not yet exist, the + * warning is set, the UI is updated, and true is returned. + * + * @param[in] id Unique identifier of the warning. + * @param[in] message Warning message to be shown. + * + * @returns true if the warning was indeed set (i.e. there is no + * active warning with this `id`), otherwise false. + */ + bool Set(warning_type id, bilingual_str message) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + /** + * @brief Unset a warning message. If a warning with the specified + * `id` is active, it is unset, the UI is updated, and true + * is returned. Otherwise, no warning is unset and false is + * returned. + * + * @param[in] id Unique identifier of the warning. + * + * @returns true if the warning was indeed unset (i.e. there is an + * active warning with this `id`), otherwise false. + */ + bool Unset(warning_type id) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + /** Return potential problems detected by the node, sorted by the + * warning_type id */ + std::vector<bilingual_str> GetMessages() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); +}; + +/** + * RPC helper function that wraps warnings.GetMessages(). + * + * Returns a UniValue::VSTR with the latest warning if use_deprecated is + * set to true, or a UniValue::VARR with all warnings otherwise. + */ +UniValue GetWarningsForRpc(const Warnings& warnings, bool use_deprecated); +} // namespace node + +#endif // BITCOIN_NODE_WARNINGS_H 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.cpp b/src/policy/fees.cpp index 5f1d15c5f2..a17faa3b99 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -385,7 +385,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal, failed_within_target_perc = 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool); } - LogPrint(BCLog::ESTIMATEFEE, "FeeEst: %d > %.0f%% decay %.5f: feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", + LogDebug(BCLog::ESTIMATEFEE, "FeeEst: %d > %.0f%% decay %.5f: feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", confTarget, 100.0 * successBreakPoint, decay, median, passBucket.start, passBucket.end, passed_within_target_perc, @@ -466,7 +466,7 @@ void TxConfirmStats::Read(AutoFile& filein, int nFileVersion, size_t numBuckets) // to match the number of confirms and buckets resizeInMemoryCounters(numBuckets); - LogPrint(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n", + LogDebug(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n", numBuckets, maxConfirms); } @@ -485,7 +485,7 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe if (nBestSeenHeight == 0) // the BlockPolicyEstimator hasn't seen any blocks yet blocksAgo = 0; if (blocksAgo < 0) { - LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, blocks ago is negative for mempool tx\n"); + LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, blocks ago is negative for mempool tx\n"); return; //This can't happen because we call this with our best seen height, no entries can have higher } @@ -493,7 +493,7 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe if (oldUnconfTxs[bucketindex] > 0) { oldUnconfTxs[bucketindex]--; } else { - LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n", + LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n", bucketindex); } } @@ -502,7 +502,7 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe if (unconfTxs[blockIndex][bucketindex] > 0) { unconfTxs[blockIndex][bucketindex]--; } else { - LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n", + LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n", blockIndex, bucketindex); } } @@ -595,7 +595,7 @@ void CBlockPolicyEstimator::processTransaction(const NewMempoolTransactionInfo& const unsigned int txHeight = tx.info.txHeight; const auto& hash = tx.info.m_tx->GetHash(); if (mapMemPoolTxs.count(hash)) { - LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n", + LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n", hash.ToString()); return; } @@ -649,7 +649,7 @@ bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const Remo if (blocksToConfirm <= 0) { // This can't happen because we don't process transactions from a block with a height // lower than our greatest seen height - LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n"); + LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n"); return false; } @@ -699,11 +699,11 @@ void CBlockPolicyEstimator::processBlock(const std::vector<RemovedMempoolTransac if (firstRecordedHeight == 0 && countedTxs > 0) { firstRecordedHeight = nBestSeenHeight; - LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight); + LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight); } - LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n", + LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n", countedTxs, txs_removed_for_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(), MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current"); @@ -1055,7 +1055,7 @@ void CBlockPolicyEstimator::FlushUnconfirmed() _removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs } const auto endclear{SteadyClock::now()}; - LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %.3fs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear)); + LogDebug(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %.3fs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear)); } std::chrono::hours CBlockPolicyEstimator::GetFeeEstimatorFileAge() 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 d8b4b907e4..68d879b5b8 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -93,7 +93,7 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason) { - if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) { + if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < 1) { reason = "version"; return false; } @@ -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/policy/policy.h b/src/policy/policy.h index 6a7980c312..a82488a28c 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -131,7 +131,7 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_ // Changing the default transaction version requires a two step process: first // adapting relay policy by bumping TX_MAX_STANDARD_VERSION, and then later // allowing the new transaction version in the wallet/RPC. -static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2}; +static constexpr decltype(CTransaction::version) TX_MAX_STANDARD_VERSION{3}; /** * Check for standard transaction types diff --git a/src/policy/v3_policy.cpp b/src/policy/truc_policy.cpp index d44832fceb..69e8d5ed1d 100644 --- a/src/policy/v3_policy.cpp +++ b/src/policy/truc_policy.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <policy/v3_policy.h> +#include <policy/truc_policy.h> #include <coins.h> #include <consensus/amount.h> @@ -14,7 +14,7 @@ #include <numeric> #include <vector> -/** Helper for PackageV3Checks: Returns a vector containing the indices of transactions (within +/** Helper for PackageTRUCChecks: Returns a vector containing the indices of transactions (within * package) that are direct parents of ptx. */ std::vector<size_t> FindInPackageParents(const Package& package, const CTransactionRef& ptx) { @@ -37,78 +37,77 @@ std::vector<size_t> FindInPackageParents(const Package& package, const CTransact return in_package_parents; } -/** Helper for PackageV3Checks, storing info for a mempool or package parent. */ +/** Helper for PackageTRUCChecks, storing info for a mempool or package parent. */ struct ParentInfo { /** Txid used to identify this parent by prevout */ const Txid& m_txid; /** Wtxid used for debug string */ const Wtxid& m_wtxid; - /** nVersion used to check inheritance of v3 and non-v3 */ - decltype(CTransaction::nVersion) m_version; + /** version used to check inheritance of TRUC and non-TRUC */ + decltype(CTransaction::version) m_version; /** If parent is in mempool, whether it has any descendants in mempool. */ bool m_has_mempool_descendant; ParentInfo() = delete; - ParentInfo(const Txid& txid, const Wtxid& wtxid, decltype(CTransaction::nVersion) version, bool has_mempool_descendant) : + ParentInfo(const Txid& txid, const Wtxid& wtxid, decltype(CTransaction::version) version, bool has_mempool_descendant) : m_txid{txid}, m_wtxid{wtxid}, m_version{version}, m_has_mempool_descendant{has_mempool_descendant} {} }; -std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t vsize, +std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize, const Package& package, const CTxMemPool::setEntries& mempool_ancestors) { // This function is specialized for these limits, and must be reimplemented if they ever change. - static_assert(V3_ANCESTOR_LIMIT == 2); - static_assert(V3_DESCENDANT_LIMIT == 2); + static_assert(TRUC_ANCESTOR_LIMIT == 2); + static_assert(TRUC_DESCENDANT_LIMIT == 2); const auto in_package_parents{FindInPackageParents(package, ptx)}; - // Now we have all ancestors, so we can start checking v3 rules. - if (ptx->nVersion == 3) { - // SingleV3Checks should have checked this already. - if (!Assume(vsize <= V3_MAX_VSIZE)) { - return strprintf("v3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes", - ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, V3_MAX_VSIZE); + // Now we have all ancestors, so we can start checking TRUC rules. + if (ptx->version == TRUC_VERSION) { + // SingleTRUCChecks should have checked this already. + if (!Assume(vsize <= TRUC_MAX_VSIZE)) { + return strprintf("version=3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes", + ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_MAX_VSIZE); } - if (mempool_ancestors.size() + in_package_parents.size() + 1 > V3_ANCESTOR_LIMIT) { + if (mempool_ancestors.size() + in_package_parents.size() + 1 > TRUC_ANCESTOR_LIMIT) { return strprintf("tx %s (wtxid=%s) would have too many ancestors", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()); } const bool has_parent{mempool_ancestors.size() + in_package_parents.size() > 0}; if (has_parent) { - // A v3 child cannot be too large. - if (vsize > V3_CHILD_MAX_VSIZE) { - return strprintf("v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", + // A TRUC child cannot be too large. + if (vsize > TRUC_CHILD_MAX_VSIZE) { + return strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), - vsize, V3_CHILD_MAX_VSIZE); + vsize, TRUC_CHILD_MAX_VSIZE); } // Exactly 1 parent exists, either in mempool or package. Find it. const auto parent_info = [&] { if (mempool_ancestors.size() > 0) { auto& mempool_parent = *mempool_ancestors.begin(); - Assume(mempool_parent->GetCountWithDescendants() == 1); return ParentInfo{mempool_parent->GetTx().GetHash(), mempool_parent->GetTx().GetWitnessHash(), - mempool_parent->GetTx().nVersion, + mempool_parent->GetTx().version, /*has_mempool_descendant=*/mempool_parent->GetCountWithDescendants() > 1}; } else { auto& parent_index = in_package_parents.front(); auto& package_parent = package.at(parent_index); return ParentInfo{package_parent->GetHash(), package_parent->GetWitnessHash(), - package_parent->nVersion, + package_parent->version, /*has_mempool_descendant=*/false}; } }(); // If there is a parent, it must have the right version. - if (parent_info.m_version != 3) { - return strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)", + if (parent_info.m_version != TRUC_VERSION) { + return strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), parent_info.m_txid.ToString(), parent_info.m_wtxid.ToString()); } @@ -119,7 +118,7 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v for (auto& input : package_tx->vin) { // Fail if we find another tx with the same parent. We don't check whether the - // sibling is to-be-replaced (done in SingleV3Checks) because these transactions + // sibling is to-be-replaced (done in SingleTRUCChecks) because these transactions // are within the same package. if (input.prevout.hash == parent_info.m_txid) { return strprintf("tx %s (wtxid=%s) would exceed descendant count limit", @@ -135,26 +134,23 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v } } - // It shouldn't be possible to have any mempool siblings at this point. SingleV3Checks - // catches mempool siblings and sibling eviction is not extended to packages. Also, if the package consists of connected transactions, - // any tx having a mempool ancestor would mean the package exceeds ancestor limits. - if (!Assume(!parent_info.m_has_mempool_descendant)) { + if (parent_info.m_has_mempool_descendant) { return strprintf("tx %s (wtxid=%s) would exceed descendant count limit", parent_info.m_txid.ToString(), parent_info.m_wtxid.ToString()); } } } else { - // Non-v3 transactions cannot have v3 parents. + // Non-TRUC transactions cannot have TRUC parents. for (auto it : mempool_ancestors) { - if (it->GetTx().nVersion == 3) { - return strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)", + if (it->GetTx().version == TRUC_VERSION) { + return strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), it->GetSharedTx()->GetHash().ToString(), it->GetSharedTx()->GetWitnessHash().ToString()); } } for (const auto& index: in_package_parents) { - if (package.at(index)->nVersion == 3) { - return strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)", + if (package.at(index)->version == TRUC_VERSION) { + return strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), package.at(index)->GetHash().ToString(), @@ -165,20 +161,20 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v return std::nullopt; } -std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTransactionRef& ptx, +std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CTransactionRef& ptx, const CTxMemPool::setEntries& mempool_ancestors, const std::set<Txid>& direct_conflicts, int64_t vsize) { - // Check v3 and non-v3 inheritance. + // Check TRUC and non-TRUC inheritance. for (const auto& entry : mempool_ancestors) { - if (ptx->nVersion != 3 && entry->GetTx().nVersion == 3) { - return std::make_pair(strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)", + if (ptx->version != TRUC_VERSION && entry->GetTx().version == TRUC_VERSION) { + return std::make_pair(strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()), nullptr); - } else if (ptx->nVersion == 3 && entry->GetTx().nVersion != 3) { - return std::make_pair(strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)", + } else if (ptx->version == TRUC_VERSION && entry->GetTx().version != TRUC_VERSION) { + return std::make_pair(strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()), nullptr); @@ -186,20 +182,20 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTra } // This function is specialized for these limits, and must be reimplemented if they ever change. - static_assert(V3_ANCESTOR_LIMIT == 2); - static_assert(V3_DESCENDANT_LIMIT == 2); + static_assert(TRUC_ANCESTOR_LIMIT == 2); + static_assert(TRUC_DESCENDANT_LIMIT == 2); - // The rest of the rules only apply to transactions with nVersion=3. - if (ptx->nVersion != 3) return std::nullopt; + // The rest of the rules only apply to transactions with version=3. + if (ptx->version != TRUC_VERSION) return std::nullopt; - if (vsize > V3_MAX_VSIZE) { - return std::make_pair(strprintf("v3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes", - ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, V3_MAX_VSIZE), + if (vsize > TRUC_MAX_VSIZE) { + return std::make_pair(strprintf("version=3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes", + ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_MAX_VSIZE), nullptr); } - // Check that V3_ANCESTOR_LIMIT would not be violated. - if (mempool_ancestors.size() + 1 > V3_ANCESTOR_LIMIT) { + // Check that TRUC_ANCESTOR_LIMIT would not be violated. + if (mempool_ancestors.size() + 1 > TRUC_ANCESTOR_LIMIT) { return std::make_pair(strprintf("tx %s (wtxid=%s) would have too many ancestors", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()), nullptr); @@ -207,10 +203,10 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTra // Remaining checks only pertain to transactions with unconfirmed ancestors. if (mempool_ancestors.size() > 0) { - // If this transaction spends V3 parents, it cannot be too large. - if (vsize > V3_CHILD_MAX_VSIZE) { - return std::make_pair(strprintf("v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", - ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, V3_CHILD_MAX_VSIZE), + // If this transaction spends TRUC parents, it cannot be too large. + if (vsize > TRUC_CHILD_MAX_VSIZE) { + return std::make_pair(strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", + ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE), nullptr); } @@ -221,14 +217,14 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTra // possible through a reorg. const auto& children = parent_entry->GetMemPoolChildrenConst(); // Don't double-count a transaction that is going to be replaced. This logic assumes that - // any descendant of the V3 transaction is a direct child, which makes sense because a V3 - // transaction can only have 1 descendant. + // any descendant of the TRUC transaction is a direct child, which makes sense because a + // TRUC transaction can only have 1 descendant. const bool child_will_be_replaced = !children.empty() && std::any_of(children.cbegin(), children.cend(), [&direct_conflicts](const CTxMemPoolEntry& child){return direct_conflicts.count(child.GetTx().GetHash()) > 0;}); - if (parent_entry->GetCountWithDescendants() + 1 > V3_DESCENDANT_LIMIT && !child_will_be_replaced) { - // Allow sibling eviction for v3 transaction: if another child already exists, even if - // we don't conflict inputs with it, consider evicting it under RBF rules. We rely on v3 rules + if (parent_entry->GetCountWithDescendants() + 1 > TRUC_DESCENDANT_LIMIT && !child_will_be_replaced) { + // Allow sibling eviction for TRUC transaction: if another child already exists, even if + // we don't conflict inputs with it, consider evicting it under RBF rules. We rely on TRUC rules // only permitting 1 descendant, as otherwise we would need to have logic for deciding // which descendant to evict. Skip if this isn't true, e.g. if the transaction has // multiple children or the sibling also has descendants due to a reorg. diff --git a/src/policy/truc_policy.h b/src/policy/truc_policy.h new file mode 100644 index 0000000000..dbc77696c6 --- /dev/null +++ b/src/policy/truc_policy.h @@ -0,0 +1,94 @@ +// 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_POLICY_TRUC_POLICY_H +#define BITCOIN_POLICY_TRUC_POLICY_H + +#include <consensus/amount.h> +#include <policy/packages.h> +#include <policy/policy.h> +#include <primitives/transaction.h> +#include <txmempool.h> +#include <util/result.h> + +#include <set> +#include <string> + +// This module enforces rules for BIP 431 TRUC transactions which help make +// RBF abilities more robust. A transaction with version=3 is treated as TRUC. +static constexpr decltype(CTransaction::version) TRUC_VERSION{3}; + +// TRUC only allows 1 parent and 1 child when unconfirmed. This translates to a descendant set size +// of 2 and ancestor set size of 2. +/** Maximum number of transactions including an unconfirmed tx and its descendants. */ +static constexpr unsigned int TRUC_DESCENDANT_LIMIT{2}; +/** Maximum number of transactions including a TRUC tx and all its mempool ancestors. */ +static constexpr unsigned int TRUC_ANCESTOR_LIMIT{2}; + +/** Maximum sigop-adjusted virtual size of all v3 transactions. */ +static constexpr int64_t TRUC_MAX_VSIZE{10000}; +/** Maximum sigop-adjusted virtual size of a tx which spends from an unconfirmed TRUC transaction. */ +static constexpr int64_t TRUC_CHILD_MAX_VSIZE{1000}; +// These limits are within the default ancestor/descendant limits. +static_assert(TRUC_MAX_VSIZE + TRUC_CHILD_MAX_VSIZE <= DEFAULT_ANCESTOR_SIZE_LIMIT_KVB * 1000); +static_assert(TRUC_MAX_VSIZE + TRUC_CHILD_MAX_VSIZE <= DEFAULT_DESCENDANT_SIZE_LIMIT_KVB * 1000); + +/** Must be called for every transaction, even if not TRUC. Not strictly necessary for transactions + * accepted through AcceptMultipleTransactions. + * + * Checks the following rules: + * 1. A TRUC tx must only have TRUC unconfirmed ancestors. + * 2. A non-TRUC tx must only have non-TRUC unconfirmed ancestors. + * 3. A TRUC's ancestor set, including itself, must be within TRUC_ANCESTOR_LIMIT. + * 4. A TRUC's descendant set, including itself, must be within TRUC_DESCENDANT_LIMIT. + * 5. If a TRUC tx has any unconfirmed ancestors, the tx's sigop-adjusted vsize must be within + * TRUC_CHILD_MAX_VSIZE. + * 6. A TRUC tx must be within TRUC_MAX_VSIZE. + * + * + * @param[in] mempool_ancestors The in-mempool ancestors of ptx. + * @param[in] direct_conflicts In-mempool transactions this tx conflicts with. These conflicts + * are used to more accurately calculate the resulting descendant + * count of in-mempool ancestors. + * @param[in] vsize The sigop-adjusted virtual size of ptx. + * + * @returns 3 possibilities: + * - std::nullopt if all TRUC checks were applied successfully + * - debug string + pointer to a mempool sibling if this transaction would be the second child in a + * 1-parent-1-child cluster; the caller may consider evicting the specified sibling or return an + * error with the debug string. + * - debug string + nullptr if this transaction violates some TRUC rule and sibling eviction is not + * applicable. + */ +std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CTransactionRef& ptx, + const CTxMemPool::setEntries& mempool_ancestors, + const std::set<Txid>& direct_conflicts, + int64_t vsize); + +/** Must be called for every transaction that is submitted within a package, even if not TRUC. + * + * For each transaction in a package: + * If it's not a TRUC transaction, verify it has no direct TRUC parents in the mempool or the package. + + * If it is a TRUC transaction, verify that any direct parents in the mempool or the package are TRUC. + * If such a parent exists, verify that parent has no other children in the package or the mempool, + * and that the transaction itself has no children in the package. + * + * If any TRUC violations in the package exist, this test will fail for one of them: + * - if a TRUC transaction T has a parent in the mempool and a child in the package, then PTRUCC(T) will fail + * - if a TRUC transaction T has a parent in the package and a child in the package, then PTRUCC(T) will fail + * - if a TRUC transaction T and a TRUC (sibling) transaction U have some parent in the mempool, + * then PTRUCC(T) and PTRUCC(U) will fail + * - if a TRUC transaction T and a TRUC (sibling) transaction U have some parent in the package, + * then PTRUCC(T) and PTRUCC(U) will fail + * - if a TRUC transaction T has a parent P and a grandparent G in the package, then + * PTRUCC(P) will fail (though PTRUCC(G) and PTRUCC(T) might succeed). + * + * @returns debug string if an error occurs, std::nullopt otherwise. + * */ +std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize, + const Package& package, + const CTxMemPool::setEntries& mempool_ancestors); + +#endif // BITCOIN_POLICY_TRUC_POLICY_H diff --git a/src/policy/v3_policy.h b/src/policy/v3_policy.h deleted file mode 100644 index 25aff37a1b..0000000000 --- a/src/policy/v3_policy.h +++ /dev/null @@ -1,92 +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_POLICY_V3_POLICY_H -#define BITCOIN_POLICY_V3_POLICY_H - -#include <consensus/amount.h> -#include <policy/packages.h> -#include <policy/policy.h> -#include <primitives/transaction.h> -#include <txmempool.h> -#include <util/result.h> - -#include <set> -#include <string> - -// This module enforces rules for transactions with nVersion=3 ("v3 transactions") which help make -// RBF abilities more robust. - -// v3 only allows 1 parent and 1 child when unconfirmed. -/** Maximum number of transactions including an unconfirmed tx and its descendants. */ -static constexpr unsigned int V3_DESCENDANT_LIMIT{2}; -/** Maximum number of transactions including a V3 tx and all its mempool ancestors. */ -static constexpr unsigned int V3_ANCESTOR_LIMIT{2}; - -/** Maximum sigop-adjusted virtual size of all v3 transactions. */ -static constexpr int64_t V3_MAX_VSIZE{10000}; -/** Maximum sigop-adjusted virtual size of a tx which spends from an unconfirmed v3 transaction. */ -static constexpr int64_t V3_CHILD_MAX_VSIZE{1000}; -// These limits are within the default ancestor/descendant limits. -static_assert(V3_MAX_VSIZE + V3_CHILD_MAX_VSIZE <= DEFAULT_ANCESTOR_SIZE_LIMIT_KVB * 1000); -static_assert(V3_MAX_VSIZE + V3_CHILD_MAX_VSIZE <= DEFAULT_DESCENDANT_SIZE_LIMIT_KVB * 1000); - -/** Must be called for every transaction, even if not v3. Not strictly necessary for transactions - * accepted through AcceptMultipleTransactions. - * - * Checks the following rules: - * 1. A v3 tx must only have v3 unconfirmed ancestors. - * 2. A non-v3 tx must only have non-v3 unconfirmed ancestors. - * 3. A v3's ancestor set, including itself, must be within V3_ANCESTOR_LIMIT. - * 4. A v3's descendant set, including itself, must be within V3_DESCENDANT_LIMIT. - * 5. If a v3 tx has any unconfirmed ancestors, the tx's sigop-adjusted vsize must be within - * V3_CHILD_MAX_VSIZE. - * 6. A v3 tx must be within V3_MAX_VSIZE. - * - * - * @param[in] mempool_ancestors The in-mempool ancestors of ptx. - * @param[in] direct_conflicts In-mempool transactions this tx conflicts with. These conflicts - * are used to more accurately calculate the resulting descendant - * count of in-mempool ancestors. - * @param[in] vsize The sigop-adjusted virtual size of ptx. - * - * @returns 3 possibilities: - * - std::nullopt if all v3 checks were applied successfully - * - debug string + pointer to a mempool sibling if this transaction would be the second child in a - * 1-parent-1-child cluster; the caller may consider evicting the specified sibling or return an - * error with the debug string. - * - debug string + nullptr if this transaction violates some v3 rule and sibling eviction is not - * applicable. - */ -std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTransactionRef& ptx, - const CTxMemPool::setEntries& mempool_ancestors, - const std::set<Txid>& direct_conflicts, - int64_t vsize); - -/** Must be called for every transaction that is submitted within a package, even if not v3. - * - * For each transaction in a package: - * If it's not a v3 transaction, verify it has no direct v3 parents in the mempool or the package. - - * If it is a v3 transaction, verify that any direct parents in the mempool or the package are v3. - * If such a parent exists, verify that parent has no other children in the package or the mempool, - * and that the transaction itself has no children in the package. - * - * If any v3 violations in the package exist, this test will fail for one of them: - * - if a v3 transaction T has a parent in the mempool and a child in the package, then PV3C(T) will fail - * - if a v3 transaction T has a parent in the package and a child in the package, then PV3C(T) will fail - * - if a v3 transaction T and a v3 (sibling) transaction U have some parent in the mempool, - * then PV3C(T) and PV3C(U) will fail - * - if a v3 transaction T and a v3 (sibling) transaction U have some parent in the package, - * then PV3C(T) and PV3C(U) will fail - * - if a v3 transaction T has a parent P and a grandparent G in the package, then - * PV3C(P) will fail (though PV3C(G) and PV3C(T) might succeed). - * - * @returns debug string if an error occurs, std::nullopt otherwise. - * */ -std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t vsize, - const Package& package, - const CTxMemPool::setEntries& mempool_ancestors); - -#endif // BITCOIN_POLICY_V3_POLICY_H diff --git a/src/pow.cpp b/src/pow.cpp index 1e8d53de8b..6c8e7e5d98 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; @@ -122,8 +134,19 @@ bool PermittedDifficultyTransition(const Consensus::Params& params, int64_t heig return true; } +// Bypasses the actual proof of work check during fuzz testing with a simplified validation checking whether +// the most signficant bit of the last byte of the hash is set. bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + return (hash.data()[31] & 0x80) == 0; +#else + return CheckProofOfWorkImpl(hash, nBits, params); +#endif +} + +bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params& params) +{ bool fNegative; bool fOverflow; arith_uint256 bnTarget; @@ -19,6 +19,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); +bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params&); /** * Return false if the proof-of-work requirement specified by new_nbits at a diff --git a/src/prevector.h b/src/prevector.h index 4776db789b..d14e5f64e9 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -5,13 +5,13 @@ #ifndef BITCOIN_PREVECTOR_H #define BITCOIN_PREVECTOR_H -#include <assert.h> -#include <cstdlib> -#include <stdint.h> -#include <string.h> - #include <algorithm> +#include <cassert> #include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <iterator> #include <type_traits> #include <utility> @@ -50,7 +50,6 @@ public: T* ptr{}; public: typedef Diff difference_type; - typedef T value_type; typedef T* pointer; typedef T& reference; using element_type = T; @@ -102,7 +101,6 @@ public: const T* ptr{}; public: typedef Diff difference_type; - typedef const T value_type; typedef const T* pointer; typedef const T& reference; using element_type = const T; @@ -212,7 +210,7 @@ private: std::fill_n(dst, count, value); } - template<typename InputIterator> + template <std::input_iterator InputIterator> void fill(T* dst, InputIterator first, InputIterator last) { while (first != last) { new(static_cast<void*>(dst)) T(*first); @@ -231,7 +229,7 @@ public: fill(item_ptr(0), n, val); } - template<typename InputIterator> + template <std::input_iterator InputIterator> void assign(InputIterator first, InputIterator last) { size_type n = last - first; clear(); @@ -242,7 +240,7 @@ public: fill(item_ptr(0), first, last); } - prevector() {} + prevector() = default; explicit prevector(size_type n) { resize(n); @@ -254,7 +252,7 @@ public: fill(item_ptr(0), n, val); } - template<typename InputIterator> + template <std::input_iterator InputIterator> prevector(InputIterator first, InputIterator last) { size_type n = last - first; change_capacity(n); @@ -365,7 +363,8 @@ public: change_capacity(new_size + (new_size >> 1)); } T* ptr = item_ptr(p); - memmove(ptr + 1, ptr, (size() - p) * sizeof(T)); + T* dst = ptr + 1; + memmove(dst, ptr, (size() - p) * sizeof(T)); _size++; new(static_cast<void*>(ptr)) T(value); return iterator(ptr); @@ -378,12 +377,13 @@ public: change_capacity(new_size + (new_size >> 1)); } T* ptr = item_ptr(p); - memmove(ptr + count, ptr, (size() - p) * sizeof(T)); + T* dst = ptr + count; + memmove(dst, ptr, (size() - p) * sizeof(T)); _size += count; fill(item_ptr(p), count, value); } - template<typename InputIterator> + template <std::input_iterator InputIterator> void insert(iterator pos, InputIterator first, InputIterator last) { size_type p = pos - begin(); difference_type count = last - first; @@ -392,7 +392,8 @@ public: change_capacity(new_size + (new_size >> 1)); } T* ptr = item_ptr(p); - memmove(ptr + count, ptr, (size() - p) * sizeof(T)); + T* dst = ptr + count; + memmove(dst, ptr, (size() - p) * sizeof(T)); _size += count; fill(ptr, first, last); } 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/primitives/transaction.cpp b/src/primitives/transaction.cpp index b4a860dd9e..fab5c40765 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -6,12 +6,12 @@ #include <primitives/transaction.h> #include <consensus/amount.h> +#include <crypto/hex_base.h> #include <hash.h> #include <script/script.h> #include <serialize.h> #include <tinyformat.h> #include <uint256.h> -#include <util/strencodings.h> #include <util/transaction_identifier.h> #include <algorithm> @@ -63,8 +63,8 @@ std::string CTxOut::ToString() const return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30)); } -CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {} -CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {} +CMutableTransaction::CMutableTransaction() : version{CTransaction::CURRENT_VERSION}, nLockTime{0} {} +CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), version{tx.version}, nLockTime{tx.nLockTime} {} Txid CMutableTransaction::GetHash() const { @@ -92,8 +92,8 @@ Wtxid CTransaction::ComputeWitnessHash() const return Wtxid::FromUint256((HashWriter{} << TX_WITH_WITNESS(*this)).GetHash()); } -CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), m_has_witness{ComputeHasWitness()}, hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} -CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), m_has_witness{ComputeHasWitness()}, hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} +CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), version{tx.version}, nLockTime{tx.nLockTime}, m_has_witness{ComputeHasWitness()}, hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} +CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), version{tx.version}, nLockTime{tx.nLockTime}, m_has_witness{ComputeHasWitness()}, hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} CAmount CTransaction::GetValueOut() const { @@ -115,9 +115,9 @@ unsigned int CTransaction::GetTotalSize() const std::string CTransaction::ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n", + str += strprintf("CTransaction(hash=%s, ver=%u, vin.size=%u, vout.size=%u, nLockTime=%u)\n", GetHash().ToString().substr(0,10), - nVersion, + version, vin.size(), vout.size(), nLockTime); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 976542cfae..bf86562886 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -197,13 +197,13 @@ static constexpr TransactionSerParams TX_NO_WITNESS{.allow_witness = false}; /** * Basic transaction serialization format: - * - int32_t nVersion + * - uint32_t version * - std::vector<CTxIn> vin * - std::vector<CTxOut> vout * - uint32_t nLockTime * * Extended transaction serialization format: - * - int32_t nVersion + * - uint32_t version * - unsigned char dummy = 0x00 * - unsigned char flags (!= 0) * - std::vector<CTxIn> vin @@ -217,7 +217,7 @@ void UnserializeTransaction(TxType& tx, Stream& s, const TransactionSerParams& p { const bool fAllowWitness = params.allow_witness; - s >> tx.nVersion; + s >> tx.version; unsigned char flags = 0; tx.vin.clear(); tx.vout.clear(); @@ -257,7 +257,7 @@ void SerializeTransaction(const TxType& tx, Stream& s, const TransactionSerParam { const bool fAllowWitness = params.allow_witness; - s << tx.nVersion; + s << tx.version; unsigned char flags = 0; // Consistency check if (fAllowWitness) { @@ -296,7 +296,7 @@ class CTransaction { public: // Default transaction version. - static const int32_t CURRENT_VERSION=2; + static const uint32_t CURRENT_VERSION{2}; // The local variables are made const to prevent unintended modification // without updating the cached hash value. However, CTransaction is not @@ -305,7 +305,7 @@ public: // structure, including the hash. const std::vector<CTxIn> vin; const std::vector<CTxOut> vout; - const int32_t nVersion; + const uint32_t version; const uint32_t nLockTime; private: @@ -378,7 +378,7 @@ struct CMutableTransaction { std::vector<CTxIn> vin; std::vector<CTxOut> vout; - int32_t nVersion; + uint32_t version; uint32_t nLockTime; explicit CMutableTransaction(); diff --git a/src/psbt.cpp b/src/psbt.cpp index b2ee3ce7a5..19d855e4c7 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -4,12 +4,12 @@ #include <psbt.h> +#include <node/types.h> #include <policy/policy.h> #include <script/signingprovider.h> #include <util/check.h> #include <util/strencodings.h> - PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx) { inputs.resize(tx.vin.size()); @@ -508,17 +508,17 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti return true; } -TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs) +bool CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs) { out = psbtxs[0]; // Copy the first one // Merge for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) { if (!out.Merge(*it)) { - return TransactionError::PSBT_MISMATCH; + return false; } } - return TransactionError::OK; + return true; } std::string PSBTRoleName(PSBTRole role) { diff --git a/src/psbt.h b/src/psbt.h index 3f74083717..6d49864b3c 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -17,6 +17,10 @@ #include <optional> +namespace node { +enum class TransactionError; +} // namespace node + // Magic bytes static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff}; @@ -221,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 { @@ -237,7 +241,7 @@ struct PSBTInput if (final_script_sig.empty() && final_script_witness.IsNull()) { // Write any partial signatures - for (auto sig_pair : partial_sigs) { + for (const auto& sig_pair : partial_sigs) { SerializeToVector(s, CompactSizeWriter(PSBT_IN_PARTIAL_SIG), Span{sig_pair.second.first}); s << sig_pair.second.second; } @@ -722,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 { @@ -963,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 @@ -1173,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; } @@ -1263,9 +1272,9 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti * * @param[out] out the combined PSBT, if successful * @param[in] psbtxs the PSBTs to combine - * @return error (OK if we successfully combined the transactions, other error if they were not compatible) + * @return True if we successfully combined the transactions, false if they were not compatible */ -[[nodiscard]] TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs); +[[nodiscard]] bool CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs); //! Decode a base64ed PSBT into a PartiallySignedTransaction [[nodiscard]] bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error); diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 13e3c2dbe0..0849d2a266 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -18,6 +18,8 @@ #include <algorithm> #include <cassert> +using namespace util::hex_literals; + namespace { struct Secp256k1SelfTester @@ -190,14 +192,7 @@ int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned * For an example script for calculating H, refer to the unit tests in * ./test/functional/test_framework/crypto/secp256k1.py */ -static const std::vector<unsigned char> NUMS_H_DATA{ParseHex("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0")}; -const XOnlyPubKey XOnlyPubKey::NUMS_H{NUMS_H_DATA}; - -XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes) -{ - assert(bytes.size() == 32); - std::copy(bytes.begin(), bytes.end(), m_keydata.begin()); -} +constexpr XOnlyPubKey XOnlyPubKey::NUMS_H{"50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"_hex_u8}; std::vector<CKeyID> XOnlyPubKey::GetKeyIDs() const { diff --git a/src/pubkey.h b/src/pubkey.h index ae34ddd0af..b4666aad22 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -254,7 +254,7 @@ public: bool IsNull() const { return m_keydata.IsNull(); } /** Construct an x-only pubkey from exactly 32 bytes. */ - explicit XOnlyPubKey(Span<const unsigned char> bytes); + constexpr explicit XOnlyPubKey(std::span<const unsigned char> bytes) : m_keydata{bytes} {} /** Construct an x-only pubkey from a normal pubkey. */ explicit XOnlyPubKey(const CPubKey& pubkey) : XOnlyPubKey(Span{pubkey}.subspan(1, 32)) {} diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt new file mode 100644 index 0000000000..7ec2b74cc8 --- /dev/null +++ b/src/qt/CMakeLists.txt @@ -0,0 +1,330 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + enable_language(OBJCXX) + set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJCXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + set(CMAKE_OBJCXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") + string(APPEND CMAKE_OBJCXX_COMPILE_OBJECT " ${APPEND_CPPFLAGS} ${APPEND_CXXFLAGS}") +endif() + +get_target_property(qt_lib_type Qt5::Core TYPE) + +function(import_plugins target) + if(qt_lib_type STREQUAL "STATIC_LIBRARY") + set(plugins Qt5::QMinimalIntegrationPlugin) + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND plugins Qt5::QXcbIntegrationPlugin) + elseif(WIN32) + list(APPEND plugins Qt5::QWindowsIntegrationPlugin Qt5::QWindowsVistaStylePlugin) + elseif(APPLE) + list(APPEND plugins Qt5::QCocoaIntegrationPlugin Qt5::QMacStylePlugin) + endif() + qt5_import_plugins(${target} + INCLUDE ${plugins} + EXCLUDE_BY_TYPE imageformats iconengines + ) + endif() +endfunction() + +# For Qt-specific commands and variables, please consult: +# - https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html +# - https://doc.qt.io/qt-5/cmake-manual.html + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOUIC_SEARCH_PATHS forms) + +# TODO: The file(GLOB ...) command should be replaced with an explicit +# file list. Such a change must be synced with the corresponding change +# to https://github.com/bitcoin-core/bitcoin-maintainer-tools/blob/main/update-translations.py +file(GLOB ts_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} locale/*.ts) +set_source_files_properties(${ts_files} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/locale) +qt5_add_translation(qm_files ${ts_files}) + +configure_file(bitcoin_locale.qrc bitcoin_locale.qrc USE_SOURCE_PERMISSIONS COPYONLY) + +# The bitcoinqt sources have to include headers in +# order to parse them to collect translatable strings. +add_library(bitcoinqt STATIC EXCLUDE_FROM_ALL + bantablemodel.cpp + bantablemodel.h + bitcoin.cpp + bitcoin.h + bitcoinaddressvalidator.cpp + bitcoinaddressvalidator.h + bitcoinamountfield.cpp + bitcoinamountfield.h + bitcoingui.cpp + bitcoingui.h + bitcoinunits.cpp + bitcoinunits.h + clientmodel.cpp + clientmodel.h + csvmodelwriter.cpp + csvmodelwriter.h + guiutil.cpp + guiutil.h + initexecutor.cpp + initexecutor.h + intro.cpp + intro.h + $<$<PLATFORM_ID:Darwin>:macdockiconhandler.h> + $<$<PLATFORM_ID:Darwin>:macdockiconhandler.mm> + $<$<PLATFORM_ID:Darwin>:macnotificationhandler.h> + $<$<PLATFORM_ID:Darwin>:macnotificationhandler.mm> + $<$<PLATFORM_ID:Darwin>:macos_appnap.h> + $<$<PLATFORM_ID:Darwin>:macos_appnap.mm> + modaloverlay.cpp + modaloverlay.h + networkstyle.cpp + networkstyle.h + notificator.cpp + notificator.h + optionsdialog.cpp + optionsdialog.h + optionsmodel.cpp + optionsmodel.h + peertablemodel.cpp + peertablemodel.h + peertablesortproxy.cpp + peertablesortproxy.h + platformstyle.cpp + platformstyle.h + qvalidatedlineedit.cpp + qvalidatedlineedit.h + qvaluecombobox.cpp + qvaluecombobox.h + rpcconsole.cpp + rpcconsole.h + splashscreen.cpp + splashscreen.h + trafficgraphwidget.cpp + trafficgraphwidget.h + utilitydialog.cpp + utilitydialog.h + $<$<PLATFORM_ID:Windows>:winshutdownmonitor.cpp> + $<$<PLATFORM_ID:Windows>:winshutdownmonitor.h> + bitcoin.qrc + ${CMAKE_CURRENT_BINARY_DIR}/bitcoin_locale.qrc +) +target_compile_definitions(bitcoinqt + PUBLIC + QT_NO_KEYWORDS + QT_USE_QSTRINGBUILDER +) +target_include_directories(bitcoinqt + PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src> +) +set_property(SOURCE macnotificationhandler.mm + # Ignore warnings "'NSUserNotificationCenter' is deprecated: first deprecated in macOS 11.0". + APPEND PROPERTY COMPILE_OPTIONS -Wno-deprecated-declarations +) +target_link_libraries(bitcoinqt + PUBLIC + Qt5::Widgets + PRIVATE + core_interface + bitcoin_cli + leveldb + Boost::headers + $<TARGET_NAME_IF_EXISTS:MiniUPnPc::MiniUPnPc> + $<TARGET_NAME_IF_EXISTS:PkgConfig::libqrencode> + $<$<PLATFORM_ID:Darwin>:-framework\ AppKit> + $<$<CXX_COMPILER_ID:MSVC>:shlwapi> +) + +if(ENABLE_WALLET) + target_sources(bitcoinqt + PRIVATE + addressbookpage.cpp + addressbookpage.h + addresstablemodel.cpp + addresstablemodel.h + askpassphrasedialog.cpp + askpassphrasedialog.h + coincontroldialog.cpp + coincontroldialog.h + coincontroltreewidget.cpp + coincontroltreewidget.h + createwalletdialog.cpp + createwalletdialog.h + editaddressdialog.cpp + editaddressdialog.h + openuridialog.cpp + openuridialog.h + overviewpage.cpp + overviewpage.h + paymentserver.cpp + paymentserver.h + psbtoperationsdialog.cpp + psbtoperationsdialog.h + qrimagewidget.cpp + qrimagewidget.h + receivecoinsdialog.cpp + receivecoinsdialog.h + receiverequestdialog.cpp + receiverequestdialog.h + recentrequeststablemodel.cpp + recentrequeststablemodel.h + sendcoinsdialog.cpp + sendcoinsdialog.h + sendcoinsentry.cpp + sendcoinsentry.h + signverifymessagedialog.cpp + signverifymessagedialog.h + transactiondesc.cpp + transactiondesc.h + transactiondescdialog.cpp + transactiondescdialog.h + transactionfilterproxy.cpp + transactionfilterproxy.h + transactionoverviewwidget.cpp + transactionoverviewwidget.h + transactionrecord.cpp + transactionrecord.h + transactiontablemodel.cpp + transactiontablemodel.h + transactionview.cpp + transactionview.h + walletcontroller.cpp + walletcontroller.h + walletframe.cpp + walletframe.h + walletmodel.cpp + walletmodel.h + walletmodeltransaction.cpp + walletmodeltransaction.h + walletview.cpp + walletview.h + ) + target_link_libraries(bitcoinqt + PRIVATE + bitcoin_wallet + Qt5::Network + ) +endif() + +if(WITH_DBUS) + target_link_libraries(bitcoinqt PRIVATE Qt5::DBus) +endif() + +if(qt_lib_type STREQUAL "STATIC_LIBRARY") + # We want to define static plugins to link ourselves, thus preventing + # automatic linking against a "sane" set of default static plugins. + qt5_import_plugins(bitcoinqt + EXCLUDE_BY_TYPE bearer iconengines imageformats platforms styles + ) +endif() + +add_executable(bitcoin-qt + main.cpp + ../init/bitcoin-qt.cpp +) + +add_windows_resources(bitcoin-qt res/bitcoin-qt-res.rc) + +target_link_libraries(bitcoin-qt + core_interface + bitcoinqt + bitcoin_node +) + +import_plugins(bitcoin-qt) +set(installable_targets bitcoin-qt) +if(WIN32) + set_target_properties(bitcoin-qt PROPERTIES WIN32_EXECUTABLE TRUE) +endif() + +if(WITH_MULTIPROCESS) + add_executable(bitcoin-gui + main.cpp + ../init/bitcoin-gui.cpp + ) + target_link_libraries(bitcoin-gui + core_interface + bitcoinqt + bitcoin_node + bitcoin_ipc + ) + import_plugins(bitcoin-gui) + list(APPEND installable_targets bitcoin-gui) + if(WIN32) + set_target_properties(bitcoin-gui PROPERTIES WIN32_EXECUTABLE TRUE) + endif() +endif() + +install(TARGETS ${installable_targets} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + COMPONENT GUI +) + +if(BUILD_GUI_TESTS) + add_subdirectory(test) +endif() + + +# Gets sources to be parsed to gather translatable strings. +function(get_translatable_sources var) + set(result) + set(targets) + foreach(dir IN ITEMS ${ARGN}) + get_directory_property(dir_targets DIRECTORY ${PROJECT_SOURCE_DIR}/${dir} BUILDSYSTEM_TARGETS) + list(APPEND targets ${dir_targets}) + endforeach() + foreach(target IN LISTS targets) + get_target_property(target_sources ${target} SOURCES) + if(target_sources) + foreach(source IN LISTS target_sources) + # Get an expression from the generator expression, if any. + if(source MATCHES ":([^>]+)>$") + set(source ${CMAKE_MATCH_1}) + endif() + cmake_path(GET source EXTENSION LAST_ONLY ext) + if(ext STREQUAL ".qrc") + continue() + endif() + if(NOT IS_ABSOLUTE source) + get_target_property(target_source_dir ${target} SOURCE_DIR) + cmake_path(APPEND target_source_dir ${source} OUTPUT_VARIABLE source) + endif() + list(APPEND result ${source}) + endforeach() + endif() + endforeach() + set(${var} ${result} PARENT_SCOPE) +endfunction() + +find_program(XGETTEXT_EXECUTABLE xgettext) +find_program(SED_EXECUTABLE sed) +if(NOT XGETTEXT_EXECUTABLE) + add_custom_target(translate + COMMAND ${CMAKE_COMMAND} -E echo "Error: GNU gettext-tools not found" + ) +elseif(NOT SED_EXECUTABLE) + add_custom_target(translate + COMMAND ${CMAKE_COMMAND} -E echo "Error: GNU sed not found" + ) +else() + set(translatable_sources_directories src src/qt src/util) + if(ENABLE_WALLET) + list(APPEND translatable_sources_directories src/wallet) + endif() + get_translatable_sources(translatable_sources ${translatable_sources_directories}) + get_translatable_sources(qt_translatable_sources src/qt) + file(GLOB ui_files ${CMAKE_CURRENT_SOURCE_DIR}/forms/*.ui) + add_custom_target(translate + COMMAND ${CMAKE_COMMAND} -E env XGETTEXT=${XGETTEXT_EXECUTABLE} COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS} ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/share/qt/extract_strings_qt.py ${translatable_sources} + COMMAND Qt5::lupdate -no-obsolete -I ${PROJECT_SOURCE_DIR}/src -locations relative ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinstrings.cpp ${ui_files} ${qt_translatable_sources} -ts ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.ts + COMMAND Qt5::lconvert -drop-translations -o ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.xlf -i ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.ts + COMMAND ${SED_EXECUTABLE} -i.old -e "s|source-language=\"en\" target-language=\"en\"|source-language=\"en\"|" -e "/<target xml:space=\"preserve\"><\\/target>/d" ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.xlf + COMMAND ${CMAKE_COMMAND} -E rm ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.xlf.old + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src + VERBATIM + ) +endif() diff --git a/src/qt/Makefile b/src/qt/Makefile deleted file mode 100644 index 3bd6199059..0000000000 --- a/src/qt/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -.PHONY: FORCE -all: FORCE - $(MAKE) -C .. bitcoin_qt test_bitcoin_qt -clean: FORCE - $(MAKE) -C .. bitcoin_qt_clean test_bitcoin_qt_clean -check: FORCE - $(MAKE) -C .. test_bitcoin_qt_check -bitcoin-qt bitcoin-qt.exe: FORCE - $(MAKE) -C .. bitcoin_qt -apk: FORCE - $(MAKE) -C .. bitcoin_qt_apk diff --git a/src/qt/README.md b/src/qt/README.md index 20c712c98d..3ecdd0888e 100644 --- a/src/qt/README.md +++ b/src/qt/README.md @@ -4,14 +4,14 @@ The current precise version for Qt 5 is specified in [qt.mk](/depends/packages/q ## Compile and run -See build instructions: [Unix](/doc/build-unix.md), [macOS](/doc/build-osx.md), [Windows](/doc/build-windows.md), [FreeBSD](/doc/build-freebsd.md), [NetBSD](/doc/build-netbsd.md), [OpenBSD](/doc/build-openbsd.md) +See build instructions: [Unix](/doc/build-unix.md), [macOS](/doc/build-osx.md), [Windows](/doc/build-windows-msvc.md), [FreeBSD](/doc/build-freebsd.md), [NetBSD](/doc/build-netbsd.md), [OpenBSD](/doc/build-openbsd.md) When following your systems build instructions, make sure to install the `Qt` dependencies. To run: ```sh -./src/qt/bitcoin-qt +./build/src/qt/bitcoin-qt ``` ## Files and Directories @@ -99,7 +99,7 @@ sudo apt-get install qtcreator #### Setup Qt Creator 1. Make sure you've installed all dependencies specified in your systems build instructions -2. Follow the compile instructions for your system, run `./configure` with the `--enable-debug` flag +2. Follow the compile instructions for your system, adding the `-DCMAKE_BUILD_TYPE=Debug` build flag 3. Start Qt Creator. At the start page, do: `New` -> `Import Project` -> `Import Existing Project` 4. Enter `bitcoin-qt` as the Project Name and enter the absolute path to `src/qt` as Location 5. Check over the file selection, you may need to select the `forms` directory (necessary if you intend to edit *.ui files) 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 44a858c16b..c43cb77866 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/bitcoin.h> @@ -60,21 +60,6 @@ #include <QTranslator> #include <QWindow> -#if defined(QT_STATICPLUGIN) -#include <QtPlugin> -#if defined(QT_QPA_PLATFORM_XCB) -Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); -#elif defined(QT_QPA_PLATFORM_WINDOWS) -Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); -Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin); -#elif defined(QT_QPA_PLATFORM_COCOA) -Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); -Q_IMPORT_PLUGIN(QMacStylePlugin); -#elif defined(QT_QPA_PLATFORM_ANDROID) -Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin) -#endif -#endif - // Declare meta types used for QMetaObject::invokeMethod Q_DECLARE_METATYPE(bool*) Q_DECLARE_METATYPE(CAmount) @@ -85,6 +70,8 @@ Q_DECLARE_METATYPE(uint256) Q_DECLARE_METATYPE(wallet::AddressPurpose) #endif // ENABLE_WALLET +using util::MakeUnorderedList; + static void RegisterMetaTypes() { // Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection @@ -210,7 +197,7 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons { Q_UNUSED(context); if (type == QtDebugMsg) { - LogPrint(BCLog::QT, "GUI: %s\n", msg.toStdString()); + LogDebug(BCLog::QT, "GUI: %s\n", msg.toStdString()); } else { LogPrintf("GUI: %s\n", msg.toStdString()); } @@ -538,7 +525,7 @@ int GuiMain(int argc, char* argv[]) /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these // Command-line options take precedence: - SetupServerArgs(gArgs); + SetupServerArgs(gArgs, init->canListenIpc()); SetupUIArgs(gArgs); std::string error; if (!gArgs.ParseParameters(argc, argv, error)) { diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 1423a8bbc6..52b117eed7 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_QT_BITCOIN_H #define BITCOIN_QT_BITCOIN_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <interfaces/node.h> #include <qt/initexecutor.h> diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc index 8883134b83..e1f2697391 100644 --- a/src/qt/bitcoin_locale.qrc +++ b/src/qt/bitcoin_locale.qrc @@ -1,6 +1,5 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/translations"> - <file alias="af">locale/bitcoin_af.qm</file> <file alias="am">locale/bitcoin_am.qm</file> <file alias="ar">locale/bitcoin_ar.qm</file> <file alias="az">locale/bitcoin_az.qm</file> @@ -104,6 +103,7 @@ <file alias="szl">locale/bitcoin_szl.qm</file> <file alias="ta">locale/bitcoin_ta.qm</file> <file alias="te">locale/bitcoin_te.qm</file> + <file alias="th">locale/bitcoin_th.qm</file> <file alias="tk">locale/bitcoin_tk.qm</file> <file alias="tl">locale/bitcoin_tl.qm</file> <file alias="tr">locale/bitcoin_tr.qm</file> diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a43009d954..6d7e183e98 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/bitcoingui.h> @@ -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/bitcoingui.h b/src/qt/bitcoingui.h index 73adbda5a5..32fb7488fb 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_QT_BITCOINGUI_H #define BITCOIN_QT_BITCOINGUI_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/bitcoinunits.h> #include <qt/clientmodel.h> 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..fb81dee8da 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/clientmodel.h> @@ -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/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp index 3e8d1461e5..2908043d28 100644 --- a/src/qt/createwalletdialog.cpp +++ b/src/qt/createwalletdialog.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <interfaces/node.h> #include <qt/createwalletdialog.h> 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/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 99fb238772..2056b2cccd 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -105,7 +105,7 @@ <item> <widget class="QLabel" name="databaseCacheLabel"> <property name="toolTip"> - <string extracomment="Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.">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.</string> + <string extracomment="Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.">Maximum database cache size. Make sure you have enough RAM. 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.</string> </property> <property name="text"> <string>Size of &database cache</string> @@ -328,10 +328,10 @@ <item> <widget class="QCheckBox" name="mapPortNatpmp"> <property name="toolTip"> - <string>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.</string> + <string>Automatically open the Bitcoin client port on the router. This only works when your router supports PCP or NAT-PMP and it is enabled. The external port could be random.</string> </property> <property name="text"> - <string>Map port using NA&T-PMP</string> + <string>Map port using PCP or NA&T-PMP</string> </property> </widget> </item> 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/intro.cpp b/src/qt/intro.cpp index 26b42deb64..bc770b71aa 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chainparams.h> #include <qt/intro.h> diff --git a/src/qt/locale/bitcoin_af.ts b/src/qt/locale/bitcoin_af.ts deleted file mode 100644 index cc4eefbe31..0000000000 --- a/src/qt/locale/bitcoin_af.ts +++ /dev/null @@ -1,315 +0,0 @@ -<TS version="2.1" language="af"> -<context> - <name>AddressBookPage</name> - <message> - <source>Right-click to edit address or label</source> - <translation type="unfinished">Regsklik om adres of etiket te verander</translation> - </message> - <message> - <source>Create a new address</source> - <translation type="unfinished">Skep ’n nuwe adres</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"> -Hierdie is die adresse waar u Bitcoins sal ontvang. Ons beveel aan dat u 'n nuwe adres kies vir elke transaksie</translation> - </message> - <message> - <source>Sending addresses - %1</source> - <translation type="unfinished">Stuur adresse -%1</translation> - </message> - <message> - <source>Receiving addresses - %1</source> - <translation type="unfinished">Ontvangs van adresse - %1</translation> - </message> - </context> -<context> - <name>AskPassphraseDialog</name> - <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">Die wagwoordfrase wat vir die beursie-dekripsie ingevoer is, is verkeerd. Dit bevat 'n nulkarakter (dws - 'n nulgreep). As die wagwoordfrase gestel is met 'n weergawe van hierdie sagteware voor 25.0, probeer asseblief weer met slegs die karakters tot - maar nie ingesluit nie - die eerste nulkarakter. As dit suksesvol is, stel asseblief 'n nuwe wagwoordfrase in om hierdie probleem in die toekoms te vermy.</translation> - </message> - <message> - <source>Passphrase change failed</source> - <translation type="unfinished">Wagfraseverandering het misluk</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">Die ou wagwoordfrase wat vir die beursie-dekripsie ingevoer is, is verkeerd. Dit bevat 'n nulkarakter (dws - 'n nulgreep). As die wagwoordfrase gestel is met 'n weergawe van hierdie sagteware voor 25.0, probeer asseblief weer met slegs die karakters tot - maar nie ingesluit nie - die eerste nulkarakter.</translation> - </message> - </context> -<context> - <name>BitcoinApplication</name> - <message> - <source>Settings file %1 might be corrupt or invalid.</source> - <translation type="unfinished">Instellingslêer %1 kan korrup of ongeldig wees.</translation> - </message> - </context> -<context> - <name>QObject</name> - <message numerus="yes"> - <source>%n second(s)</source> - <translation type="unfinished"> - <numerusform>%n second(s)</numerusform> - <numerusform>%n second(s)</numerusform> - </translation> - </message> - <message numerus="yes"> - <source>%n minute(s)</source> - <translation type="unfinished"> - <numerusform>%n minute(s)</numerusform> - <numerusform>%n minute(s)</numerusform> - </translation> - </message> - <message numerus="yes"> - <source>%n hour(s)</source> - <translation type="unfinished"> - <numerusform>%n hour(s)</numerusform> - <numerusform>%n hour(s)</numerusform> - </translation> - </message> - <message numerus="yes"> - <source>%n day(s)</source> - <translation type="unfinished"> - <numerusform>%n day(s)</numerusform> - <numerusform>%n day(s)</numerusform> - </translation> - </message> - <message numerus="yes"> - <source>%n week(s)</source> - <translation type="unfinished"> - <numerusform>%n week(s)</numerusform> - <numerusform>%n week(s)</numerusform> - </translation> - </message> - <message numerus="yes"> - <source>%n year(s)</source> - <translation type="unfinished"> - <numerusform>%n year(s)</numerusform> - <numerusform>%n year(s)</numerusform> - </translation> - </message> - </context> -<context> - <name>BitcoinGUI</name> - <message numerus="yes"> - <source>Processed %n block(s) of transaction history.</source> - <translation type="unfinished"> - <numerusform>Processed %n block(s) of transaction history.</numerusform> - <numerusform>Processed %n block(s) of transaction history.</numerusform> - </translation> - </message> - <message> - <source>Restore Wallet…</source> - <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> - <translation type="unfinished">Stel beursie terug …</translation> - </message> - <message> - <source>Restore a wallet from a backup file</source> - <extracomment>Status tip for Restore Wallet menu item</extracomment> - <translation type="unfinished">Herstel 'n beursie vanaf 'n rugsteunlêer</translation> - </message> - <message> - <source>Migrate Wallet</source> - <translation type="unfinished">Migreer Wallet</translation> - </message> - <message> - <source>Migrate a wallet</source> - <translation type="unfinished">Migreer Wallet</translation> - </message> - <message> - <source>Load Wallet Backup</source> - <extracomment>The title for Restore Wallet File Windows</extracomment> - <translation type="unfinished">Laai Wallet-rugsteun</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">Herstel beursie</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 active connection(s) to Bitcoin network.</numerusform> - <numerusform>%n active connection(s) to Bitcoin network.</numerusform> - </translation> - </message> - <message> - <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Voor-sinkroniseringsopskrifte (%1%)...</translation> - </message> - <message> - <source>Error creating wallet</source> - <translation type="unfinished">Kon nie beursie skep nie</translation> - </message> - <message> - <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> - <translation type="unfinished">Kan nie nuwe beursie skep nie, die sagteware is saamgestel sonder sqlite-ondersteuning (vereis vir beskrywer-beursies)</translation> - </message> - </context> -<context> - <name>CreateWalletActivity</name> - <message> - <source>Too many external signers found</source> - <translation type="unfinished">Te veel eksterne ondertekenaars gevind</translation> - </message> -</context> -<context> - <name>MigrateWalletActivity</name> - <message> - <source>Migrate wallet</source> - <translation type="unfinished">Migreer beursie</translation> - </message> - <message> - <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> - <translation type="unfinished">Is jy seker jy wil die beursie migreer <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">Om die beursie te migreer, sal hierdie beursie na een of meer beskrywer-beursies omskakel. 'n Nuwe beursie-rugsteun sal gemaak moet word. -As hierdie beursie enige oplosbare maar nie gekykte skrifte bevat nie, sal 'n ander en nuwe beursie geskep word wat daardie skrifte bevat. -As hierdie beursie enige oplosbare maar nie gekykte skrifte bevat nie, sal 'n ander en nuwe beursie geskep word wat daardie skrifte bevat. - -Die migrasieproses sal 'n rugsteun van die beursie skep voordat dit migreer. Hierdie rugsteunlêer sal 'n naam kry <wallet name>-<timestamp>. legacy.bak en kan gevind word in die gids vir hierdie beursie. In die geval van 'n verkeerde migrasie, kan die rugsteun met die "Herstel Wallet"-funksie herstel word.</translation> - </message> - <message> - <source>Migrate Wallet</source> - <translation type="unfinished">Migreer Wallet</translation> - </message> - <message> - <source>Migrating Wallet <b>%1</b>…</source> - <translation type="unfinished">Migreer Wallet <b>%1</b>...</translation> - </message> - <message> - <source>The wallet '%1' was migrated successfully.</source> - <translation type="unfinished">Die beursie'%1' is suksesvol gemigreer.</translation> - </message> - <message> - <source>Migration failed</source> - <translation type="unfinished">Migrasie het misluk</translation> - </message> - <message> - <source>Migration Successful</source> - <translation type="unfinished">Migrasie suksesvol</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">Herstel beursie</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">Herstel beursie <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">Herstel beursie het misluk</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">Herstel beursie waarskuwing</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">Herstel beursieboodskap</translation> - </message> -</context> -<context> - <name>CreateWalletDialog</name> - <message> - <source>You are one step away from creating your new wallet!</source> - <translation type="unfinished">Jy is een stap weg van die skep van jou nuwe beursie!</translation> - </message> - <message> - <source>Please provide a name and, if desired, enable any advanced options</source> - <translation type="unfinished">Verskaf asseblief 'n naam en, indien verlang, aktiveer enige gevorderde opsies</translation> - </message> - </context> -<context> - <name>Intro</name> - <message numerus="yes"> - <source>%n GB of space available</source> - <translation type="unfinished"> - <numerusform>%n GB of space available</numerusform> - <numerusform>%n GB of space available</numerusform> - </translation> - </message> - <message numerus="yes"> - <source>(of %n GB needed)</source> - <translation type="unfinished"> - <numerusform>(of %n GB needed)</numerusform> - <numerusform>(of %n GB needed)</numerusform> - </translation> - </message> - <message numerus="yes"> - <source>(%n GB needed for full chain)</source> - <translation type="unfinished"> - <numerusform>(%n GB needed for full chain)</numerusform> - <numerusform>(%n GB needed for full chain)</numerusform> - </translation> - </message> - <message> - <source>Choose data directory</source> - <translation type="unfinished">Kies datagids</translation> - </message> - <message numerus="yes"> - <source>(sufficient to restore backups %n day(s) old)</source> - <extracomment>Explanatory text on the capability of the current prune target.</extracomment> - <translation type="unfinished"> - <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> - <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> - </translation> - </message> - <message> - <source>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">Wanneer jy OK klik, %1 sal begin om die volledige af te laai en te verwerk %4 blok ketting (%2GB) begin met die vroegste transaksies in %3 wanneer %4 aanvanklik van stapel gestuur.</translation> - </message> - </context> -<context> - <name>ModalOverlay</name> - <message> - <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> - <translation type="unfinished">Onbekend. Voor-sinkronisering opskrifte (%1, %2%)...</translation> - </message> -</context> -<context> - <name>OptionsDialog</name> - <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">Volle pad na 'n%1 versoenbare skrip (bv. C:\Downloads\hwi.exe of /Users/you/Downloads/hwi.py). Pasop: wanware kan jou munte steel!</translation> - </message> - </context> -<context> - <name>SendCoinsDialog</name> - <message numerus="yes"> - <source>Estimated to begin confirmation within %n block(s).</source> - <translation type="unfinished"> - <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> - <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> - </translation> - </message> - </context> -<context> - <name>TransactionDesc</name> - <message numerus="yes"> - <source>matures in %n more block(s)</source> - <translation type="unfinished"> - <numerusform>matures in %n more block(s)</numerusform> - <numerusform>matures in %n more block(s)</numerusform> - </translation> - </message> - </context> -</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_am.ts b/src/qt/locale/bitcoin_am.ts index 502acb9879..c02049b984 100644 --- a/src/qt/locale/bitcoin_am.ts +++ b/src/qt/locale/bitcoin_am.ts @@ -176,6 +176,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ቦርሳዎ ምስጢር ተደርጓል</translation> </message> <message> + <source>Back</source> + <translation type="unfinished">ተመለስ</translation> + </message> + <message> <source>Wallet to be encrypted</source> <translation type="unfinished">ለመመስጠር የተዘጋጀ ዋሌት</translation> </message> @@ -254,6 +258,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ስህተት፥ %1</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> @@ -299,7 +315,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n year(s)</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">መደበኛ ዋሌት</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -359,6 +379,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&ተቀበል</translation> </message> <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">&የይለፍ ቃል ቀይር…</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation type="unfinished">በእርሶ የተያዙ መሆኑን ለማረጋገጥ በBitcoin አድራሻዎችዎ መልዕክቶችን ይፈርሙ</translation> + </message> + <message> <source>&File</source> <translation type="unfinished">&ፋይል</translation> </message> @@ -402,8 +430,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ዋሌት ዝጋ</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">መደበኛ ዋሌት</translation> + <source>Migrate Wallet</source> + <translation type="unfinished">ዋሌትዎን ያዛውሩ</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">ዋሌትዎን ያዛውሩ</translation> </message> <message> <source>Wallet Name</source> @@ -423,6 +455,14 @@ 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>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> @@ -485,12 +525,51 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> - <name>OpenWalletActivity</name> + <name>MigrateWalletActivity</name> <message> - <source>default wallet</source> - <translation type="unfinished">መደበኛ ዋሌት</translation> + <source>Migrate wallet</source> + <translation type="unfinished">ዋሌት ያዛውሩ</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">ዋሌትን ማዛወር ይህንን ዋሌት አንድ ወይም ከዚያ በላይ ወደሆነ ገላጭ ዋሌቶች ይቀይረዋል።አዲስ ዋሌት ማዘጋጀት ያስፈልጋል ።ይህ ዋሌት ምንም ዓይነት የመመልከት ብቻ ስክሪፕቶችን የያዘ ከሆነ፣እነዚያን የመመልከት ብቻ ስክሪፕቶችን የያዘ አዲስ ዋሌት ይፈጠራል።ይህ ዋሌት ሊፈቱ የሚችሉ ነገር ግን የመመልከት ብቻ ያልሆኑ ስክሪፕቶችን የያዘ ከሆነ ፣ እነዚህን የያዘ አዲስ እና ልዩ የሆነ ዋሌት ይፈጠራል ።የማዛወር ሂደቱ ማዘዋወር ከመፈጸሙ በፊት የነዚህን ዋሌቶች መጠባበቂያ ቅጂ ይይዛል።ይህ መጠባበቂያ ቅጂ 1-2 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</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">ዋሌት ክፈት</translation> @@ -506,6 +585,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>CreateWalletDialog</name> <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> @@ -594,6 +681,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>OptionsDialog</name> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">በአጠቃላይ እይታ ትር ውስጥ ያለ ፊደል</translation> + </message> + <message> <source>Error</source> <translation type="unfinished">ስህተት</translation> </message> @@ -606,6 +697,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>Sends %1 to %2</source> + <translation type="unfinished">%1 ወደ %2 ይልካል</translation> + </message> + </context> +<context> <name>PeerTableModel</name> <message> <source>Address</source> @@ -614,6 +712,56 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>RPCConsole</name> + <message> + <source>Local Addresses</source> + <translation type="unfinished">የአካባቢ አድራሻዎች</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">የእርስዎ Bitcoin ኖድ ከሌሎች ኖዶች ጋር ለመገናኘት በአሁኑ ጊዜ እየተጠቀመበት ያለው የአውታረ መረብ አድራሻ።</translation> + </message> + <message> + <source>Hide Peers Detail</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>Session ID</source> + <translation type="unfinished">የክፍለ ጊዜ መለያ</translation> + </message> + <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">የBIP324 ክፍለ ጊዜ መለያ ሕብረቁምፊ በሄክስ።</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>Node window - [%1]</source> + <translation type="unfinished">የኖድ መስኮት - [%1]</translation> + </message> + </context> +<context> <name>ReceiveRequestDialog</name> <message> <source>Amount:</source> @@ -665,6 +813,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Copy fee</source> <translation type="unfinished">ክፍያው ቅዳ</translation> </message> + <message> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1 ከዋሌት %2'</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> @@ -678,6 +830,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>SignVerifyMessageDialog</name> + <message> + <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">ወደ እነርሱ የተላኩ ቢትኮይን መቀበል እንደሚችሉ ለማረጋገጥ ከርስዎ (P2PKH) አድራሻዎች ጋር መልዕክቶችን/ስምምነቶችን መፈረም ይችላሉ። የማስገር ጥቃቶች እርስዎን ማንነትዎን በእነሱ ላይ እንዲፈርሙ ሊያታልሉዎት ስለሚችሉ ግልጽ ያልሆነ ወይም በዘፈቀደ ላለመፈረም ይጠንቀቁ። የተስማሙባቸውን ሙሉ ዝርዝር መግለጫዎች ብቻ ይፈርሙ።</translation> + </message> + <message> + <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">የገባው አድራሻ የቅርስ (P2PKH) ቁልፍን አያመለክትም። ለሴግዊት እና ሌሎች P2PKH ላልሆኑ የአድራሻ አይነቶች የመልዕክት መፈረም በዚህ የ%1 ስሪት ውስጥ አይደገፍም። እባክዎ አድራሻውን ያረጋግጡ እና እንደገና ይሞክሩ።</translation> + </message> + </context> +<context> <name>TransactionDesc</name> <message> <source>Date</source> @@ -691,6 +854,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> </translation> </message> <message> + <source>%1 (Certificate was not verified)</source> + <translation type="unfinished">%1 (ማረጋገጫው አልተረጋገጠም)</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">መጠን</translation> </message> @@ -748,10 +915,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>WalletModel</name> <message> - <source>default wallet</source> - <translation type="unfinished">መደበኛ ዋሌት</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">ከክፍያ-ነፃ PSBT ወደ ቅንጥብ ሰሌዳ ተቀድቷል።</translation> </message> -</context> + <message> + <source>Signer error</source> + <translation type="unfinished">የፈራሚ ስህተት</translation> + </message> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index e58c221a86..86fef05136 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -2,275 +2,17 @@ <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> <message> - <source>Export the data in the current tab to a file</source> - <translation type="unfinished">صدّر البيانات في التبويب الحالي الى ملف</translation> - </message> - <message> <source>&Export</source> - <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> - <name>AddressTableModel</name> - <message> - <source>Label</source> - <translation type="unfinished">المذكرة</translation> - </message> - <message> - <source>Address</source> - <translation type="unfinished">العنوان</translation> - </message> - <message> - <source>(no label)</source> - <translation type="unfinished">( لا وجود لمذكرة)</translation> - </message> -</context> -<context> - <name>AskPassphraseDialog</name> - <message> - <source>Passphrase Dialog</source> - <translation type="unfinished">حوار عبارة المرور</translation> - </message> - <message> - <source>Enter passphrase</source> - <translation type="unfinished">ادخل عبارة المرور</translation> - </message> - <message> - <source>New passphrase</source> - <translation type="unfinished">أنشئ عبارة مرور</translation> - </message> - <message> - <source>Repeat new passphrase</source> - <translation type="unfinished">أعد عبارة المرور</translation> - </message> - <message> - <source>Show passphrase</source> - <translation type="unfinished">عرض عبارة المرور</translation> - </message> - <message> - <source>Encrypt wallet</source> - <translation type="unfinished">تشفير المحفظة</translation> - </message> - <message> - <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">هذه العملية تتطلب عبارة المرور لفك تشفير المحفظة.</translation> - </message> - <message> - <source>Unlock wallet</source> - <translation type="unfinished">فتح قفل المحفظة</translation> - </message> - <message> - <source>Change passphrase</source> - <translation type="unfinished">تغيير عبارة المرور</translation> - </message> - <message> - <source>Confirm wallet encryption</source> - <translation type="unfinished">تأكيد تشفير المحفظة</translation> - </message> - <message> - <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> - <translation type="unfinished">تحذير: إذا قمت بتشفير المحفظة وأضعت الكلمة السرية؛ <b>ستفقد كل البتكوين</b>!</translation> - </message> - <message> - <source>Are you sure you wish to encrypt your wallet?</source> - <translation type="unfinished">هل أنت متأكد من رغبتك في تشفير المحفظة؟</translation> - </message> - <message> - <source>Wallet encrypted</source> - <translation type="unfinished">المحفظة مشفرة</translation> - </message> - <message> - <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation type="unfinished">أدخل عبارة المرور للمحفظة. <br/>الرجاء استخدام عبارة مرور تتكون من <b>عشر خانات عشوائية أو أكثر</b>، أو <b>ثمان كلمات أو أكثر</b>.</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> + <translation type="unfinished">و إستخرج</translation> </message> - <message> - <source>Wallet encryption failed</source> - <translation type="unfinished">فشل تشفير المحفظة</translation> - </message> - <message> - <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">فشل تشفير المحفظة بسبب خطأ داخلي. لم يتم تشفير محفظتك.</translation> - </message> - <message> - <source>The supplied passphrases do not match.</source> - <translation type="unfinished">عبارتي مرور غير متطابقتين.</translation> - </message> - <message> - <source>Wallet unlock failed</source> - <translation type="unfinished">فشل فتح المحفظة</translation> - </message> - <message> - <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">عبارة المرور التي تم إدخالها لفك تشفير المحفظة غير صحيحة.</translation> - </message> - <message> - <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">لقد تم تغيير عبارة المرور بنجاح.</translation> - </message> - <message> - <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished">تحذير: مفتاح الحروف الكبيرة مفعل!</translation> - </message> -</context> -<context> - <name>BanTableModel</name> - <message> - <source>IP/Netmask</source> - <translation type="unfinished">بروتوكول الانترنت/قناع الشبكة</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">Runaway exception</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> <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> @@ -279,10 +21,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">%1 لم يغلق بامان بعد…</translation> </message> <message> - <source>unknown</source> - <translation type="unfinished">غير معروف</translation> - </message> - <message> <source>Amount</source> <translation type="unfinished">القيمة</translation> </message> @@ -443,6 +181,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 جيجابايت</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">محفظة افتراضية</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -528,10 +270,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -644,7 +382,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 behind</source> - <translation type="unfinished">خلف %1</translation> + <translation type="unfinished">متأخر %1</translation> </message> <message> <source>Catching up…</source> @@ -652,11 +390,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">تم توليد الكتلة المستقبلة الأخيرة منذ %1.</translation> + <translation type="unfinished">آخر طابق مستلم تم بناءه قبل %1.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">المعاملات بعد ذلك لن تكون مريئة بعد.</translation> + <translation type="unfinished">المعاملات بعد هذه لن تكون ظاهرة فورا.</translation> </message> <message> <source>Error</source> @@ -672,35 +410,39 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Up to date</source> - <translation type="unfinished">محدث</translation> + <translation type="unfinished">حديث</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">تحميل معاملة بتكوين الموقعة جزئيًا</translation> + <translation type="unfinished">تحميل معاملة بتكوين موقعة جزئيًا (PSBT)</translation> + </message> + <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">تحميل معاملة بتكوين موقعة جزئيا (PSBT) من &الحافظة…</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">تحميل معاملة بتكوين الموقعة جزئيًا من الحافظة</translation> + <translation type="unfinished">تحميل معاملة بتكوين موقعة جزئيًا (PSBT) من الحافظة</translation> </message> <message> <source>Node window</source> - <translation type="unfinished">نافذة Node </translation> + <translation type="unfinished">نافذة النود</translation> </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">افتح وحدة التحكم في تصحيح أخطاء node والتشخيص</translation> + <translation type="unfinished">افتح وحدة التحكم في تصحيح الأخطاء والتشخيص للنود</translation> </message> <message> <source>&Sending addresses</source> - <translation type="unfinished">&عناوين الإرسال</translation> + <translation type="unfinished">&عناوين الإرسال</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&عناوين الإستقبال</translation> + <translation type="unfinished">&عناوين الإستلام</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">افتح عملة بيتكوين: URI</translation> + <translation type="unfinished">افتح رابط بتكوين: URI</translation> </message> <message> <source>Open Wallet</source> @@ -708,7 +450,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Open a wallet</source> - <translation type="unfinished">افتح المحفظة</translation> + <translation type="unfinished">افتح محفظة</translation> </message> <message> <source>Close wallet</source> @@ -726,7 +468,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">إغلاق جميع المحافظ ...</translation> + <translation type="unfinished">إغلاق جميع المحافظ</translation> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> @@ -741,10 +483,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -759,18 +497,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <translation type="unfinished">&نافذة</translation> </message> <message> <source>Zoom</source> @@ -833,108 +566,13 @@ Signing is only possible with addresses of the type 'legacy'.</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>UnitDisplayStatusBarControl</name> - <message> - <source>Unit to show amounts in. Click to select another unit.</source> - <translation type="unfinished">وحدة عرض القيمة. انقر لتغيير وحدة العرض.</translation> - </message> -</context> + </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> @@ -1032,19 +670,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation type="unfinished">يمكن يزيد أو ينقص %1 ساتوشي لكل مدخل.</translation> + <translation type="unfinished">يمكن أن يختلف +/- %1 من ساتوشي(s) لكل إدخال.</translation> </message> <message> <source>(no label)</source> - <translation type="unfinished">( لا وجود لمذكرة)</translation> + <translation type="unfinished">(بدون وسم)</translation> </message> <message> <source>change from %1 (%2)</source> - <translation type="unfinished">تغيير من %1 (%2)</translation> + <translation type="unfinished">تغير من %1 (%2)</translation> </message> <message> <source>(change)</source> - <translation type="unfinished">(غيّر)</translation> + <translation type="unfinished">(تغير)</translation> </message> </context> <context> @@ -1057,11 +695,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <translation type="unfinished">جاري انشاء المحفظة <b>%1</b>... </translation> </message> <message> <source>Create wallet failed</source> - <translation type="unfinished">تعذر إنشاء المحفظة</translation> + <translation type="unfinished">فشل إنشاء المحفظة</translation> </message> <message> <source>Create wallet warning</source> @@ -1071,227 +709,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Can't list signers</source> <translation type="unfinished">لا يمكن سرد الموقعين</translation> </message> - <message> - <source>Too many external signers found</source> - <translation type="unfinished">تم العثور على موقّعين خارجيين كُثر (Too Many)</translation> - </message> -</context> -<context> - <name>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> <context> <name>WalletController</name> <message> - <source>Close wallet</source> - <translation type="unfinished">اغلق المحفظة</translation> - </message> - <message> - <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> - <translation type="unfinished">اغلاق المحفظة لفترة طويلة قد يؤدي الى الاضطرار الى اعادة مزامنة السلسلة بأكملها اذا تم تمكين التلقيم.</translation> - </message> - <message> - <source>Close all wallets</source> - <translation type="unfinished">إغلاق جميع المحافظ ...</translation> - </message> - <message> - <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">هل أنت متأكد من رغبتك في اغلاق جميع المحافظ؟</translation> - </message> -</context> -<context> - <name>CreateWalletDialog</name> - <message> - <source>Create Wallet</source> - <translation type="unfinished">إنشاء محفظة</translation> - </message> - <message> - <source>Wallet Name</source> - <translation type="unfinished">إسم المحفظة</translation> - </message> - <message> - <source>Wallet</source> - <translation type="unfinished">محفظة</translation> - </message> - <message> - <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation type="unfinished">شفر المحفظة. المحفظة سيتم تشفيرها بإستخدام كلمة مرور من إختيارك.</translation> - </message> - <message> - <source>Encrypt Wallet</source> - <translation type="unfinished">تشفير محفظة</translation> - </message> - <message> - <source>Advanced Options</source> - <translation type="unfinished">خيارات متقدمة</translation> - </message> - <message> - <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> - <translation type="unfinished">تعطيل المفاتيح الخاصة لهذه المحفظة. لن تحتوي المحافظ ذات المفاتيح الخاصة المعطلة على مفاتيح خاصة ولا يمكن أن تحتوي على مفتاح HD أو مفاتيح خاصة مستوردة. هذا مثالي لمحافظ مشاهدة فقط فقط.</translation> - </message> - <message> - <source>Disable Private Keys</source> - <translation type="unfinished">إيقاف المفاتيح الخاصة</translation> - </message> - <message> - <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> - <translation type="unfinished">اصنع محفظة فارغة. لا تحتوي المحافظ الفارغة في البداية على مفاتيح خاصة أو نصوص. يمكن استيراد المفاتيح والعناوين الخاصة، أو يمكن تعيين مصدر HD في وقت لاحق.</translation> - </message> - <message> - <source>Make Blank Wallet</source> - <translation type="unfinished">أنشئ محفظة فارغة</translation> - </message> - <message> - <source>Use 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> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation type="unfinished">هل أنت متأكد من رغبتك في إغلاق المحفظة <i>%1</i>؟ </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> <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"> @@ -1300,7 +727,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n GB of space available</numerusform> <numerusform>%n GB of space available</numerusform> <numerusform>%n GB of space available</numerusform> - <numerusform>%n جيجابايت من المساحة متوفرة</numerusform> + <numerusform>%n GB of space available</numerusform> </translation> </message> <message numerus="yes"> @@ -1311,7 +738,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>(of %n GB needed)</numerusform> <numerusform>(of %n GB needed)</numerusform> <numerusform>(of %n GB needed)</numerusform> - <numerusform>(مطلوب %n جيجابايت)</numerusform> + <numerusform>(of %n GB needed)</numerusform> </translation> </message> <message numerus="yes"> @@ -1322,17 +749,9 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>(%n GB needed for full chain)</numerusform> <numerusform>(%n GB needed for full chain)</numerusform> <numerusform>(%n GB needed for full chain)</numerusform> - <numerusform>( مطلوب %n جيجابايت لكامل المتتالية)</numerusform> + <numerusform>(%n GB needed for full chain)</numerusform> </translation> </message> - <message> - <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> - <translation type="unfinished">سيتم تخزين %1 جيجابايت على الأقل من البيانات في هذا الدليل، وستنمو مع الوقت.</translation> - </message> - <message> - <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">سيتم تخزين %1 جيجابايت تقريباً من البيانات في هذا الدليل.</translation> - </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> <extracomment>Explanatory text on the capability of the current prune target.</extracomment> @@ -1345,211 +764,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> </translation> </message> - <message> - <source>%1 will download and store a copy of the Bitcoin block chain.</source> - <translation type="unfinished">سيقوم %1 بتنزيل نسخة من سلسلة كتل بتكوين وتخزينها.</translation> - </message> - <message> - <source>The wallet will also be stored in this directory.</source> - <translation type="unfinished">سوف يتم تخزين المحفظة في هذا الدليل.</translation> - </message> - <message> - <source>Error: Specified data directory "%1" cannot be created.</source> - <translation type="unfinished">خطأ: لا يمكن تكوين دليل بيانات مخصص ل %1</translation> - </message> - <message> - <source>Error</source> - <translation type="unfinished">خطأ</translation> - </message> - <message> - <source>Welcome</source> - <translation type="unfinished">أهلا</translation> - </message> - <message> - <source>Welcome to %1.</source> - <translation type="unfinished"> اهلا بكم في %1</translation> - </message> - <message> - <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> - <translation type="unfinished">بما انه هذه اول مرة لانطلاق هذا البرنامج, فيمكنك ان تختار اين سيخزن %1 بياناته</translation> - </message> - <message> - <source>Limit block chain storage to</source> - <translation type="unfinished">تقييد تخزين سلسلة الكتل إلى</translation> - </message> - <message> - <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation type="unfinished">تتطلب العودة إلى هذا الإعداد إعادة تنزيل سلسلة الكتل بالكامل. من الأسرع تنزيل السلسلة الكاملة أولاً وتقليمها لاحقًا. تعطيل بعض الميزات المتقدمة.</translation> - </message> - <message> - <source> GB</source> - <translation type="unfinished">غيغابايت</translation> - </message> - <message> - <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> - <translation type="unfinished">تُعد هذه المزامنة الأولية أمرًا شاقًا للغاية، وقد تعرض جهاز الكمبيوتر الخاص بك للمشاكل الذي لم يلاحظها أحد سابقًا. في كل مرة تقوم فيها بتشغيل %1، سيتابع التحميل من حيث تم التوقف.</translation> - </message> - <message> - <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source> - <translation type="unfinished">عندما تنقر موافق. %1 سنبدأ التحميل ومعالجة كامل %4 الطوابق المتتالية (%2 GB) بدأً من أوائل العمليات في %3 عندما %4 تم الاطلاق لأول مرة.</translation> - </message> - <message> - <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> - <translation type="unfinished">إذا كنت قد اخترت تقييد تخزين سلسلة الكتل (التجريد)، فيجب تحميل البيانات القديمة ومعالجتها، ولكن سيتم حذفها بعد ذلك للحفاظ على انخفاض استخدام القرص.</translation> - </message> - <message> - <source>Use the default data directory</source> - <translation type="unfinished">استخدام دليل البانات الافتراضي</translation> - </message> - <message> - <source>Use a custom data directory:</source> - <translation type="unfinished">استخدام دليل بيانات مخصص:</translation> - </message> -</context> -<context> - <name>HelpMessageDialog</name> - <message> - <source>version</source> - <translation type="unfinished">النسخة</translation> - </message> - <message> - <source>About %1</source> - <translation type="unfinished">حوالي %1</translation> - </message> - <message> - <source>Command-line options</source> - <translation type="unfinished">خيارات سطر الأوامر</translation> - </message> -</context> -<context> - <name>ShutdownWindow</name> - <message> - <source>%1 is shutting down…</source> - <translation type="unfinished">%1 يتم الإغلاق ...</translation> - </message> - <message> - <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">لا توقف عمل الكمبيوتر حتى تختفي هذه النافذة</translation> - </message> -</context> -<context> - <name>ModalOverlay</name> - <message> - <source>Form</source> - <translation type="unfinished">نمودج</translation> - </message> - <message> - <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation type="unfinished">قد لا تكون المعاملات الأخيرة مرئية بعد، وبالتالي قد يكون رصيد محفظتك غير صحيح. ستكون هذه المعلومات صحيحة بمجرد الانتهاء من محفظتك مع شبكة البيتكوين، كما هو مفصل أدناه.</translation> - </message> - <message> - <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation type="unfinished">لن تقبل الشبكة محاولة إنفاق البتكوين المتأثرة بالمعاملات التي لم يتم عرضها بعد.</translation> - </message> - <message> - <source>Number of blocks left</source> - <translation type="unfinished">عدد الكتل الفاضلة</translation> - </message> - <message> - <source>Unknown…</source> - <translation type="unfinished">غير معروف</translation> - </message> - <message> - <source>calculating…</source> - <translation type="unfinished">جاري الحساب</translation> - </message> - <message> - <source>Last block time</source> - <translation type="unfinished">اخر وقت الكتلة</translation> - </message> - <message> - <source>Progress</source> - <translation type="unfinished">تقدم</translation> - </message> - <message> - <source>Progress increase per hour</source> - <translation type="unfinished">تقدم يزيد بلساعة</translation> - </message> - <message> - <source>Estimated time left until synced</source> - <translation type="unfinished">الوقت المتبقي للمزامنة</translation> - </message> - <message> - <source>Hide</source> - <translation type="unfinished">إخفاء</translation> - </message> - <message> - <source>Esc</source> - <translation type="unfinished">خروج</translation> - </message> - <message> - <source>Unknown. Syncing Headers (%1, %2%)…</source> - <translation type="unfinished">مجهول. مزامنة الرؤوس (%1،%2٪) ...</translation> - </message> - <message> - <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> - <translation type="unfinished">غير معروف. ما قبل مزامنة الرؤوس (%1, %2%)…</translation> - </message> -</context> -<context> - <name>OpenURIDialog</name> - <message> - <source>Open bitcoin URI</source> - <translation type="unfinished">افتح رابط بتكوين (URI)</translation> - </message> - <message> - <source>URI:</source> - <translation type="unfinished">العنوان:</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> <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>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> - <translation type="unfinished">عنوان IP للوكيل (مثل IPv4: 127.0.0.1 / IPv6: ::1)</translation> - </message> - <message> - <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> - <translation type="unfinished">إظهار ما إذا كان وكيل SOCKS5 الافتراضي الموفر تم استخدامه للوصول إلى الأقران عبر نوع الشبكة هذا.</translation> - </message> - <message> - <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> - <translation type="unfinished">التصغير بدلاً من الخروج من التطبيق عند إغلاق النافذة. عند تفعيل هذا الخيار، سيتم إغلاق التطبيق فقط بعد النقر على خروج من القائمة المنسدلة.</translation> - </message> - <message> <source>Options set in this dialog are overridden by the command line:</source> <translation type="unfinished">التفضيلات المعينة عن طريق سطر الأوامر لها أولوية أكبر وتتجاوز التفضيلات المختارة هنا:</translation> </message> @@ -1639,11 +857,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> @@ -2156,867 +1369,47 @@ If you are receiving this error you should request the merchant provide a BIP21 </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">العنوان الناتج طويل جدًا، حاول أن تقلص النص للمذكرة / الرسالة.</translation> - </message> - <message> - <source>Error encoding URI into QR Code.</source> - <translation type="unfinished">خطأ في ترميز العنوان إلى رمز الاستجابة السريع QR.</translation> - </message> - <message> - <source>QR code support not available.</source> - <translation type="unfinished">دعم رمز الاستجابة السريع QR غير متوفر.</translation> - </message> - <message> - <source>Save QR Code</source> - <translation type="unfinished">حفظ رمز الاستجابة السريع QR</translation> - </message> - <message> - <source>PNG Image</source> - <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment> - <translation type="unfinished">صورة PNG</translation> - </message> -</context> -<context> <name>RPCConsole</name> <message> - <source>N/A</source> - <translation type="unfinished">غير معروف</translation> - </message> - <message> - <source>Client version</source> - <translation type="unfinished">اصدار العميل</translation> - </message> - <message> - <source>&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> <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>Version</source> - <translation type="unfinished">الإصدار</translation> - </message> - <message> - <source>Starting Block</source> - <translation type="unfinished">طابق البداية</translation> - </message> - <message> - <source>Synced Headers</source> - <translation type="unfinished">رؤوس مزامنة</translation> - </message> - <message> - <source>Synced Blocks</source> - <translation type="unfinished">طوابق مزامنة</translation> - </message> - <message> - <source>Last Transaction</source> - <translation type="unfinished">آخر عملية</translation> - </message> - <message> - <source>The mapped Autonomous System used for diversifying peer selection.</source> - <translation type="unfinished">النظام التفصيلي المستقل المستخدم لتنويع اختيار الأقران.</translation> - </message> - <message> - <source>Mapped AS</source> - <translation type="unfinished">Mapped AS</translation> - </message> - <message> - <source>Whether we relay addresses to this peer.</source> - <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment> - <translation type="unfinished">توصيل العناوين لهذا القرين أم لا.</translation> - </message> - <message> - <source>Address Relay</source> - <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment> - <translation type="unfinished">توصيل العنوان</translation> - </message> - <message> - <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source> - <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment> - <translation type="unfinished">مجموع العناوين المستلمة والمعالجة من هذا القرين (تستثنى العناوين المسقطة بسبب التقييد الحدي)</translation> - </message> - <message> - <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source> - <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment> - <translation type="unfinished">مجموع العناوين المستلمة والمسقطة من هذا القرين (غير معالجة) بسبب التقييد الحدي.</translation> - </message> - <message> - <source>Addresses Processed</source> - <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment> - <translation type="unfinished">العناوين المعالجة</translation> - </message> - <message> - <source>Addresses Rate-Limited</source> - <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment> - <translation type="unfinished">عناوين مقيدة حديا</translation> - </message> - <message> - <source>User Agent</source> - <translation type="unfinished">وكيل المستخدم</translation> - </message> - <message> <source>Node window</source> - <translation type="unfinished">نافذة Node </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> + <translation type="unfinished">نافذة النود</translation> </message> - <message> - <source>Services</source> - <translation type="unfinished">خدمات</translation> - </message> - <message> - <source>High Bandwidth</source> - <translation type="unfinished">نطاق بيانات عالي</translation> - </message> - <message> - <source>Connection Time</source> - <translation type="unfinished">مدة الاتصال</translation> - </message> - <message> - <source>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>&Open</source> - <translation type="unfinished">&فتح</translation> - </message> - <message> - <source>&Console</source> - <translation type="unfinished">&سطر الأوامر</translation> - </message> - <message> - <source>&Network Traffic</source> - <translation type="unfinished">&حركة الشبكة</translation> - </message> - <message> - <source>Totals</source> - <translation type="unfinished">المجاميع</translation> - </message> - <message> - <source>Debug log file</source> - <translation type="unfinished">ملف سجل تصحيح الأخطاء</translation> - </message> - <message> - <source>Clear console</source> - <translation type="unfinished">مسح الأوامر</translation> - </message> - <message> - <source>In:</source> - <translation type="unfinished">داخل:</translation> - </message> - <message> - <source>Out:</source> - <translation type="unfinished">خارج:</translation> - </message> - <message> - <source>Inbound: initiated by peer</source> - <extracomment>Explanatory text for an inbound peer connection.</extracomment> - <translation type="unfinished">الواردة: بدأها القرين</translation> - </message> - <message> - <source>Outbound Full Relay: default</source> - <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment> - <translation type="unfinished">الموصل الكامل الصادر: افتراضي</translation> - </message> - <message> - <source>Outbound Block Relay: does not relay transactions or addresses</source> - <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment> - <translation type="unfinished">موصل الطابق الصادر: لا يقوم بتوصيل العمليات أو العناوين</translation> - </message> - <message> - <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> - <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment> - <translation type="unfinished">دليل الصادر: مضاف باستخدام نداء الاجراء البعيد RPC %1 أو %2/%3 خيارات الاعداد</translation> - </message> - <message> - <source>Outbound Feeler: short-lived, for testing addresses</source> - <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment> - <translation type="unfinished">أداة التفقد الصادر: قصير الأجل ، لاختبار العناوين</translation> - </message> - <message> - <source>Outbound Address Fetch: short-lived, for soliciting addresses</source> - <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment> - <translation type="unfinished">إحضار العنوان الصادر: قصير الأجل ، لطلب العناوين</translation> - </message> - <message> - <source>we selected the peer for high bandwidth relay</source> - <translation type="unfinished">اخترنا القرين لتوصيل نطاق البيانات العالي</translation> - </message> - <message> - <source>the peer selected us for high bandwidth relay</source> - <translation type="unfinished">القرين اختارنا لتوصيل بيانات ذات نطاق عالي</translation> - </message> - <message> - <source>no high bandwidth relay selected</source> - <translation type="unfinished">لم يتم تحديد موصل للبيانات عالية النطاق</translation> - </message> - <message> - <source>Ctrl++</source> - <extracomment>Main shortcut to increase the RPC console font size.</extracomment> - <translation type="unfinished">Ctrl ++</translation> - </message> - <message> - <source>Ctrl+-</source> - <extracomment>Main shortcut to decrease the RPC console font size.</extracomment> - <translation type="unfinished">Ctrl + -</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>&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>Executing command using "%1" wallet</source> - <translation type="unfinished">تنفيذ الأوامر باستخدام "%1" من المحفظة</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">رسالة اختيارية لإرفاقها بطلب الدفع، والتي سيتم عرضها عند فتح الطلب. ملاحظة: لن يتم إرسال الرسالة مع العملية عبر شبكة البتكوين.</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>Could not unlock wallet.</source> - <translation type="unfinished"> يمكن فتح المحفظة.</translation> - </message> - <message> - <source>Could not generate new %1 address</source> - <translation type="unfinished">تعذر توليد عنوان %1 جديد.</translation> - </message> -</context> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Request payment to …</source> - <translation type="unfinished"> طلب الدفع لـ ...</translation> - </message> - <message> - <source>Address:</source> - <translation type="unfinished">العنوان:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">القيمة:</translation> - </message> - <message> - <source>Label:</source> - <translation type="unfinished">مذكرة:</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">رسالة:</translation> - </message> - <message> <source>Wallet:</source> <translation type="unfinished">المحفظة:</translation> </message> - <message> - <source>Copy &URI</source> - <translation type="unfinished">نسخ &الرابط (URI)</translation> - </message> - <message> - <source>Copy &Address</source> - <translation type="unfinished">نسخ &العنوان</translation> - </message> - <message> - <source>&Verify</source> - <translation type="unfinished">&تحقق</translation> - </message> - <message> - <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">تحقق من العنوان على شاشة المحفظة الخارجية</translation> - </message> - <message> - <source>&Save Image…</source> - <translation type="unfinished">&احفظ الصورة...</translation> - </message> - <message> - <source>Payment information</source> - <translation type="unfinished">معلومات الدفع</translation> - </message> - <message> - <source>Request payment to %1</source> - <translation type="unfinished">طلب الدفعة إلى %1</translation> - </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> - <source>Date</source> - <translation type="unfinished">التاريخ</translation> - </message> - <message> - <source>Label</source> - <translation type="unfinished">المذكرة</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">رسالة </translation> - </message> - <message> <source>(no label)</source> - <translation type="unfinished">( لا وجود لمذكرة)</translation> - </message> - <message> - <source>(no message)</source> - <translation type="unfinished">( لا رسائل )</translation> + <translation type="unfinished">(بدون وسم)</translation> </message> - <message> - <source>(no amount requested)</source> - <translation type="unfinished">(لا يوجد قيمة مطلوبة)</translation> - </message> - <message> - <source>Requested</source> - <translation type="unfinished">تم الطلب</translation> - </message> -</context> + </context> <context> <name>SendCoinsDialog</name> <message> - <source>Send Coins</source> - <translation type="unfinished">إرسال وحدات البتكوين</translation> - </message> - <message> - <source>Coin Control Features</source> - <translation type="unfinished">ميزات التحكم بوحدات البتكوين</translation> - </message> - <message> - <source>automatically selected</source> - <translation type="unfinished">اختيار تلقائيا</translation> - </message> - <message> - <source>Insufficient funds!</source> - <translation type="unfinished">الرصيد غير كافي!</translation> - </message> - <message> - <source>Quantity:</source> - <translation type="unfinished">الكمية:</translation> - </message> - <message> - <source>Bytes:</source> - <translation type="unfinished">بايت:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">القيمة:</translation> - </message> - <message> - <source>Fee:</source> - <translation type="unfinished">الرسوم:</translation> - </message> - <message> - <source>After Fee:</source> - <translation type="unfinished">بعد الرسوم:</translation> - </message> - <message> - <source>Change:</source> - <translation type="unfinished">تعديل:</translation> - </message> - <message> - <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> - <translation type="unfinished">إذا تم تنشيط هذا، ولكن عنوان الفكة فارغ أو غير صالح، فسيتم إرسال الفكة إلى عنوان مولّد حديثًا.</translation> - </message> - <message> - <source>Custom change address</source> - <translation type="unfinished">تغيير عنوان الفكة</translation> - </message> - <message> - <source>Transaction Fee:</source> - <translation type="unfinished">رسوم المعاملة:</translation> - </message> - <message> - <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> - <translation type="unfinished">يمكن أن يؤدي استخدام الرسوم الاحتياطية إلى إرسال معاملة تستغرق عدة ساعات أو أيام (أو أبدًا) للتأكيد. ضع في اعتبارك اختيار الرسوم يدويًا أو انتظر حتى تتحقق من صحة المتتالية الكاملة.</translation> - </message> - <message> - <source>Warning: Fee estimation is currently not possible.</source> - <translation type="unfinished">تحذير: تقدير الرسوم غير ممكن في الوقت الحالي.</translation> - </message> - <message> - <source>per kilobyte</source> - <translation type="unfinished">لكل كيلوبايت</translation> - </message> - <message> - <source>Hide</source> - <translation type="unfinished">إخفاء</translation> - </message> - <message> - <source>Recommended:</source> - <translation type="unfinished">موصى به:</translation> - </message> - <message> - <source>Custom:</source> - <translation type="unfinished">تخصيص:</translation> - </message> - <message> - <source>Send to multiple recipients at once</source> - <translation type="unfinished">إرسال إلى عدة مستلمين في وقت واحد</translation> - </message> - <message> - <source>Add &Recipient</source> - <translation type="unfinished">أضافة &مستلم</translation> - </message> - <message> - <source>Clear all fields of the form.</source> - <translation type="unfinished">مسح كل الحقول من النموذج.</translation> - </message> - <message> - <source>Inputs…</source> - <translation type="unfinished">المدخلات...</translation> - </message> - <message> - <source>Choose…</source> - <translation type="unfinished">اختيار...</translation> - </message> - <message> - <source>Hide transaction fee settings</source> - <translation type="unfinished">اخفاء اعدادات رسوم المعاملة</translation> - </message> - <message> - <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. - -Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">حدد الرسوم المخصصة لكل كيلوبايت (١٠٠٠ بايت) من حجم العملية الافتراضي. - -ملاحظة: بما أن الرسوم تحتسب لكل بايت، معدل الرسوم ل “ ١٠٠ ساتوشي لكل كيلوبايت افتراضي” لعملية بحجم ٥٠٠ بايت افتراضي (نصف كيلوبايت افتراضي) ستكون ٥٠ ساتوشي فقط.</translation> - </message> - <message> - <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> - <translation type="unfinished">قد يفرض المعدنون والأنواد الموصلة حدا أدنى للرسوم عندما يكون عدد العمليات قليل نسبة لسعة الطوابق. يمكنك دفع الحد الأدنى ولكن كن على دراية بأن العملية قد لا تنفذ في حالة أن الطلب على عمليات البتكوين فاق قدرة الشبكة على المعالجة.</translation> - </message> - <message> - <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation type="unfinished">الرسوم القليلة جدا قد تؤدي الى عملية لا تتأكد أبدا (اقرأ التلميح).</translation> - </message> - <message> - <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> - <translation type="unfinished">(الرسوم الذكية غير مهيأة بعد. عادة يتطلب عدة طوابق…)</translation> - </message> - <message> - <source>Confirmation time target:</source> - <translation type="unfinished">هدف وقت التأكيد:</translation> - </message> - <message> - <source>Enable Replace-By-Fee</source> - <translation type="unfinished">تفعيل الإستبدال بواسطة الرسوم</translation> - </message> - <message> - <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> - <translation type="unfinished">يمكنك زيادة رسوم المعاملة بعد إرسالها عند تفعيل الاستبدال بواسطة الرسوم (BIP-125). نوصي بوضع رسوم أعلى اذا لم يتم التفعيل لتفادي مخاطر تأخير العملية.</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">مسح الكل</translation> - </message> - <message> - <source>Balance:</source> - <translation type="unfinished">الرصيد:</translation> - </message> - <message> - <source>Confirm the send action</source> - <translation type="unfinished">تأكيد الإرسال</translation> - </message> - <message> - <source>S&end</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>%1 (%2 blocks)</source> - <translation type="unfinished">%1 (%2 طوابق)</translation> - </message> - <message> - <source>Sign on device</source> - <extracomment>"device" usually means a hardware wallet.</extracomment> - <translation type="unfinished">جهاز التوقيع</translation> - </message> - <message> - <source>Connect your hardware wallet first.</source> - <translation type="unfinished">قم بتوصيل المحفظة الخارجية أولا.</translation> - </message> - <message> - <source>Set external signer script path in Options -> 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> - <message> - <source>%1 to '%2'</source> - <translation type="unfinished">%1 الى "%2"</translation> - </message> - <message> - <source>%1 to %2</source> - <translation type="unfinished">%1 الى %2</translation> - </message> - <message> - <source>To review recipient list click "Show Details…"</source> - <translation type="unfinished">لمراجعة قائمة المستلمين انقر على “عرض التفاصيل…”</translation> - </message> - <message> - <source>Sign failed</source> - <translation type="unfinished">فشل التوقيع</translation> - </message> - <message> - <source>External signer not found</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">لم يتم العثور على موقّع خارجي</translation> - </message> - <message> - <source>External signer failure</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">فشل الموقّع الخارجي</translation> - </message> - <message> - <source>Save Transaction Data</source> - <translation type="unfinished">حفظ بيانات العملية</translation> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation type="unfinished">أنشئ معاملة بتكوين موقعة جزئيا (PSBT) للاستعمال مع محفظة %1 غير متصلة بالشبكة مثلا، أو محفظة خارجية متوافقة مع الـ(PSBT).</translation> </message> <message> <source>Partially Signed Transaction (Binary)</source> @@ -3024,90 +1417,9 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">معاملة موقعة جزئيًا (ثنائي)</translation> </message> <message> - <source>PSBT saved</source> - <extracomment>Popup message when a PSBT has been saved to a file</extracomment> - <translation type="unfinished">تم حفظ PSBT</translation> - </message> - <message> - <source>External balance:</source> - <translation type="unfinished">رصيد خارجي </translation> - </message> - <message> <source>or</source> <translation type="unfinished">أو</translation> </message> - <message> - <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> - <translation type="unfinished">يمكنك زيادة الرسوم لاحقًا (الاستبدال بواسطة الرسوم، BIP-125 مفعل).</translation> - </message> - <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> - <translation type="unfinished">رجاء، راجع معاملتك. هذا ينشئ معاملة بتكوين موقعة جزئيا (PSBT) ويمكنك حفظها أو نسخها و التوقيع مع محفظة %1 غير متصلة بالشبكة، أو محفظة خارجية متوافقة مع الـPSBT.</translation> - </message> - <message> - <source>Do you want to create this transaction?</source> - <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment> - <translation type="unfinished">هل تريد انشاء هذه المعاملة؟</translation> - </message> - <message> - <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment> - <translation type="unfinished">رجاء، راجع معاملتك.تستطيع انشاء وارسال هذه العملية أو انشاء معاملة بتكوين موقعة جزئيا (PSBT) ويمكنك حفظها أو نسخها و التوقيع مع محفظة %1 غير متصلة بالشبكة، أو محفظة خارجية متوافقة مع الـPSBT.</translation> - </message> - <message> - <source>Please, review your transaction.</source> - <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment> - <translation type="unfinished">رجاء، راجع معاملتك.</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">رسوم العملية</translation> - </message> - <message> - <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation type="unfinished">الاستبدال بواسطة الرسوم، BIP-125 غير مفعلة.</translation> - </message> - <message> - <source>Total Amount</source> - <translation type="unfinished">القيمة الإجمالية</translation> - </message> - <message> - <source>Confirm send coins</source> - <translation type="unfinished">تأكيد ارسال وحدات البتكوين</translation> - </message> - <message> - <source>Watch-only balance:</source> - <translation type="unfinished">رصيد المراقبة:</translation> - </message> - <message> - <source>The recipient address is not valid. Please recheck.</source> - <translation type="unfinished">عنوان المستلم غير صالح. يرجى مراجعة العنوان.</translation> - </message> - <message> - <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">القيمة المدفوعة يجب ان تكون اكبر من 0.</translation> - </message> - <message> - <source>The amount exceeds your balance.</source> - <translation type="unfinished">القيمة تتجاوز رصيدك.</translation> - </message> - <message> - <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation type="unfinished">المجموع يتجاوز رصيدك عندما يتم اضافة %1 رسوم العملية</translation> - </message> - <message> - <source>Duplicate address found: addresses should only be used once each.</source> - <translation type="unfinished">تم العثور على عنوان مكرر: من الأفضل استخدام العناوين مرة واحدة فقط.</translation> - </message> - <message> - <source>Transaction creation failed!</source> - <translation type="unfinished">تعذر إنشاء المعاملة!</translation> - </message> - <message> - <source>A fee higher than %1 is considered an absurdly high fee.</source> - <translation type="unfinished">تعتبر الرسوم الأعلى من %1 رسوماً باهظة.</translation> - </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> @@ -3116,333 +1428,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> - <numerusform>الوقت التقديري للنفاذ خلال %n طوابق.</numerusform> + <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> </translation> </message> <message> - <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished">تحذير: عنوان بتكوين غير صالح</translation> - </message> - <message> - <source>Warning: Unknown change address</source> - <translation type="unfinished">تحذير: عنوان الفكة غير معروف</translation> - </message> - <message> - <source>Confirm custom change address</source> - <translation type="unfinished">تأكيد تغيير العنوان الفكة</translation> - </message> - <message> - <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> - <translation type="unfinished">العنوان الذي قمت بتحديده للفكة ليس جزءا من هذه المحفظة. بعض أو جميع الأموال في محفظتك قد يتم إرسالها لهذا العنوان. هل أنت متأكد؟</translation> - </message> - <message> <source>(no label)</source> - <translation type="unfinished">( لا وجود لمذكرة)</translation> - </message> -</context> -<context> - <name>SendCoinsEntry</name> - <message> - <source>A&mount:</source> - <translation type="unfinished">&القيمة</translation> - </message> - <message> - <source>Pay &To:</source> - <translation type="unfinished">ادفع &الى :</translation> - </message> - <message> - <source>&Label:</source> - <translation type="unfinished">&مذكرة :</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">اختر عنوانا تم استخدامه سابقا</translation> - </message> - <message> - <source>The Bitcoin address to send the payment to</source> - <translation type="unfinished">عنوان البتكوين لارسال الدفعة له</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">ألصق العنوان من الحافظة</translation> - </message> - <message> - <source>Remove this entry</source> - <translation type="unfinished">ازل هذا المدخل</translation> - </message> - <message> - <source>The amount to send in the selected unit</source> - <translation type="unfinished">القيمة للإرسال في الوحدة المحددة</translation> - </message> - <message> - <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source> - <translation type="unfinished">سيتم خصم الرسوم من المبلغ الذي يتم إرساله. لذا سوف يتلقى المستلم قيمة أقل من البتكوين المدخل في حقل القيمة. في حالة تحديد عدة مستلمين، يتم تقسيم الرسوم بالتساوي.</translation> - </message> - <message> - <source>S&ubtract fee from amount</source> - <translation type="unfinished">ط&رح الرسوم من القيمة</translation> - </message> - <message> - <source>Use available balance</source> - <translation type="unfinished">استخدام الرصيد المتاح</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">رسالة:</translation> - </message> - <message> - <source>Enter a label for this address to add it to the list of used addresses</source> - <translation type="unfinished">أدخل مذكرة لهذا العنوان لإضافته إلى قائمة العناوين المستخدمة</translation> - </message> - <message> - <source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source> - <translation type="unfinished">الرسالة يتم إرفاقها مع البتكوين: الرابط سيتم تخزينه مع العملية لك للرجوع إليه. ملاحظة: لن يتم إرسال هذه الرسالة عبر شبكة البتكوين.</translation> - </message> -</context> -<context> - <name>SendConfirmationDialog</name> - <message> - <source>Send</source> - <translation type="unfinished">إرسال</translation> - </message> - <message> - <source>Create Unsigned</source> - <translation type="unfinished">إنشاء غير موقع</translation> - </message> -</context> -<context> - <name>SignVerifyMessageDialog</name> - <message> - <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">التواقيع - التوقيع / تحقق من الرسالة</translation> - </message> - <message> - <source>&Sign Message</source> - <translation type="unfinished">&توقيع الرسالة</translation> - </message> - <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">تستطيع توقيع رسائل/اتفاقيات من عناوينك لإثبات أنه بإمكانك استلام بتكوين مرسل لهذه العناوين. كن حذرا من توقيع أي شيء غامض أو عشوائي، هجمات التصيد قد تحاول خداعك وانتحال هويتك. وقع البيانات الواضحة بالكامل والتي توافق عليها فقط.</translation> - </message> - <message> - <source>The Bitcoin address to sign the message with</source> - <translation type="unfinished">عنوان البتكوين لتوقيع الرسالة منه</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">اختر عنوانا تم استخدامه سابقا</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">ألصق العنوان من الحافظة</translation> - </message> - <message> - <source>Enter the message you want to sign here</source> - <translation type="unfinished">ادخل الرسالة التي تريد توقيعها هنا</translation> - </message> - <message> - <source>Signature</source> - <translation type="unfinished">التوقيع</translation> - </message> - <message> - <source>Copy the current signature to the system clipboard</source> - <translation type="unfinished">نسخ التوقيع الحالي إلى حافظة النظام</translation> - </message> - <message> - <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">وقع الرسالة لتثبت انك تملك عنوان البتكوين هذا</translation> - </message> - <message> - <source>Sign &Message</source> - <translation type="unfinished">توقيع &الرسالة</translation> - </message> - <message> - <source>Reset all sign message fields</source> - <translation type="unfinished">إعادة تعيين كافة حقول توقيع الرسالة</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">مسح الكل</translation> - </message> - <message> - <source>&Verify Message</source> - <translation type="unfinished">&تحقق من الرسالة</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">أدخل عنوان المتلقي، راسل (تأكد من نسخ فواصل الأسطر، الفراغات، الخ.. تماما) والتوقيع أسفله لتأكيد الرسالة. كن حذرا من عدم قراءة داخل التوقيع أكثر مما هو موقع بالرسالة نفسها، لتجنب خداعك بهجوم man-in-the-middle. لاحظ أنه هذا لاثبات أن الجهة الموقعة تستقبل مع العنوان فقط، لا تستطيع اثبات الارسال لأي معاملة.</translation> - </message> - <message> - <source>The Bitcoin address the message was signed with</source> - <translation type="unfinished">عنوان البتكوين الذي تم توقيع الرسالة منه</translation> - </message> - <message> - <source>The signed message to verify</source> - <translation type="unfinished">الرسالة الموقعة للتحقق.</translation> - </message> - <message> - <source>The signature given when the message was signed</source> - <translation type="unfinished">التوقيع المعطى عند توقيع الرسالة</translation> - </message> - <message> - <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation type="unfinished">تحقق من الرسالة للتأكد أنه تم توقيعها من عنوان البتكوين المحدد</translation> - </message> - <message> - <source>Verify &Message</source> - <translation type="unfinished">تحقق من &الرسالة</translation> - </message> - <message> - <source>Reset all verify message fields</source> - <translation type="unfinished">إعادة تعيين جميع حقول التحقق من الرسالة</translation> - </message> - <message> - <source>Click "Sign Message" to generate signature</source> - <translation type="unfinished">انقر "توقيع الرسالة" لانشاء التوقيع</translation> - </message> - <message> - <source>The entered address is invalid.</source> - <translation type="unfinished">العنوان المدخل غير صالح</translation> - </message> - <message> - <source>Please check the address and try again.</source> - <translation type="unfinished">الرجاء التأكد من العنوان والمحاولة مرة اخرى.</translation> - </message> - <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">العنوان المدخل لا يشير الى مفتاح.</translation> - </message> - <message> - <source>Wallet unlock was cancelled.</source> - <translation type="unfinished">تم الغاء عملية فتح المحفظة.</translation> - </message> - <message> - <source>No error</source> - <translation type="unfinished">لا يوجد خطأ</translation> - </message> - <message> - <source>Private key for the entered address is not available.</source> - <translation type="unfinished">المفتاح الخاص للعنوان المدخل غير متاح.</translation> - </message> - <message> - <source>Message signing failed.</source> - <translation type="unfinished">فشل توقيع الرسالة.</translation> - </message> - <message> - <source>Message signed.</source> - <translation type="unfinished">الرسالة موقعة.</translation> - </message> - <message> - <source>The signature could not be decoded.</source> - <translation type="unfinished">لا يمكن فك تشفير التوقيع.</translation> - </message> - <message> - <source>Please check the signature and try again.</source> - <translation type="unfinished">فضلا تاكد من التوقيع وحاول مرة اخرى</translation> - </message> - <message> - <source>The signature did not match the message digest.</source> - <translation type="unfinished">لم يتطابق التوقيع مع ملخص الرسالة.</translation> - </message> - <message> - <source>Message verification failed.</source> - <translation type="unfinished">فشلت عملية التأكد من الرسالة.</translation> - </message> - <message> - <source>Message verified.</source> - <translation type="unfinished">تم تأكيد الرسالة.</translation> - </message> -</context> -<context> - <name>SplashScreen</name> - <message> - <source>(press q to shutdown and continue later)</source> - <translation type="unfinished">(انقر q للاغلاق والمواصلة لاحقا)</translation> - </message> - <message> - <source>press q to shutdown</source> - <translation type="unfinished">انقر q للاغلاق</translation> - </message> -</context> -<context> - <name>TrafficGraphWidget</name> - <message> - <source>kB/s</source> - <translation type="unfinished">كيلوبايت/ثانية</translation> + <translation type="unfinished">(بدون وسم)</translation> </message> </context> <context> <name>TransactionDesc</name> - <message> - <source>conflicted with a transaction with %1 confirmations</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment> - <translation type="unfinished">تعارضت مع عملية أخرى تم تأكيدها %1</translation> - </message> - <message> - <source>0/unconfirmed, in memory pool</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment> - <translation type="unfinished">0/غير مؤكدة، في تجمع الذاكرة</translation> - </message> - <message> - <source>0/unconfirmed, not in memory pool</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment> - <translation type="unfinished">0/غير مؤكدة، ليست في تجمع الذاكرة</translation> - </message> - <message> - <source>abandoned</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment> - <translation type="unfinished">مهجور</translation> - </message> - <message> - <source>%1/unconfirmed</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment> - <translation type="unfinished">غير مؤكدة/%1</translation> - </message> - <message> - <source>%1 confirmations</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment> - <translation type="unfinished">تأكيد %1</translation> - </message> - <message> - <source>Status</source> - <translation type="unfinished">الحالة.</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">التاريخ</translation> - </message> - <message> - <source>Source</source> - <translation type="unfinished">المصدر</translation> - </message> - <message> - <source>Generated</source> - <translation type="unfinished">مُصدر</translation> - </message> - <message> - <source>From</source> - <translation type="unfinished">من</translation> - </message> - <message> - <source>unknown</source> - <translation type="unfinished">غير معروف</translation> - </message> - <message> - <source>To</source> - <translation type="unfinished">الى</translation> - </message> - <message> - <source>own address</source> - <translation type="unfinished">عنوانه</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">مراقبة فقط</translation> - </message> - <message> - <source>label</source> - <translation type="unfinished">مذكرة</translation> - </message> <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> @@ -3455,348 +1450,35 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </translation> </message> <message> - <source>not accepted</source> - <translation type="unfinished">غير مقبولة</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">رسوم العملية</translation> - </message> - <message> - <source>Net amount</source> - <translation type="unfinished">صافي القيمة</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">رسالة </translation> - </message> - <message> - <source>Comment</source> - <translation type="unfinished">تعليق</translation> - </message> - <message> - <source>Transaction ID</source> - <translation type="unfinished">رقم العملية</translation> - </message> - <message> - <source>Transaction total size</source> - <translation type="unfinished">الحجم الكلي للعملية</translation> - </message> - <message> - <source>Transaction virtual size</source> - <translation type="unfinished">حجم المعاملة الافتراضي</translation> - </message> - <message> - <source>Output index</source> - <translation type="unfinished">مؤشر المخرجات</translation> - </message> - <message> - <source>Merchant</source> - <translation type="unfinished">تاجر</translation> - </message> - <message> - <source>Debug information</source> - <translation type="unfinished">معلومات التصحيح</translation> - </message> - <message> - <source>Transaction</source> - <translation type="unfinished">عملية</translation> - </message> - <message> - <source>Inputs</source> - <translation type="unfinished">المدخلات</translation> + <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> + <translation type="unfinished">النقود المولدة يجب أن تنضج %1 من الكتل قبل أن يكون بالإمكان إنفاقهم. عندما تولد أنت هذه الكتلة، تكون قد بثت الى الشبكة ليتم اضافتها لسلسلة الكتل. اذا فشلت في الدخول الى السلسلة، حالتها سوف تتغير الى "غير مقبولة" ولن تكون قابلة للإنفاق. هذا قد يحدث أحيانا اذا قامت عقدة أخرى بتوليد كتلة خلال ثوان معدودة من قيامك بنفس العملية.</translation> </message> <message> <source>Amount</source> <translation type="unfinished">القيمة</translation> </message> - <message> - <source>true</source> - <translation type="unfinished">صحيح</translation> - </message> - <message> - <source>false</source> - <translation type="unfinished">خاطئ</translation> - </message> -</context> -<context> - <name>TransactionDescDialog</name> - <message> - <source>This pane shows a detailed description of the transaction</source> - <translation type="unfinished">يبين هذا الجزء وصفا مفصلا لهده المعاملة</translation> - </message> - <message> - <source>Details for %1</source> - <translation type="unfinished">تفاصيل عن %1</translation> - </message> -</context> + </context> <context> <name>TransactionTableModel</name> <message> - <source>Date</source> - <translation type="unfinished">التاريخ</translation> - </message> - <message> <source>Type</source> <translation type="unfinished">النوع</translation> </message> <message> - <source>Label</source> - <translation type="unfinished">المذكرة</translation> - </message> - <message> - <source>Unconfirmed</source> - <translation type="unfinished">غير مؤكد</translation> - </message> - <message> - <source>Abandoned</source> - <translation type="unfinished">مهجور</translation> - </message> - <message> - <source>Confirming (%1 of %2 recommended confirmations)</source> - <translation type="unfinished">قيد التأكيد (%1 من %2 تأكيد موصى به)</translation> - </message> - <message> - <source>Confirmed (%1 confirmations)</source> - <translation type="unfinished">نافذ (%1 تأكيدات)</translation> - </message> - <message> - <source>Conflicted</source> - <translation type="unfinished">يتعارض</translation> - </message> - <message> - <source>Immature (%1 confirmations, will be available after %2)</source> - <translation type="unfinished">غير ناضجة (تأكيدات %1 ، ستكون متوفرة بعد %2)</translation> - </message> - <message> - <source>Generated but not accepted</source> - <translation type="unfinished">ولّدت ولكن لم تقبل</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">استلم في</translation> - </message> - <message> - <source>Received from</source> - <translation type="unfinished">استلم من</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">أرسل إلى</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">معدّن</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">مراقبة فقط</translation> - </message> - <message> - <source>(n/a)</source> - <translation type="unfinished">غير متوفر</translation> - </message> - <message> <source>(no label)</source> - <translation type="unfinished">( لا وجود لمذكرة)</translation> + <translation type="unfinished">(بدون وسم)</translation> </message> - <message> - <source>Transaction status. Hover over this field to show number of confirmations.</source> - <translation type="unfinished">حالة التحويل. مرر فوق هذا الحقل لعرض عدد التأكيدات.</translation> - </message> - <message> - <source>Date and time that the transaction was received.</source> - <translation type="unfinished">التاريخ والوقت الذي تم فيه استلام العملية.</translation> - </message> - <message> - <source>Type of transaction.</source> - <translation type="unfinished">نوع العملية.</translation> - </message> - <message> - <source>Whether or not a watch-only address is involved in this transaction.</source> - <translation type="unfinished">إذا كان عنوان المراقبة له علاقة بهذه العملية أم لا.</translation> - </message> - <message> - <source>User-defined intent/purpose of the transaction.</source> - <translation type="unfinished">سبب تنفيذ العملية للمستخدم.</translation> - </message> - <message> - <source>Amount removed from or added to balance.</source> - <translation type="unfinished">القيمة المضافة أو المزالة من الرصيد.</translation> - </message> -</context> + </context> <context> <name>TransactionView</name> <message> - <source>All</source> - <translation type="unfinished">الكل</translation> - </message> - <message> - <source>Today</source> - <translation type="unfinished">اليوم</translation> - </message> - <message> - <source>This week</source> - <translation type="unfinished">هذا الاسبوع</translation> - </message> - <message> - <source>This month</source> - <translation type="unfinished">هذا الشهر</translation> - </message> - <message> - <source>Last month</source> - <translation type="unfinished">الشهر الماضي</translation> - </message> - <message> - <source>This year</source> - <translation type="unfinished">هذا العام</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">استلم في</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">أرسل إلى</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">معدّن</translation> - </message> - <message> - <source>Other</source> - <translation type="unfinished">أخرى</translation> - </message> - <message> - <source>Enter address, transaction id, or label to search</source> - <translation type="unfinished">أدخل العنوان أو معرف المعاملة أو المذكرة للبحث</translation> - </message> - <message> - <source>Min amount</source> - <translation type="unfinished">الحد الأدنى</translation> - </message> - <message> - <source>Range…</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</source> - <translation type="unfinished">نسخ &معرف العملية</translation> - </message> - <message> - <source>Copy &raw transaction</source> - <translation type="unfinished">نسخ &النص الأصلي للعملية</translation> - </message> - <message> - <source>Copy full transaction &details</source> - <translation type="unfinished">نسخ كامل &تفاصيل العملية</translation> - </message> - <message> - <source>&Show transaction details</source> - <translation type="unfinished">& اظهر تفاصيل العملية</translation> - </message> - <message> - <source>Increase transaction &fee</source> - <translation type="unfinished">زيادة العملية و الرسوم</translation> - </message> - <message> - <source>A&bandon transaction</source> - <translation type="unfinished">ال&تخلي عن العملية</translation> - </message> - <message> - <source>&Edit address label</source> - <translation type="unfinished">و تحرير تسمية العنوان </translation> - </message> - <message> - <source>Show in %1</source> - <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment> - <translation type="unfinished">عرض في %1</translation> - </message> - <message> - <source>Export Transaction History</source> - <translation type="unfinished">تصدير سجل العمليات التاريخي</translation> - </message> - <message> - <source>Comma separated file</source> - <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment> - <translation type="unfinished">ملف القيم المفصولة بفاصلة</translation> - </message> - <message> - <source>Confirmed</source> - <translation type="unfinished">نافذ</translation> - </message> - <message> - <source>Watch-only</source> - <translation type="unfinished">مراقبة فقط</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">التاريخ</translation> - </message> - <message> <source>Type</source> <translation type="unfinished">النوع</translation> </message> - <message> - <source>Label</source> - <translation type="unfinished">المذكرة</translation> - </message> - <message> - <source>Address</source> - <translation type="unfinished">العنوان</translation> - </message> - <message> - <source>ID</source> - <translation type="unfinished">المعرف</translation> - </message> - <message> - <source>Exporting Failed</source> - <translation type="unfinished">فشل التصدير</translation> - </message> - <message> - <source>There was an error trying to save the transaction history to %1.</source> - <translation type="unfinished">حدث خطأ أثناء محاولة حفظ سجل العملية التاريخي في %1.</translation> - </message> - <message> - <source>Exporting Successful</source> - <translation type="unfinished">نجح التصدير</translation> - </message> - <message> - <source>The transaction history was successfully saved to %1.</source> - <translation type="unfinished">تم حفظ سجل العملية التاريخي بنجاح في %1.</translation> - </message> - <message> - <source>Range:</source> - <translation type="unfinished">المدى:</translation> - </message> - <message> - <source>to</source> - <translation type="unfinished">إلى</translation> - </message> -</context> + </context> <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">لم يتم تحميل أي محافظ. -اذهب الى ملف > فتح محفظة لتحميل محفظة. -- أو -</translation> - </message> - <message> <source>Create a new wallet</source> <translation type="unfinished">إنشاء محفظة جديدة</translation> </message> @@ -3804,100 +1486,12 @@ Go to File > Open Wallet to load a wallet. <source>Error</source> <translation type="unfinished">خطأ</translation> </message> - <message> - <source>Unable to decode PSBT from clipboard (invalid base64)</source> - <translation type="unfinished">تعذر قراءة وتحليل ترميز PSBT من الحافظة (base64 غير صالح)</translation> - </message> - <message> - <source>Load Transaction Data</source> - <translation type="unfinished">تحميل بيانات العملية</translation> - </message> - <message> - <source>Partially Signed Transaction (*.psbt)</source> - <translation type="unfinished">معاملة موقعة جزئيا (psbt.*)</translation> - </message> - <message> - <source>PSBT file must be smaller than 100 MiB</source> - <translation type="unfinished">ملف PSBT يجب أن يكون أصغر من 100 ميجابايت</translation> - </message> - <message> - <source>Unable to decode PSBT</source> - <translation type="unfinished">غير قادر على قراءة وتحليل ترميز PSBT</translation> - </message> -</context> -<context> - <name>WalletModel</name> - <message> - <source>Send Coins</source> - <translation type="unfinished">إرسال وحدات البتكوين</translation> - </message> - <message> - <source>Fee bump error</source> - <translation type="unfinished">خطأ في زيادة الرسوم</translation> - </message> - <message> - <source>Increasing transaction fee failed</source> - <translation type="unfinished">فشل في زيادة رسوم العملية</translation> - </message> - <message> - <source>Do you want to increase the fee?</source> - <extracomment>Asks a user if they would like to manually increase the fee of a transaction that has already been created.</extracomment> - <translation type="unfinished">هل تريد زيادة الرسوم؟</translation> - </message> - <message> - <source>Current fee:</source> - <translation type="unfinished">الرسوم الان:</translation> - </message> - <message> - <source>Increase:</source> - <translation type="unfinished">زيادة:</translation> - </message> - <message> - <source>New fee:</source> - <translation type="unfinished">رسم جديد:</translation> - </message> - <message> - <source>Confirm fee bump</source> - <translation type="unfinished">تأكيد زيادة الرسوم</translation> - </message> - <message> - <source>Can't draft transaction.</source> - <translation type="unfinished">لا يمكن صياغة المعاملة</translation> - </message> - <message> - <source>PSBT copied</source> - <translation type="unfinished">تم نسخ PSBT</translation> - </message> - <message> - <source>Can't sign transaction.</source> - <translation type="unfinished">لا يمكن توقيع المعاملة.</translation> - </message> - <message> - <source>Could not commit transaction</source> - <translation type="unfinished">لا يمكن تنفيذ المعاملة</translation> - </message> - <message> - <source>Can't display address</source> - <translation type="unfinished">لا يمكن عرض العنوان </translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">محفظة افتراضية</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> <source>&Export</source> - <translation type="unfinished">&تصدير</translation> - </message> - <message> - <source>Export the data in the current tab to a file</source> - <translation type="unfinished">صدّر البيانات في التبويب الحالي الى ملف</translation> - </message> - <message> - <source>Backup Wallet</source> - <translation type="unfinished">انسخ المحفظة احتياطيا</translation> + <translation type="unfinished">و إستخرج</translation> </message> <message> <source>Wallet Data</source> @@ -3905,22 +1499,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">بيانات المحفظة</translation> </message> <message> - <source>Backup Failed</source> - <translation type="unfinished">تعذر النسخ الاحتياطي</translation> - </message> - <message> - <source>There was an error trying to save the wallet data to %1.</source> - <translation type="unfinished">لقد حدث خطأ أثناء محاولة حفظ بيانات المحفظة الى %1.</translation> - </message> - <message> - <source>Backup Successful</source> - <translation type="unfinished">نجح النسخ الاحتياطي</translation> - </message> - <message> - <source>The wallet data was successfully saved to %1.</source> - <translation type="unfinished">تم حفظ بيانات المحفظة بنجاح إلى %1.</translation> - </message> - <message> <source>Cancel</source> <translation type="unfinished">إلغاء</translation> </message> @@ -3928,456 +1506,12 @@ Go to File > Open Wallet to load a wallet. <context> <name>bitcoin-core</name> <message> - <source>The %s developers</source> - <translation type="unfinished">%s المبرمجون</translation> - </message> - <message> - <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> - <translation type="unfinished">%s مشكل. حاول استخدام أداة محفظة البتكوين للاصلاح أو استعادة نسخة احتياطية.</translation> - </message> - <message> - <source>%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فشل في التحقق من صحة حالة اللقطة -assumeutxo. يشير هذا إلى وجود مشكلة في الأجهزة، أو خطأ في البرنامج، أو تعديل سيء في البرنامج يسمح بتحميل لقطة غير صالحة. ونتيجة لذلك، سيتم إيقاف تشغيل العقدة والتوقف عن استخدام أي حالة تم إنشاؤها في اللقطة، مما يؤدي إلى إعادة ضبط ارتفاع السلسلة من%dإلى %d. في عملية إعادة التشغيل التالية، ستستأنف العقدة المزامنة من %dدون استخدام أي بيانات لقطة. الرجاء الإبلاغ عن هذه الحادثة إلى %s، بما في ذلك كيفية حصولك على اللقطة. سيتم ترك حالة سلسلة اللقطة غير الصالحة على القرص في حال كان ذلك مفيدًا في تشخيص المشكلة التي تسببت في هذا الخطأ.</translation> - </message> - <message> - <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> - <translation type="unfinished">لا يمكن استرجاع إصدار المحفظة من %i الى %i. لم يتغير إصدار المحفظة.</translation> - </message> - <message> - <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">لا يمكن اقفال المجلد %s. من المحتمل أن %s يعمل بالفعل.</translation> - </message> - <message> - <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> - <translation type="unfinished">موزع بموجب ترخيص برامج MIT ، راجع الملف المصاحب %s أو %s</translation> - </message> - <message> - <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source> - <translation type="unfinished">خطأ في قراءة %s بيانات العملية قد تكون مفقودة أو غير صحيحة. اعادة فحص المحفظة.</translation> - </message> - <message> - <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source> - <translation type="unfinished">الملف %s موجود مسبقا , اذا كنت متأكدا من المتابعة يرجى ابعاده للاستمرار.</translation> - </message> - <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">رجاء تأكد من أن التاريخ والوقت في حاسوبك صحيحان! اذا كانت ساعتك خاطئة، %s لن يعمل بصورة صحيحة.</translation> - </message> - <message> - <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> - <translation type="unfinished">يرجى المساهمة إذا وجدت %s مفيداً. تفضل بزيارة %s لمزيد من المعلومات حول البرنامج.</translation> - </message> - <message> - <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> - <translation type="unfinished">الاختصار أقل من الحد الأدنى %d ميجابايت. من فضلك ارفع الحد.</translation> - </message> - <message> - <source>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source> - <translation type="unfinished">الاختصار: اخر مزامنة للمحفظة كانت قبل البيانات المختصرة. تحتاج الى - اعادة فهرسة (قم بتنزيل الطوابق المتتالية بأكملها مرة أخرى في حال تم اختصار النود)</translation> - </message> - <message> - <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> - <translation type="unfinished">SQLiteDatabase: اصدار مخطط لمحفظة sqlite غير معروف %d. فقط اصدار %d مدعوم.</translation> - </message> - <message> - <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> - <translation type="unfinished">قاعدة بيانات الطوابق تحتوي على طابق مستقبلي كما يبدو. قد يكون هذا بسبب أن التاريخ والوقت في جهازك لم يضبطا بشكل صحيح. قم بإعادة بناء قاعدة بيانات الطوابق في حال كنت متأكدا من أن التاريخ والوقت قد تم ضبطهما بشكل صحيح</translation> - </message> - <message> - <source>The transaction amount is too small to send after the fee has been deducted</source> - <translation type="unfinished">قيمة المعاملة صغيرة جدًا ولا يمكن إرسالها بعد خصم الرسوم</translation> - </message> - <message> - <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> - <translation type="unfinished">هذه بناء برمجي تجريبي - استخدمه على مسؤوليتك الخاصة - لا تستخدمه للتعدين أو التجارة</translation> - </message> - <message> - <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> - <translation type="unfinished">هذا هو الحد الاعلى للرسوم التي تدفعها (بالاضافة للرسوم العادية) لتفادي الدفع الجزئي واعطاء أولوية لاختيار الوحدات.</translation> - </message> - <message> - <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> - <translation type="unfinished">هذه رسوم المعاملة يمكنك التخلص منها إذا كان المبلغ أصغر من الغبار عند هذا المستوى</translation> - </message> - <message> - <source>This is the transaction fee you may pay when fee estimates are not available.</source> - <translation type="unfinished">هذه هي رسوم المعاملة التي قد تدفعها عندما تكون عملية حساب الرسوم غير متوفرة.</translation> - </message> - <message> - <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> - <translation type="unfinished">صيغة ملف المحفظة غير معروفة “%s”. الرجاء تقديم اما “bdb” أو “sqlite”.</translation> - </message> - <message> - <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source> - <translation type="unfinished">تم انشاء المحفظة بنجاح. سيتم الغاء العمل بنوعية المحافظ القديمة ولن يتم دعم انشاءها أو فتحها مستقبلا.</translation> - </message> - <message> - <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> - <translation type="unfinished">تحذير: تم اكتشاف مفاتيح خاصة في المحفظة {%s} رغم أن خيار التعامل مع المفاتيح الخاصة معطل} مع مفاتيح خاصة موقفة. </translation> - </message> - <message> - <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> - <translation type="unfinished">تحذير: لا يبدو أننا نتفق تمامًا مع أقراننا! قد تحتاج إلى الترقية ، أو قد تحتاج الأنواد الأخرى إلى الترقية.</translation> - </message> - <message> - <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> - <translation type="unfinished">تحتاج إلى إعادة إنشاء قاعدة البيانات باستخدام -reindex للعودة إلى الوضعية النود الكامل. هذا سوف يعيد تحميل الطوابق المتتالية بأكملها</translation> - </message> - <message> - <source>%s is set very high!</source> - <translation type="unfinished">ضبط %s مرتفع جدا!</translation> - </message> - <message> - <source>-maxmempool must be at least %d MB</source> - <translation type="unfinished">-الحد الأقصى لتجمع الذاكرة %d ميجابايت على الأقل</translation> - </message> - <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">حدث خطأ داخلي شديد، راجع ملف تصحيح الأخطاء للتفاصيل</translation> - </message> - <message> - <source>Cannot resolve -%s address: '%s'</source> - <translation type="unfinished">لا يمكن الحل - %s العنوان: '%s'</translation> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation type="unfinished">أكثر من عنوان مربوط بالonion مقدم. استخدام %s من أجل خدمة تور (Tor) المنشأة تلقائيا.</translation> </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">لايمكن الكتابة في المجلد '%s'؛ تحقق من الصلاحيات.</translation> - </message> - <message> - <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> - <translation type="unfinished">فشل في إعادة تسمية ملف invalid peers.dat. يرجى نقله أو حذفه وحاول مرة أخرى.</translation> - </message> - <message> - <source>Config setting for %s only applied on %s network when in [%s] section.</source> - <translation type="unfinished">يتم تطبيق إعداد التكوين لـ%s فقط على شبكة %s في قسم [%s].</translation> - </message> - <message> - <source>Copyright (C) %i-%i</source> - <translation type="unfinished">حقوق الطبع والنشر (C) %i-%i</translation> - </message> - <message> - <source>Corrupted block database detected</source> - <translation type="unfinished">تم الكشف عن قاعدة بيانات طوابق تالفة</translation> - </message> - <message> - <source>Could not find asmap file %s</source> - <translation type="unfinished">تعذر العثور على ملف asmap %s</translation> - </message> - <message> - <source>Could not parse asmap file %s</source> - <translation type="unfinished">تعذر تحليل ملف asmap %s</translation> - </message> - <message> - <source>Disk space is too low!</source> - <translation type="unfinished">تحذير: مساحة التخزين منخفضة!</translation> - </message> - <message> - <source>Do you want to rebuild the block database now?</source> - <translation type="unfinished">هل تريد إعادة بناء قاعدة بيانات الطوابق الآن؟</translation> - </message> - <message> - <source>Done loading</source> - <translation type="unfinished">إنتهاء التحميل</translation> - </message> - <message> - <source>Dump file %s does not exist.</source> - <translation type="unfinished">ملف الاسقاط %s غير موجود.</translation> - </message> - <message> - <source>Error creating %s</source> - <translation type="unfinished">خطأ في إنشاء %s</translation> - </message> - <message> - <source>Error loading %s</source> - <translation type="unfinished">خطأ في تحميل %s</translation> - </message> - <message> - <source>Error loading %s: Private keys can only be disabled during creation</source> - <translation type="unfinished">خطأ في تحميل %s: يمكن تعطيل المفاتيح الخاصة أثناء الانشاء فقط</translation> - </message> - <message> - <source>Error loading %s: Wallet corrupted</source> - <translation type="unfinished">خطأ في التحميل %s: المحفظة تالفة.</translation> + <translation type="unfinished">لايمكن الكتابة على دليل البيانات '%s'؛ تحقق من السماحيات.</translation> </message> - <message> - <source>Error loading %s: Wallet requires newer version of %s</source> - <translation type="unfinished">خطأ في تحميل %s: المحفظة تتطلب الاصدار الجديد من %s</translation> - </message> - <message> - <source>Error loading block database</source> - <translation type="unfinished">خطأ في تحميل قاعدة بيانات الطوابق</translation> - </message> - <message> - <source>Error opening block database</source> - <translation type="unfinished">خطأ في فتح قاعدة بيانات الطوابق</translation> - </message> - <message> - <source>Error reading from database, shutting down.</source> - <translation type="unfinished">خطأ في القراءة من قاعدة البيانات ، يجري التوقف.</translation> - </message> - <message> - <source>Error reading next record from wallet database</source> - <translation type="unfinished">خطأ قراءة السجل التالي من قاعدة بيانات المحفظة</translation> - </message> - <message> - <source>Error: Couldn't create cursor into database</source> - <translation type="unfinished">خطأ : لم نتمكن من انشاء علامة فارقة (cursor) في قاعدة البيانات</translation> - </message> - <message> - <source>Error: Disk space is low for %s</source> - <translation type="unfinished">خطأ : مساحة التخزين منخفضة ل %s</translation> - </message> - <message> - <source>Error: Failed to create new watchonly wallet</source> - <translation type="unfinished">خطأ: فشل انشاء محفظة المراقبة فقط الجديدة</translation> - </message> - <message> - <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">خطأ: المفتاح ليس في صيغة ست عشرية: %s</translation> - </message> - <message> - <source>Error: Got value that was not hex: %s</source> - <translation type="unfinished">خطأ: القيمة ليست في صيغة ست عشرية: %s</translation> - </message> - <message> - <source>Error: Missing checksum</source> - <translation type="unfinished">خطأ : مجموع اختباري مفقود </translation> - </message> - <message> - <source>Error: No %s addresses available.</source> - <translation type="unfinished">خطأ : لا يتوفر %s عناوين.</translation> - </message> - <message> - <source>Error: Unable to begin reading all records in the database</source> - <translation type="unfinished">خطأ: غير قادر على قراءة السجلات في قاعدة البيانات</translation> - </message> - <message> - <source>Error: Unable to make a backup of your wallet</source> - <translation type="unfinished">خطأ: غير قادر النسخ الاحتياطي للمحفظة</translation> - </message> - <message> - <source>Error: Unable to read all records in the database</source> - <translation type="unfinished">خطأ: غير قادر على قراءة السجلات في قاعدة البيانات</translation> - </message> - <message> - <source>Error: Unable to remove watchonly address book data</source> - <translation type="unfinished">خطأ: غير قادر على ازالة عناوين المراقبة فقط من السجل</translation> - </message> - <message> - <source>Error: Unable to write record to new wallet</source> - <translation type="unfinished">خطأ : لا يمكن كتابة السجل للمحفظة الجديدة</translation> - </message> - <message> - <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation type="unfinished">فشل في الاستماع على أي منفذ. استخدام الاستماع = 0 إذا كنت تريد هذا.</translation> - </message> - <message> - <source>Failed to rescan the wallet during initialization</source> - <translation type="unfinished">فشلت عملية اعادة تفحص وتدقيق المحفظة أثناء التهيئة</translation> - </message> - <message> - <source>Failed to verify database</source> - <translation type="unfinished">فشل في التحقق من قاعدة البيانات</translation> - </message> - <message> - <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> - <translation type="unfinished">معدل الرسوم (%s) أقل من الحد الادنى لاعدادات معدل الرسوم (%s)</translation> - </message> - <message> - <source>Ignoring duplicate -wallet %s.</source> - <translation type="unfinished">تجاهل المحفظة المكررة %s.</translation> - </message> - <message> - <source>Importing…</source> - <translation type="unfinished">الاستيراد…</translation> - </message> - <message> - <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished">لم يتم العثور على طابق الأساس أو المعلومات غير صحيحة. مجلد بيانات خاطئ للشبكة؟</translation> - </message> - <message> - <source>Initialization sanity check failed. %s is shutting down.</source> - <translation type="unfinished">فشل التحقق من اختبار التعقل. تم إيقاف %s.</translation> - </message> - <message> - <source>Input not found or already spent</source> - <translation type="unfinished">المدخلات غير موجودة أو تم صرفها</translation> - </message> - <message> - <source>Insufficient funds</source> - <translation type="unfinished">الرصيد غير كافي</translation> - </message> - <message> - <source>Invalid -onion address or hostname: '%s'</source> - <translation type="unfinished">عنوان اونيون غير صحيح : '%s'</translation> - </message> - <message> - <source>Invalid P2P permission: '%s'</source> - <translation type="unfinished">إذن القرين للقرين غير صالح: ‘%s’</translation> - </message> - <message> - <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation type="unfinished">قيمة غير صحيحة ل - %s=<amount>:"%s"</translation> - </message> - <message> - <source>Loading P2P addresses…</source> - <translation type="unfinished">تحميل عناوين P2P....</translation> - </message> - <message> - <source>Loading banlist…</source> - <translation type="unfinished">تحميل قائمة الحظر</translation> - </message> - <message> - <source>Loading block index…</source> - <translation type="unfinished">تحميل فهرس الطابق…</translation> - </message> - <message> - <source>Loading wallet…</source> - <translation type="unfinished">تحميل المحفظة…</translation> - </message> - <message> - <source>Missing amount</source> - <translation type="unfinished">يفتقد القيمة</translation> - </message> - <message> - <source>Not enough file descriptors available.</source> - <translation type="unfinished">لا تتوفر واصفات ملفات كافية.</translation> - </message> - <message> - <source>Prune cannot be configured with a negative value.</source> - <translation type="unfinished">لا يمكن ضبط الاختصار بقيمة سالبة.</translation> - </message> - <message> - <source>Prune mode is incompatible with -txindex.</source> - <translation type="unfinished">وضع الاختصار غير متوافق مع -txindex.</translation> - </message> - <message> - <source>Replaying blocks…</source> - <translation type="unfinished">إستعادة الطوابق…</translation> - </message> - <message> - <source>Rescanning…</source> - <translation type="unfinished">إعادة التفحص والتدقيق…</translation> - </message> - <message> - <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> - <translation type="unfinished">SQLiteDatabase: فشل في تنفيذ الامر لتوثيق قاعدة البيانات: %s</translation> - </message> - <message> - <source>Section [%s] is not recognized.</source> - <translation type="unfinished">لم يتم التعرف على القسم [%s]</translation> - </message> - <message> - <source>Signing transaction failed</source> - <translation type="unfinished">فشل توقيع المعاملة</translation> - </message> - <message> - <source>Specified -walletdir "%s" does not exist</source> - <translation type="unfinished">مجلد المحفظة المحددة "%s" غير موجود</translation> - </message> - <message> - <source>Specified -walletdir "%s" is a relative path</source> - <translation type="unfinished">مسار مجلد المحفظة المحدد "%s" مختصر ومتغير</translation> - </message> - <message> - <source>The source code is available from %s.</source> - <translation type="unfinished">شفرة المصدر متاحة من %s.</translation> - </message> - <message> - <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">قيمة المعاملة صغيرة جدا ولا تكفي لدفع الرسوم</translation> - </message> - <message> - <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation type="unfinished">سوف تتجنب المحفظة دفع رسوم أقل من الحد الأدنى للتوصيل.</translation> - </message> - <message> - <source>This is experimental software.</source> - <translation type="unfinished">هذا برنامج تجريبي.</translation> - </message> - <message> - <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation type="unfinished">هذه هي اقل قيمة من العمولة التي تدفعها عند كل عملية تحويل للأموال.</translation> - </message> - <message> - <source>This is the transaction fee you will pay if you send a transaction.</source> - <translation type="unfinished">هذه هي رسوم ارسال العملية التي ستدفعها إذا قمت بارسال العمليات.</translation> - </message> - <message> - <source>Transaction amount too small</source> - <translation type="unfinished">قيمة العملية صغيره جدا</translation> - </message> - <message> - <source>Transaction amounts must not be negative</source> - <translation type="unfinished">يجب ألا تكون قيمة العملية بالسالب</translation> - </message> - <message> - <source>Transaction must have at least one recipient</source> - <translation type="unfinished">يجب أن تحتوي المعاملة على مستلم واحد على الأقل</translation> - </message> - <message> - <source>Transaction needs a change address, but we can't generate it.</source> - <translation type="unfinished">العملية تتطلب عنوان فكة ولكن لم نتمكن من توليد العنوان.</translation> - </message> - <message> - <source>Transaction too large</source> - <translation type="unfinished">المعاملة كبيرة جدا</translation> - </message> - <message> - <source>Unable to bind to %s on this computer (bind returned error %s)</source> - <translation type="unfinished">يتعذر الربط مع %s على هذا الكمبيوتر (الربط انتج خطأ %s)</translation> - </message> - <message> - <source>Unable to bind to %s on this computer. %s is probably already running.</source> - <translation type="unfinished">تعذر الربط مع %s على هذا الكمبيوتر. %s على الأغلب يعمل مسبقا.</translation> - </message> - <message> - <source>Unable to generate initial keys</source> - <translation type="unfinished">غير قادر على توليد مفاتيح أولية</translation> - </message> - <message> - <source>Unable to generate keys</source> - <translation type="unfinished"> غير قادر على توليد مفاتيح</translation> - </message> - <message> - <source>Unable to open %s for writing</source> - <translation type="unfinished">غير قادر على فتح %s للكتابة </translation> - </message> - <message> - <source>Unable to start HTTP server. See debug log for details.</source> - <translation type="unfinished">غير قادر على بدء خادم ال HTTP. راجع سجل تصحيح الأخطاء للحصول على التفاصيل.</translation> - </message> - <message> - <source>Unknown -blockfilterindex value %s.</source> - <translation type="unfinished">قيمة -blockfilterindex مجهولة %s.</translation> - </message> - <message> - <source>Unknown address type '%s'</source> - <translation type="unfinished">عنوان غير صحيح : '%s'</translation> - </message> - <message> - <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">شبكة مجهولة عرفت حددت في -onlynet: '%s'</translation> - </message> - <message> - <source>Verifying blocks…</source> - <translation type="unfinished">جار التحقق من الطوابق...</translation> - </message> - <message> - <source>Verifying wallet(s)…</source> - <translation type="unfinished"> التحقق من المحافظ ....</translation> - </message> - <message> - <source>Wallet needed to be rewritten: restart %s to complete</source> - <translation type="unfinished">يجب إعادة كتابة المحفظة: يلزم إعادة التشغيل %s لإكمال العملية</translation> - </message> - <message> - <source>Settings file could not be read</source> - <translation type="unfinished">ملف الاعدادات لا يمكن قراءته</translation> - </message> - <message> - <source>Settings file could not be written</source> - <translation type="unfinished">لم نتمكن من كتابة ملف الاعدادات</translation> - </message> -</context> + </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_az.ts b/src/qt/locale/bitcoin_az.ts index 3bba7a2b40..ad81f3a0bd 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> @@ -172,6 +176,10 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <translation type="unfinished">Pulqabı üçün köhnə şifrəli sözü və yeni şifrəli sözü daxil edin</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Davam et</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Unutmayın ki, pulqabınızın şifrələməsi bitcoinlərinizi kompüterinizə zərərli proqram tərəfindən oğurlanmaqdan tamamilə qoruya bilməz.</translation> </message> @@ -281,46 +289,50 @@ 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> + <message> + <source>default wallet</source> + <translation type="unfinished">standart cüzdan</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -502,7 +514,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Ödəmə tələbi (QR-kodlar və Bitcoin URI-ləri yaradılır)^</translation> + <translation type="unfinished">Ödəmə tələbi (QR-kodlar və Bitcoin URI-ləri yaradılır):</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> @@ -510,7 +522,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">İstifadə edilmiş </translation> + <translation type="unfinished">İstifadə edilmiş qəbuletmə ünvanlarının və etiketlərin siyahısını göstərmək</translation> </message> <message> <source>&Command-line options</source> @@ -525,7 +537,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 geridə qaldı</translation> + <translation type="unfinished">%1 geridə qalır</translation> </message> <message> <source>Catching up…</source> @@ -626,10 +638,6 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <translation type="unfinished">İcmal vərəqində dəyərləri gizlədin</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart cüzdan</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Heç bir cüzdan yoxdur</translation> </message> @@ -646,7 +654,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <message> <source>Restore Wallet</source> <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment> - <translation type="unfinished">Cüzdanı bərpa et</translation> + <translation type="unfinished">Pulqabını bərpa et</translation> </message> <message> <source>Wallet Name</source> @@ -963,6 +971,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> @@ -973,13 +988,9 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <translation type="unfinished">Pulqabının açılması xəbərdarlığı</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart cüzdan</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> - <translation type="unfinished">Cüzdanı açın</translation> + <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> @@ -1412,17 +1423,29 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished">Komissiydan sonra:</translation> + <translation type="unfinished">Komissiyadan sonra:</translation> </message> <message> <source>Change:</source> <translation type="unfinished">Qalıq:</translation> </message> <message> + <source>per kilobyte</source> + <translation type="unfinished">kilobayt başına</translation> + </message> + <message> <source>Hide</source> <translation type="unfinished">Gizlə</translation> </message> <message> + <source>Choose…</source> + <translation type="unfinished">Seçin…</translation> + </message> + <message> + <source>Balance:</source> + <translation type="unfinished">Balans:</translation> + </message> + <message> <source>Copy quantity</source> <translation type="unfinished">Miqdarı kopyalayın</translation> </message> @@ -1457,8 +1480,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> @@ -1476,11 +1499,15 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <source>unknown</source> <translation type="unfinished">naməlum</translation> </message> + <message> + <source>own address</source> + <translation type="unfinished">öz ünvanı</translation> + </message> <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> @@ -1559,13 +1586,6 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">standart cüzdan</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> diff --git a/src/qt/locale/bitcoin_az@latin.ts b/src/qt/locale/bitcoin_az@latin.ts index bb808eaddb..c35a060fa4 100644 --- a/src/qt/locale/bitcoin_az@latin.ts +++ b/src/qt/locale/bitcoin_az@latin.ts @@ -176,6 +176,10 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <translation type="unfinished">Pulqabı üçün köhnə şifrəli sözü və yeni şifrəli sözü daxil edin</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Davam et</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Unutmayın ki, pulqabınızın şifrələməsi bitcoinlərinizi kompüterinizə zərərli proqram tərəfindən oğurlanmaqdan tamamilə qoruya bilməz.</translation> </message> @@ -285,46 +289,50 @@ 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> + <message> + <source>default wallet</source> + <translation type="unfinished">standart cüzdan</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -506,7 +514,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Ödəmə tələbi (QR-kodlar və Bitcoin URI-ləri yaradılır)^</translation> + <translation type="unfinished">Ödəmə tələbi (QR-kodlar və Bitcoin URI-ləri yaradılır):</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> @@ -514,7 +522,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">İstifadə edilmiş </translation> + <translation type="unfinished">İstifadə edilmiş qəbuletmə ünvanlarının və etiketlərin siyahısını göstərmək</translation> </message> <message> <source>&Command-line options</source> @@ -529,7 +537,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 geridə qaldı</translation> + <translation type="unfinished">%1 geridə qalır</translation> </message> <message> <source>Catching up…</source> @@ -630,10 +638,6 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <translation type="unfinished">İcmal vərəqində dəyərləri gizlədin</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart cüzdan</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Heç bir cüzdan yoxdur</translation> </message> @@ -977,10 +981,6 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> <translation type="unfinished">Pulqabının açılması xəbərdarlığı</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart cüzdan</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Cüzdanı açın</translation> @@ -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> @@ -1563,13 +1563,6 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation> </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">standart cüzdan</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> 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..bfbc848fb6 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -183,6 +183,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Въведете старата и новата паролна фраза за портфейла.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Продължи</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Не забравяйте, че криптирането на вашия портфейл не може напълно да защити вашите биткойни от кражба от зловреден софтуер, заразяващ компютъра ви.</translation> </message> @@ -397,6 +401,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 Гигабайт</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">Портфейл по подразбиране</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -491,7 +499,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">Шифровай портфейла</translation> + <translation type="unfinished">&Крипритай уолет..</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -642,7 +650,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Load PSBT from &clipboard…</source> - <translation type="unfinished">Заредете PSBT от &клипборд...</translation> + <translation type="unfinished">Заредете PSBT (частично подписана Bitcoin трансакция) от &клипборд...</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> @@ -715,10 +723,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -800,7 +804,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Предварителна синхронизация на Headers (%1%)…</translation> + <translation type="unfinished">Предварителна синхронизация на хедъри (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -1109,10 +1113,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -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> @@ -2133,6 +2137,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&Копирай адрес</translation> </message> <message> + <source>None</source> + <translation type="unfinished">нито един</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Извършване на команда без портфейл</translation> </message> @@ -2554,10 +2562,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Моля проверете адреса и опитайте отново.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Въведеният адрес не може да се съпостави с валиден ключ.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Отключването на портфейла беше отменено.</translation> </message> @@ -2937,11 +2941,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Send Coins</source> <translation type="unfinished">Изпращане</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Портфейл по подразбиране</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_bn.ts b/src/qt/locale/bitcoin_bn.ts index f4cdcd1a4b..bfb104a7a3 100644 --- a/src/qt/locale/bitcoin_bn.ts +++ b/src/qt/locale/bitcoin_bn.ts @@ -276,6 +276,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">আংশিক স্বাক্ষরিত বিটকয়েন লেনদেন লোড করুন</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">&ক্লিপবোর্ড থেকে আংশিক স্বাক্ষরিত বিটকয়েন লেনদেন আনুন</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">ক্লিপবোর্ড থেকে আংশিক স্বাক্ষরিত বিটকয়েন লেনদেন লোড করুন</translation> </message> @@ -466,6 +470,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ঠিকানা কপি করুন</translation> </message> <message> + <source>via %1</source> + <translation type="unfinished">এর মাধ্যমে %1</translation> + </message> + <message> <source>Unknown</source> <translation type="unfinished">অজানা</translation> </message> diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index 2667d04cb7..e71def3e6c 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -329,7 +329,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">zadani novčanik</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -598,10 +602,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Maskirajte vrijednosti na kartici Pregled</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">zadani novčanik</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Nema dostupnih novčanika</translation> </message> @@ -851,10 +851,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>OpenWalletActivity</name> <message> - <source>default wallet</source> - <translation type="unfinished">zadani novčanik</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Otvorite Novčanik</translation> @@ -1515,13 +1511,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">zadani novčanik</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 2ea1e0a2a2..eff91d3387 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -184,6 +184,10 @@ Només és possible firmar amb adreces del tipus "legacy".</translation> <translation type="unfinished">Introduïu la contrasenya antiga i la contrasenya nova a la cartera.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continua</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">Recorda que tot i xifrant la teva cartera, els teus bitcoins no estan completament protegits de robatori a través de programari maliciós que estigui infectant el teu ordinador.</translation> </message> @@ -273,7 +277,11 @@ Només és possible firmar amb adreces del tipus "legacy".</translation> <source>Internal error</source> <translation type="unfinished">Error intern</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">S'ha produït un error intern. %1 intentarà continuar amb seguretat. Es tracta d’un error inesperat que es pot informar tal com es descriu a continuació.</translation> + </message> +</context> <context> <name>QObject</name> <message> @@ -311,6 +319,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 +361,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,11 +400,15 @@ 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> + <message> + <source>default wallet</source> + <translation type="unfinished">cartera predeterminada</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -700,10 +718,6 @@ Només és possible firmar amb adreces del tipus "legacy".</translation> <translation type="unfinished">Emmascara els valors en la pestanya Visió general</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">cartera predeterminada</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">No hi ha cap cartera disponible</translation> </message> @@ -1110,10 +1124,6 @@ El procés de migració crearà una còpia de seguretat de la cartera abans de m <translation type="unfinished">Avís en l'obertura de la cartera</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">cartera predeterminada</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Obre la cartera</translation> @@ -1136,7 +1146,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 +1192,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">A un pas de 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 +1337,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 +1412,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 +1508,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> @@ -1515,6 +1556,10 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">Nombre de fils de &verificació d'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">Camí complet a %1 script compatible amb Bitcoin Core (per exemple, C:\Downloads\hwi.exe o /Users/you/Downloads/hwi.py). Aneu amb compte: el programari maliciós pot robar-vos les monedes!</translation> + </message> + <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished">Adreça IP del proxy (p. ex. IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> @@ -1527,6 +1572,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 +1608,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 +1629,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 +1730,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 +1796,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 +1890,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 +1991,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 +2059,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> @@ -2367,6 +2451,10 @@ Si rebeu aquest error, haureu de sol·licitar al comerciant que proporcioni un U <translation type="unfinished">Activitat de xarxa inhabilitada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Cap</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">S'està executant l'ordre sense cap cartera</translation> </message> @@ -2564,8 +2652,7 @@ No utilitzeu aquesta consola sense entendre completament les ramificacions d'una </message> <message> <source>&Verify</source> - <translation type="unfinished">&Verifica -</translation> + <translation type="unfinished">&Verifica</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> @@ -2864,6 +2951,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> @@ -3035,10 +3127,6 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k <translation type="unfinished">&Signa el missatge</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">Podeu signar missatges/acords amb les vostres adreces per a provar que rebeu les bitcoins que s'hi envien. Aneu amb compte no signar res que sigui vague o aleatori, perquè en alguns atacs de suplantació es pot provar que hi signeu la vostra identitat. Només signeu aquelles declaracions completament detallades en què hi esteu d'acord. </translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">L'adreça Bitcoin amb què signar el missatge</translation> </message> @@ -3127,10 +3215,6 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k <translation type="unfinished">Comproveu l'adreça i torneu-ho a provar.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">L'adreça introduïda no referencia a cap clau.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">S'ha cancel·lat el desblocatge de la cartera.</translation> </message> @@ -3247,8 +3331,8 @@ 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> @@ -3669,11 +3753,6 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <translation type="unfinished">PSBT copiada</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiat al portaretalls</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">No es pot signar la transacció.</translation> </message> @@ -3685,10 +3764,6 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <source>Can't display address</source> <translation type="unfinished">No es pot mostrar l'adreça</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">cartera predeterminada</translation> - </message> </context> <context> <name>WalletView</name> @@ -3793,10 +3868,6 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <translation type="unfinished">No s'ha proporcionat cap format de fitxer de cartera. Per a utilitzar createfromdump, s'ha de proporcionar<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> - <translation type="unfinished">Comproveu que la data i hora de l'ordinador són correctes. Si el rellotge és incorrecte, %s no funcionarà correctament.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Contribueix si trobes %s útil. Visita %s per a obtenir més informació sobre el programari.</translation> </message> @@ -3881,10 +3952,6 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <translation type="unfinished">-maxmempool ha de tenir almenys %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">S'ha produït un error intern fatal. Consulteu debug.log per a més detalls</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">No es pot resoldre -%s adreça: '%s'</translation> </message> @@ -3897,6 +3964,22 @@ 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 tarifa de minrelay de %s per evi tar que les tarifes 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 +4153,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 +4169,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 +4261,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_cmn.ts b/src/qt/locale/bitcoin_cmn.ts index d65385fd59..b5d9efb79d 100644 --- a/src/qt/locale/bitcoin_cmn.ts +++ b/src/qt/locale/bitcoin_cmn.ts @@ -175,6 +175,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">输入钱包的旧密码和新密码。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</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> @@ -257,6 +265,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -428,7 +440,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 GB (十億位元組)</translation> </message> -</context> + </context> <context> <name>BitcoinGUI</name> <message> @@ -506,7 +518,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">修改钱包加密密码</translation> + <translation type="unfinished">更改钱包密码</translation> </message> <message> <source>&Send</source> @@ -517,16 +529,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">接收(&R)</translation> </message> <message> - <source>&Options…</source> - <translation type="unfinished">选项(&O)</translation> - </message> - <message> - <source>&Encrypt Wallet…</source> - <translation type="unfinished">加密钱包(&E)</translation> - </message> - <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">把你钱包中的私钥加密</translation> + <translation type="unfinished">將錢包中之密鑰加密</translation> </message> <message> <source>&Backup Wallet…</source> @@ -537,18 +541,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">修改密码(&C)</translation> </message> <message> - <source>Sign &message…</source> - <translation type="unfinished">签名消息(&M)</translation> - </message> - <message> - <source>&Verify message…</source> - <translation type="unfinished">验证消息(&V)</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">从文件加载PSBT(&L)...</translation> </message> @@ -565,32 +557,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">创建钱包...</translation> </message> <message> - <source>Close All Wallets…</source> - <translation type="unfinished">关闭所有钱包...</translation> - </message> - <message> <source>&File</source> - <translation type="unfinished">文件(&F)</translation> + <translation type="unfinished">&文件</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">设置(&S)</translation> + <translation type="unfinished">&設定</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">帮助(&H)</translation> + <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> + <translation type="unfinished">分頁工具列</translation> </message> <message> <source>Indexing blocks on disk…</source> @@ -602,7 +582,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> @@ -632,15 +612,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">赶上...</translation> + <translation type="unfinished">正在追上进度...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">最新收到的区块产生于 %1 之前。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">在此之后的交易尚不可见</translation> </message> <message> <source>Error</source> @@ -726,7 +706,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation type="unfinished">显示 %1 帮助信息,获取可用命令行选项列表</translation> + <translation type="unfinished">显示%1帮助消息以获得可能包含Bitcoin命令行选项的列表</translation> </message> <message> <source>&Mask values</source> @@ -737,10 +717,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -762,7 +738,7 @@ 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">钱包名称</translation> + <translation type="unfinished">錢包名稱</translation> </message> <message> <source>&Window</source> @@ -778,15 +754,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 client</source> - <translation type="unfinished">%1 客户端</translation> + <translation type="unfinished">%1 客戶端</translation> </message> <message> <source>&Hide</source> - <translation type="unfinished">隐藏(&H)</translation> + <translation type="unfinished">&躲</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">&顯示</translation> + <translation type="unfinished">显示(&H)</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -798,26 +774,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <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> + <translation type="unfinished">關閉網路紀錄</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">預先同步標頭(%1%)</translation> + <translation type="unfinished">预同步区块头 (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -919,11 +885,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Quantity:</source> - <translation type="unfinished">总量:</translation> + <translation type="unfinished">數量:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished">位元組數:</translation> + <translation type="unfinished">位元組:</translation> </message> <message> <source>Amount:</source> @@ -938,14 +904,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">計費後金額:</translation> </message> <message> - <source>Change:</source> - <translation type="unfinished">找零:</translation> - </message> - <message> - <source>(un)select all</source> - <translation type="unfinished">全(不)选</translation> - </message> - <message> <source>Tree mode</source> <translation type="unfinished">树状模式</translation> </message> @@ -958,22 +916,10 @@ Signing is only possible with addresses of the type 'legacy'.</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>Confirmed</source> - <translation type="unfinished">已确认</translation> - </message> - <message> <source>Copy amount</source> <translation type="unfinished">复制金额</translation> </message> @@ -998,10 +944,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">锁定未花费(&O)</translation> </message> <message> - <source>&Unlock unspent</source> - <translation type="unfinished">解锁未花费(&U)</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">复制数目</translation> </message> @@ -1037,11 +979,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>change from %1 (%2)</source> <translation type="unfinished">找零來自於 %1 (%2)</translation> </message> - <message> - <source>(change)</source> - <translation type="unfinished">(找零)</translation> - </message> -</context> + </context> <context> <name>CreateWalletActivity</name> <message> @@ -1133,10 +1071,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1186,7 +1120,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">您确定想要关闭所有钱包吗?</translation> + <translation type="unfinished">您確定要關閉所有錢包嗎?</translation> </message> </context> <context> @@ -1237,7 +1171,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Create</source> - <translation type="unfinished">创建</translation> + <translation type="unfinished">創建</translation> </message> </context> <context> @@ -1276,7 +1210,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> - <translation type="unfinished">地址“%1”已经存在,它是一个收款地址,标签为“%2”,所以它不能作为一个付款地址被添加进来。</translation> + <translation type="unfinished">地址“%1”為已登記存在“%2”的地址,因此無法新增為發送地址。</translation> </message> <message> <source>The entered address "%1" is already in the address book with label "%2".</source> @@ -1299,7 +1233,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>name</source> - <translation type="unfinished">名称</translation> + <translation type="unfinished">姓名</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> @@ -1307,7 +1241,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Path already exists, and is not a directory.</source> - <translation type="unfinished">路径已存在,并且不是一个目录。</translation> + <translation type="unfinished">已經有指定的路徑了,並且不是一個目錄。</translation> </message> <message> <source>Cannot create data directory here.</source> @@ -1344,7 +1278,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">会在此目录中存储约 %1 GB 的数据。</translation> + <translation type="unfinished">此目錄中將儲存約%1 GB 的資料。</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1375,7 +1309,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Welcome to %1.</source> - <translation type="unfinished">欢迎使用 %1</translation> + <translation type="unfinished">歡迎來到 %1。</translation> </message> <message> <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> @@ -1383,7 +1317,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation type="unfinished">取消此设置需要重新下载整个区块链。先完整下载整条链再进行修剪会更快。这会禁用一些高级功能。</translation> + <translation type="unfinished">恢復此設定需要重新下載整個區塊鏈。 先下載完整鏈然後再修剪它的速度更快。 禁用一些高級功能。</translation> </message> <message> <source>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> @@ -1425,7 +1359,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">在此窗口消失前不要关闭计算机。</translation> + <translation type="unfinished">在該視窗消失之前,請勿關閉電腦。</translation> </message> </context> <context> @@ -1436,15 +1370,15 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation type="unfinished">近期交易可能尚未显示,因此当前余额可能不准确。以上信息将在与比特币网络完全同步后更正。详情如下</translation> + <translation type="unfinished">最近的交易可能還看不到,因此錢包餘額可能不正確。在錢包軟體完成跟 bitcoin 網路的同步後,這裡的資訊就會正確。詳情請見下面。</translation> </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation type="unfinished">尝试使用受未可见交易影响的余额将不被网络接受。</translation> + <translation type="unfinished">嘗試花費受尚未顯示的交易影響的比特幣將不會被網路接受。</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">剩余区块数量</translation> + <translation type="unfinished">剩餘區塊數量</translation> </message> <message> <source>Unknown…</source> @@ -1456,7 +1390,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>Progress</source> @@ -1468,7 +1402,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Estimated time left until synced</source> - <translation type="unfinished">预计剩余同步时间</translation> + <translation type="unfinished">預計完成同步所需時間</translation> </message> <message> <source>Hide</source> @@ -1496,7 +1430,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <source>Paste address from clipboard</source> <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> </context> <context> @@ -1507,11 +1441,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>&Main</source> - <translation type="unfinished">主要(&M)</translation> + <translation type="unfinished">&主要(&Main)</translation> </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">在登入系统后自动启动 %1</translation> + <translation type="unfinished">登錄系統%1後自動啟動。</translation> </message> <message> <source>&Start %1 on system login</source> @@ -1523,11 +1457,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Size of &database cache</source> - <translation type="unfinished">数据库缓存大小(&D)</translation> + <translation type="unfinished">資料庫快取的大小 </translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">脚本验证线程数(&V)</translation> + <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> @@ -2274,10 +2208,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2384,6 +2314,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/类型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2446,7 +2380,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>&Open</source> @@ -2552,7 +2486,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 天(&A)</translation> + <translation type="unfinished">一天</translation> </message> <message> <source>1 &week</source> @@ -2576,6 +2510,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">无</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -2611,7 +2549,7 @@ For more information on using this console, type %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(节点: %1)</translation> + <translation type="unfinished">(同儕:%1)</translation> </message> <message> <source>via %1</source> @@ -2801,11 +2739,11 @@ For more information on using this console, type %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">验证(&V)</translation> + <translation type="unfinished">&驗證</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">在像是硬件钱包屏幕的地方检验这个地址</translation> + <translation type="unfinished">在例如硬體錢包螢幕上驗證這個地址</translation> </message> <message> <source>&Save Image…</source> @@ -2943,7 +2881,7 @@ For more information on using this console, type %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">输入...</translation> + <translation type="unfinished">輸入…</translation> </message> <message> <source>Choose…</source> @@ -2957,9 +2895,9 @@ For more information on using this console, type %6. <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">指定交易虚拟大小的每kB (1,000字节) 自定义费率。 + <translation type="unfinished">指定每千字節(1,000字節)交易虛擬大小的自訂手續費。 -附注:因为矿工费是按字节计费的,所以如果费率是“每kvB支付100聪”,那么对于一笔500虚拟字节 (1kvB的一半) 的交易,最终将只会产生50聪的矿工费。(译注:这里就是提醒单位是字节,而不是千字节,如果搞错的话,矿工费会过低,导致交易长时间无法确认,或者压根无法发出)</translation> +注意:由於手續費是按每字節計算的,對於虛擬大小為500字節(半千字節)的交易,手續費率為「每千字節100聰」,最終將只收取50聰的手續費。</translation> </message> <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> @@ -3074,6 +3012,10 @@ 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 balance:</source> + <translation type="unfinished">外部餘額:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">或</translation> </message> @@ -3082,6 +3024,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">你可以之後再提高手續費(有 BIP-125 手續費追加的標記)</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">請檢查您的交易提案。這將產生部分簽名的比特幣交易(PSBT),您可以儲存或複製該交易,然後使用簽名。離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 from wallet '%2'</source> <translation type="unfinished">%1 来自钱包 “%2”</translation> </message> @@ -3205,7 +3152,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Remove this entry</source> @@ -3262,10 +3209,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">簽署訊息(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以使用您的地址簽名訊息/協議,以證明您可以接收發送給他們的比特幣。但是請小心,不要簽名語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽名的手法來冒充是你。只有簽名您同意的詳細內容。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3275,7 +3218,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Enter the message you want to sign here</source> @@ -3350,10 +3293,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -3406,6 +3345,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <source>kB/s</source> + <translation type="unfinished">千字節/秒</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -3772,7 +3718,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Confirmed</source> - <translation type="unfinished">已确认</translation> + <translation type="unfinished">已確認</translation> </message> <message> <source>Watch-only</source> @@ -3906,11 +3852,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT已複製</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">沒辦法簽署交易。</translation> </message> @@ -3920,11 +3861,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Can't display address</source> - <translation type="unfinished">無法顯示地址</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">默认钱包</translation> + <translation type="unfinished">無法顯示錢包位址</translation> </message> </context> <context> @@ -3974,6 +3911,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s 開發人員</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation type="unfinished">%s損壞。嘗試使用錢包工具bitcoin-wallet挽救或還原備份。</translation> + </message> + <message> <source>%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 验证 -assumeutxo 快照状态失败。这表明硬件可能有问题,也可能是软件bug,或者还可能是软件被不当修改、从而让非法快照也能够被加载。因此,将关闭节点并停止使用从这个快照构建出的任何状态,并将链高度从 %d 重置到 %d 。下次启动时,节点将会不使用快照数据从 %d 继续同步。请将这个事件报告给 %s 并在报告中包括您是如何获得这份快照的。无效的链状态快照仍被保存至磁盘上,以供诊断问题的原因。</translation> </message> @@ -3987,7 +3928,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">无法锁定数据目录 %s。%s 可能已经在运行。</translation> + <translation type="unfinished">無法在資料目錄上獲取鎖定%s。%s可能已經在運行了。</translation> </message> <message> <source>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> @@ -4015,7 +3956,9 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">错误: 转储文件标识符记录不正确。得到的是 "%s",而预期本应得到的是 "%s"。</translation> + <translation type="unfinished"> +錯誤:轉存檔案識別記錄不正確。獲得%s,預期 +%s。</translation> </message> <message> <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> @@ -4054,10 +3997,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">没有提供钱包格式。要使用 createfromdump ,必须提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4166,10 +4105,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">參數 -maxmempool 至少要給 %d 百萬位元組(MB)</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">沒辦法解析 -%s 參數指定的地址: '%s'</translation> </message> @@ -4304,6 +4239,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4321,7 +4260,7 @@ Unable to restore backup of wallet.</source> </message> <message> <source>Could not find asmap file %s</source> - <translation type="unfinished">找不到asmap文件%s</translation> + <translation type="unfinished">找不到asmap 檔案 %s</translation> </message> <message> <source>Could not parse asmap file %s</source> @@ -4412,14 +4351,34 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: %s 所在的磁盘空间低。</translation> </message> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">錯誤:轉存檔案的校驗和不匹配。%s計算得%s</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">错误:创建新仅观察钱包失败</translation> </message> <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的鍵不是十六進制:%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的值不是十六進制:%s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">錯誤:keypool已用完,請先重新呼叫keypoolrefill</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">錯誤:缺少校驗和</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">錯誤: 沒有可用的 %s 地址</translation> + </message> + <message> <source>Error: This wallet already uses SQLite</source> <translation type="unfinished">错误:此钱包已经在使用SQLite</translation> </message> @@ -4472,6 +4431,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: 钱包%s的数据库事务无法被执行</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to start indexes, shutting down..</source> <translation type="unfinished">无法启动索引,关闭中...</translation> </message> @@ -4480,6 +4443,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">校验数据库失败</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4504,6 +4475,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">dbcache不足以用于区块验证</translation> </message> <message> + <source>Insufficient funds</source> + <translation type="unfinished">金额不足</translation> + </message> + <message> <source>Invalid -i2psam address or hostname: '%s'</source> <translation type="unfinished">无效的 -i2psam 地址或主机名: '%s'</translation> </message> @@ -4672,10 +4647,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易位元量太大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation type="unfinished">沒辦法繫結在這台電腦上的 %s 。%s 可能已經在執行了。</translation> </message> diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 5f2ffc5bd0..1f5c6d9610 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -171,6 +171,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Zadej staré a nové heslo k peněžence.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Pokračovat</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">Pamatujte, že zašifrování peněženky nemůže plně ochránit vaše bitcoiny před krádeží, pokud by byl váš počítač napadem malwarem.</translation> </message> @@ -396,7 +400,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n let</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">výchozí peněženka</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -597,7 +605,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"> <numerusform>Zpracován %n blok transakční historie.</numerusform> <numerusform>Zpracovány %n bloky transakční historie.</numerusform> - <numerusform>Zpracováno %n bloků transakční historie.</numerusform> + <numerusform>Zpracováno %n bloků transakční historie</numerusform> </translation> </message> <message> @@ -703,10 +711,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Skrýt částky v přehledu</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">výchozí peněženka</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Nejsou dostupné žádné peněženky</translation> </message> @@ -1059,10 +1063,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Varování otevření peněženky</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">výchozí peněženka</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Otevřít peněženku</translation> @@ -2531,6 +2531,10 @@ Pokud vidíte tuto chybu, měli byste požádat, aby obchodník poskytl adresu k <translation type="unfinished">Síť je vypnutá</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Žádné</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Spouštění příkazu bez jakékoliv peněženky</translation> </message> @@ -2539,6 +2543,23 @@ Pokud vidíte tuto chybu, měli byste požádat, aby obchodník poskytl adresu k <translation type="unfinished">Příkaz se vykonává s použitím peněženky "%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">Vítejte v konzole %1 RPC. + Použijte šipky nahoru a dolů k procházení historie a %2 k vymazání obrazovky. + Použijte %3 a %4 ke zvětšení nebo zmenšení velikosti písma. + Pro přehled dostupných příkazů zadejte %5. + Další informace o používání této konzoly získáte zadáním %6 + + %7VAROVÁNÍ: Podvodníci byli aktivní a říkali uživatelům, aby sem zadávali příkazy, a kradli jim obsah peněženky. Nepoužívejte tuto konzolu, aniž byste plně porozuměli důsledkům příkazu.%8</translation> + </message> + <message> <source>Executing…</source> <extracomment>A console message indicating an entered command is currently being executed.</extracomment> <translation type="unfinished">Provádím...</translation> @@ -3225,10 +3246,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">&Podepiš zprávu</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">Podepsáním zprávy/smlouvy svými adresami můžeš prokázat, že jsi na ně schopen přijmout bitcoiny. Buď opatrný a nepodepisuj nic vágního nebo náhodného; například při phishingových útocích můžeš být lákán, abys něco takového podepsal. Podepisuj pouze naprosto úplná a detailní prohlášení, se kterými souhlasíš.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoinová adresa, kterou se zpráva podepíše</translation> </message> @@ -3313,10 +3330,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Zkontroluj ji prosím a zkus to pak znovu.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Zadaná adresa nepasuje ke klíči.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Odemčení peněženky bylo zrušeno.</translation> </message> @@ -3871,11 +3884,6 @@ Přejděte do Soubor > Otevřít peněženku pro načtení peněženky. <translation type="unfinished">PSBT zkopírována</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Zkopírováno do schránky</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">Nemůžu podepsat transakci.</translation> </message> @@ -3887,10 +3895,6 @@ Přejděte do Soubor > Otevřít peněženku pro načtení peněženky. <source>Can't display address</source> <translation type="unfinished">Nemohu zobrazit adresu</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">výchozí peněženka</translation> - </message> </context> <context> <name>WalletView</name> @@ -4016,10 +4020,6 @@ Ověřuji peněženku.</translation> <translation type="unfinished">Nebyl poskytnut formát souboru peněženky. Pro použití createfromdump, -format=<format> musí být poskytnut.</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">Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, %s nebude fungovat správně.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Prosíme, zapoj se nebo přispěj, pokud ti %s přijde užitečný. Více informací o programu je na %s.</translation> </message> @@ -4116,10 +4116,6 @@ Ověřuji peněženku.</translation> <translation type="unfinished">-maxmempool musí být alespoň %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Nastala závažná vnitřní chyba, podrobnosti viz v debug.log.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Nemohu přeložit -%s adresu: '%s'</translation> </message> @@ -4148,6 +4144,10 @@ 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 mohou 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> @@ -4662,10 +4662,6 @@ Nelze obnovit zálohu peněženky.</translation> <translation type="unfinished">Transakce je příliš velká</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Není možné alokovat paměť pro -maxsigcachesize '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Nedaří se mi připojit na %s na tomhle počítači (operace bind vrátila chybu %s)</translation> </message> @@ -4730,6 +4726,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..78ce4e7155 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -175,6 +175,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Indtast den gamle adgangskode og en ny adgangskode til tegnebogen.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Forsæt</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">Husk, at kryptere din tegnebog vil ikke fuldt ud beskytte dine bitcoins mod at blive stjålet af malware på din computer.</translation> </message> @@ -382,7 +386,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n år</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">Standard tegnebog</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -680,10 +688,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Maskér værdierne i Oversigt-fanebladet</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standard tegnebog</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Ingen tegnebøger tilgængelige</translation> </message> @@ -1007,10 +1011,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Advarsel for åbning af tegnebog</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standard tegnebog</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Åben Tegnebog</translation> @@ -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> @@ -2354,6 +2362,10 @@ Hvis du modtager denne fejl, skal du anmode forhandleren om en BIP21-kompatibel <translation type="unfinished">Netværksaktivitet deaktiveret</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ingen</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Udfører kommando uden en tegnebog</translation> </message> @@ -2794,6 +2806,10 @@ Bemærk: Da gebyret beregnes på per-byte-basis, ville en gebyrsats på "100 sat <translation type="unfinished">L&av usigneret</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">Laver en delvist signeret bitcointransaktion (forkortet PSBT) som kan bruges med f.eks. en offline %1 tegnebog. De kan også bruges med PSBT-kompatible hardwaretegnebøger.</translation> + </message> + <message> <source>%1 to '%2'</source> <translation type="unfinished">%1 til '%2'</translation> </message> @@ -2916,8 +2932,8 @@ Bemærk: Da gebyret beregnes på per-byte-basis, ville en gebyrsats på "100 sat <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform>Anslået at begynde bekræftelse inden for %n blok(e).</numerusform> - <numerusform>Anslået at begynde bekræftelse inden for %n blok(e).</numerusform> + <numerusform>Anslået at begynde bekræftelse inden for %n blok.</numerusform> + <numerusform>Anslået at begynde bekræftelse inden for %n blokke.</numerusform> </translation> </message> <message> @@ -3022,10 +3038,6 @@ Bemærk: Da gebyret beregnes på per-byte-basis, ville en gebyrsats på "100 sat <translation type="unfinished">&Singér besked</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">Du kan signere beskeder/aftaler med dine adresser for at bevise, at du kan modtage bitcoin, der bliver sendt til adresserne. Vær forsigtig med ikke at signere noget vagt eller tilfældigt, da eventuelle phishing-angreb kan snyde dig til at overlade din identitet til dem. Signér kun fuldt ud detaljerede udsagn, som du er enig i.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin-adresse, som beskeden skal signeres med</translation> </message> @@ -3110,10 +3122,6 @@ Bemærk: Da gebyret beregnes på per-byte-basis, ville en gebyrsats på "100 sat <translation type="unfinished">Tjek venligst adressen og forsøg igen.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Den indtastede adresse henviser ikke til en nøgle.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Tegnebogsoplåsning annulleret.</translation> </message> @@ -3230,8 +3238,8 @@ Bemærk: Da gebyret beregnes på per-byte-basis, ville en gebyrsats på "100 sat <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> - <numerusform>modnes i yderligere %n blok(e)</numerusform> - <numerusform>modnes i yderligere %n blok(e)</numerusform> + <numerusform>modnes i yderligere %n blok</numerusform> + <numerusform>modnes i yderligere %n blokke</numerusform> </translation> </message> <message> @@ -3664,10 +3672,6 @@ Gå til Fil > Åbn Pung for, at indlæse en pung. <source>Can't display address</source> <translation type="unfinished">Adressen kan ikke vises</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Standard tegnebog</translation> - </message> </context> <context> <name>WalletView</name> @@ -3780,10 +3784,6 @@ Gå til Fil > Åbn Pung for, at indlæse en pung. <translation type="unfinished">Der er ikke angivet noget tegnebogsfilformat. For at bruge createfromdump skal -format=<format> angives.</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Undersøg venligst at din computers dato og klokkeslet er korrekt indstillet! Hvis der er fejl i disse, vil %s ikke fungere korrekt.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Overvej venligst at bidrage til udviklingen, hvis du finder %s brugbar. Besøg %s for yderligere information om softwaren.</translation> </message> @@ -3868,10 +3868,6 @@ Gå til Fil > Åbn Pung for, at indlæse en pung. <translation type="unfinished">-maxmempool skal være mindst %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Der er sket en fatal intern fejl, se debug.log for detaljer</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Kan ikke finde -%s-adressen: “%s”</translation> </message> @@ -3888,6 +3884,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 +3896,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 +4088,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 +4104,10 @@ 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 +4208,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..807a1c64ee 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -184,6 +184,14 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Geben Sie die alte und die neue Wallet-Passphrase ein.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Weiter</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Zurück</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">Beachten Sie, dass das Verschlüsseln Ihrer Wallet nicht komplett vor Diebstahl Ihrer Bitcoins durch Malware schützt, die Ihren Computer infiziert hat.</translation> </message> @@ -291,6 +299,10 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Ein schwerwiegender Fehler ist aufgetreten. Überprüfen Sie, ob die Einstellungsdatei beschreibbar ist, oder versuchen Sie, mit -nosettings zu starten.</translation> </message> <message> + <source>Error: %1</source> + <translation type="unfinished">Fehler: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely…</source> <translation type="unfinished">%1 noch nicht sicher beendet…</translation> </message> @@ -366,10 +378,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> @@ -427,7 +435,11 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <numerusform>%n Jahre</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">Standard-Wallet</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -505,7 +517,7 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Die Passphrase ändern, die für die Wallet-Verschlüsselung benutzt wird</translation> + <translation type="unfinished">Ändert die Passphrase, die für die Wallet-Verschlüsselung benutzt wird</translation> </message> <message> <source>&Send</source> @@ -525,7 +537,7 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">Die zu Ihrer Wallet gehörenden privaten Schlüssel verschlüsseln</translation> + <translation type="unfinished">Verschlüsselt die zu Ihrer Wallet gehörenden privaten Schlüssel</translation> </message> <message> <source>&Backup Wallet…</source> @@ -537,7 +549,7 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>Sign &message…</source> - <translation type="unfinished">&Nachricht signieren</translation> + <translation type="unfinished">&Nachricht unterzeichnen…</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> @@ -561,11 +573,11 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">Wallet schließen</translation> + <translation type="unfinished">Schließe Wallet…</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Wallet erstellen…</translation> + <translation type="unfinished">Erstelle Wallet…</translation> </message> <message> <source>Close All Wallets…</source> @@ -589,7 +601,7 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Synchronisiere Header (%1%)…</translation> + <translation type="unfinished">Synchronisiere Headers (%1%)…</translation> </message> <message> <source>Synchronizing with network…</source> @@ -605,126 +617,16 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">Verbinde mit Gegenstellen...</translation> - </message> - <message> - <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Zahlungen anfordern (erzeugt QR-Codes und bitcoin: URIs)</translation> - </message> - <message> - <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Liste verwendeter Zahlungsadressen und Bezeichnungen anzeigen</translation> - </message> - <message> - <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Liste verwendeter Empfangsadressen und Bezeichnungen anzeigen</translation> - </message> - <message> - <source>&Command-line options</source> - <translation type="unfinished">&Kommandozeilenoptionen</translation> + <translation type="unfinished">Verbindung zu Peers wird hergestellt…</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform> %n Block der Transaktionshistorie verarbeitet.</numerusform> - <numerusform> %n Blöcke der Transaktionshistorie verarbeitet.</numerusform> + <numerusform>%n Block der Transaktionshistorie prozessiert.</numerusform> + <numerusform>%n Block/Blöcke der Transaktionshistorie prozessiert.</numerusform> </translation> </message> <message> - <source>%1 behind</source> - <translation type="unfinished">%1 im Rückstand</translation> - </message> - <message> - <source>Catching up…</source> - <translation type="unfinished">Hole auf…</translation> - </message> - <message> - <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">Zuletzt empfangener Block wurde generiert vor %1 .</translation> - </message> - <message> - <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Transaktionen hiernach werden noch nicht angezeigt.</translation> - </message> - <message> - <source>Error</source> - <translation type="unfinished">Fehler</translation> - </message> - <message> - <source>Warning</source> - <translation type="unfinished">Warnung</translation> - </message> - <message> - <source>Information</source> - <translation type="unfinished">Informationen</translation> - </message> - <message> - <source>Up to date</source> - <translation type="unfinished">Auf aktuellem Stand</translation> - </message> - <message> - <source>Ctrl+Q</source> - <translation type="unfinished">STRG+B</translation> - </message> - <message> - <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">Lade teilsignierte Bitcoin-Transaktion</translation> - </message> - <message> - <source>Load PSBT from &clipboard…</source> - <translation type="unfinished">Lade PSBT aus Zwischenablage…</translation> - </message> - <message> - <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">Lade teilsignierte Bitcoin-Transaktion aus Zwischenablage</translation> - </message> - <message> - <source>Node window</source> - <translation type="unfinished">Node-Fenster</translation> - </message> - <message> - <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Öffne Node-Konsole für Fehlersuche und Diagnose</translation> - </message> - <message> - <source>&Sending addresses</source> - <translation type="unfinished">&Versandadressen</translation> - </message> - <message> - <source>&Receiving addresses</source> - <translation type="unfinished">&Empfangsadressen</translation> - </message> - <message> - <source>Open a bitcoin: URI</source> - <translation type="unfinished">Öffne bitcoin: URI</translation> - </message> - <message> - <source>Open Wallet</source> - <translation type="unfinished">Wallet öffnen</translation> - </message> - <message> - <source>Open a wallet</source> - <translation type="unfinished">Eine Wallet öffnen</translation> - </message> - <message> - <source>Close wallet</source> - <translation type="unfinished">Wallet schließen</translation> - </message> - <message> - <source>Restore Wallet…</source> - <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> - <translation type="unfinished">Wallet wiederherstellen...</translation> - </message> - <message> - <source>Restore a wallet from a backup file</source> - <extracomment>Status tip for Restore Wallet menu item</extracomment> - <translation type="unfinished">Wiederherstellen einer Wallet aus einer Sicherungsdatei</translation> - </message> - <message> - <source>Close all wallets</source> - <translation type="unfinished">Schließe alle Wallets</translation> - </message> - <message> <source>Migrate Wallet</source> <translation type="unfinished">Wallet migrieren</translation> </message> @@ -745,10 +647,6 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Blende die Werte im Übersichtsreiter aus</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Keine Wallets verfügbar</translation> </message> @@ -804,8 +702,8 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>%n active connection(s) to Bitcoin network.</numerusform> - <numerusform>%n aktive Verbindung(en) zum Bitcoin-Netzwerk</numerusform> + <numerusform>%n aktive Verbindung zum Bitcoin-Netzwerk</numerusform> + <numerusform>%n aktive Verbindungen zum Bitcoin-Netzwerk</numerusform> </translation> </message> <message> @@ -816,7 +714,7 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <message> <source>Show Peers tab</source> <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment> - <translation type="unfinished">Gegenstellen Reiter anzeigen</translation> + <translation type="unfinished">Reiter mit Peers anzeigen</translation> </message> <message> <source>Disable network activity</source> @@ -830,7 +728,7 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Synchronisiere Header vorab (%1%)…</translation> + <translation type="unfinished">Synchronisiere Header (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -1153,10 +1051,6 @@ Während des Migrationsprozesses wird vor der Migration ein Backup der Wallet er <translation type="unfinished">Wallet öffnen Warnung</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Wallet öffnen</translation> @@ -1226,7 +1120,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> @@ -1530,7 +1424,7 @@ Während des Migrationsprozesses wird vor der Migration ein Backup der Wallet er </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 synchronisiert gerade. Es lädt Header und Blöcke von Gegenstellen und validiert sie bis zum Erreichen der Spitze der Blockchain.</translation> + <translation type="unfinished">%1 synchronisiert gerade. Es lädt Header und Blöcke von Peers und validiert sie bis zum Erreichen der Spitze der Blockchain.</translation> </message> <message> <source>Unknown. Syncing Headers (%1, %2%)…</source> @@ -1749,7 +1643,7 @@ Während des Migrationsprozesses wird vor der Migration ein Backup der Wallet er </message> <message> <source>Used for reaching peers via:</source> - <translation type="unfinished">Benutzt um Gegenstellen zu erreichen über:</translation> + <translation type="unfinished">Benutzt um Peers zu erreichen über:</translation> </message> <message> <source>&Window</source> @@ -1813,7 +1707,7 @@ Während des Migrationsprozesses wird vor der Migration ein Backup der Wallet er </message> <message> <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> - <translation type="unfinished">Nutze separaten SOCKS&5-Proxy um Gegenstellen über Tor-Onion-Dienste zu erreichen:</translation> + <translation type="unfinished">Nutze separaten SOCKS&5-Proxy um Peers über Tor-Onion-Dienste zu erreichen:</translation> </message> <message> <source>&Cancel</source> @@ -2152,11 +2046,6 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">User-Agent</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">Gegenstelle</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">Alter</translation> @@ -2169,7 +2058,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> @@ -2281,6 +2170,14 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">Anzahl der Verbindungen</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Lokale Adressen</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Netzwerk-Adressen, die dein Bitcoin-Node aktuell verwendet, um mit anderen Nodes zu kommunizieren.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Blockchain</translation> </message> @@ -2310,31 +2207,31 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI </message> <message> <source>Sent</source> - <translation type="unfinished">Übertragen</translation> - </message> - <message> - <source>&Peers</source> - <translation type="unfinished">&Gegenstellen</translation> + <translation type="unfinished">Gesendet</translation> </message> <message> <source>Banned peers</source> - <translation type="unfinished">Gesperrte Gegenstellen</translation> + <translation type="unfinished">Gesperrte Peers</translation> </message> <message> <source>Select a peer to view detailed information.</source> - <translation type="unfinished">Gegenstelle auswählen, um detaillierte Informationen zu erhalten.</translation> + <translation type="unfinished">Peers auswählen, um detaillierte Informationen zu erhalten.</translation> </message> <message> - <source>The transport layer version: %1</source> - <translation type="unfinished">Die Transportschicht-Version: %1</translation> + <source>Hide Peers Detail</source> + <translation type="unfinished">Reiter mit Peers verstecken</translation> + </message> + <message> + <source>Ctrl+X</source> + <translation type="unfinished">Strg+X</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Die BIP324-Sitzungs-ID-Zeichenfolge in hexadezimaler Form, falls vorhanden.</translation> + <source>The transport layer version: %1</source> + <translation type="unfinished">Die Transportschicht-Version: %1</translation> </message> <message> <source>Whether we relay transactions to this peer.</source> - <translation type="unfinished">Ob wir Adressen an diese Gegenstelle weiterleiten.</translation> + <translation type="unfinished">Ob wir Adressen an diesen Peer weiterleiten.</translation> </message> <message> <source>Transaction Relay</source> @@ -2358,7 +2255,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI </message> <message> <source>The mapped Autonomous System used for diversifying peer selection.</source> - <translation type="unfinished">Das zugeordnete autonome System zur Diversifizierung der Gegenstellen-Auswahl.</translation> + <translation type="unfinished">Das zugeordnete autonome System zur Diversifizierung der Peer-Auswahl.</translation> </message> <message> <source>Mapped AS</source> @@ -2367,7 +2264,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <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">Ob wir Adressen an diese Gegenstelle weiterleiten.</translation> + <translation type="unfinished">Ob wir Adressen an diesen Peer weiterleiten.</translation> </message> <message> <source>Address Relay</source> @@ -2377,12 +2274,12 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <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">Die Gesamtzahl der von dieser Gegenstelle empfangenen Adressen, die aufgrund von Ratenbegrenzung verworfen (nicht verarbeitet) wurden.</translation> + <translation type="unfinished">Die Gesamtzahl der von diesem Peer empfangenen Adressen, die aufgrund von Ratenbegrenzung verworfen (nicht verarbeitet) wurden.</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">Die Gesamtzahl der von dieser Gegenstelle empfangenen Adressen, die aufgrund von Ratenbegrenzung verworfen (nicht verarbeitet) wurden.</translation> + <translation type="unfinished">Die Gesamtzahl der von diesem Peer empfangenen Adressen, die aufgrund von Ratenbegrenzung verworfen (nicht verarbeitet) wurden.</translation> </message> <message> <source>Addresses Processed</source> @@ -2399,10 +2296,6 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">User-Agent</translation> </message> <message> - <source>Node window</source> - <translation type="unfinished">Node-Fenster</translation> - </message> - <message> <source>Current block height</source> <translation type="unfinished">Aktuelle Blockhöhe</translation> </message> @@ -2424,15 +2317,19 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI </message> <message> <source>The direction and type of peer connection: %1</source> - <translation type="unfinished">Die Richtung und der Typ der Gegenstellen-Verbindung: %1</translation> + <translation type="unfinished">Die Richtung und der Typ der Peer-Verbindung: %1</translation> </message> <message> <source>Direction/Type</source> <translation type="unfinished">Richtung/Typ</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">Die BIP324-Sitzungs-ID-Zeichenfolge in hexadezimaler Form.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> - <translation type="unfinished">Das Netzwerkprotokoll, über das diese Gegenstelle verbunden ist, ist: IPv4, IPv6, Onion, I2P oder CJDNS.</translation> + <translation type="unfinished">Das Netzwerkprotokoll, über das dieser Peer verbunden ist, ist: IPv4, IPv6, Onion, I2P oder CJDNS.</translation> </message> <message> <source>Services</source> @@ -2452,7 +2349,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI </message> <message> <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source> - <translation type="unfinished">Abgelaufene Zeit seitdem ein neuer Block mit erfolgreichen initialen Gültigkeitsprüfungen von dieser Gegenstelle empfangen wurde.</translation> + <translation type="unfinished">Verstrichene Zeit, seit ein neuer Block, der initiale Validierungsprüfungen bestanden hat, von diesem Peer empfangen wurde.</translation> </message> <message> <source>Last Block</source> @@ -2461,7 +2358,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <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">Abgelaufene Zeit seit eine neue Transaktion, die in unseren Speicherpool hineingelassen wurde, von dieser Gegenstelle empfangen wurde.</translation> + <translation type="unfinished">Verstrichene Zeit, seit eine neue Transaktion, die in unseren Mempool aufgenommen wurde, von diesem Peer empfangen wurde.</translation> </message> <message> <source>Last Send</source> @@ -2530,7 +2427,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <message> <source>Inbound: initiated by peer</source> <extracomment>Explanatory text for an inbound peer connection.</extracomment> - <translation type="unfinished">Eingehend: wurde von Gegenstelle initiiert</translation> + <translation type="unfinished">Eingehend: wurde vom Peer initiiert</translation> </message> <message> <source>Outbound Full Relay: default</source> @@ -2560,7 +2457,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <message> <source>detecting: peer could be v1 or v2</source> <extracomment>Explanatory text for "detecting" transport type.</extracomment> - <translation type="unfinished">Erkennen: Peer könnte v1 oder v2 sein</translation> + <translation type="unfinished">Erkenne: Peer könnte v1 oder v2 sein</translation> </message> <message> <source>v1: unencrypted, plaintext transport protocol</source> @@ -2574,11 +2471,11 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI </message> <message> <source>we selected the peer for high bandwidth relay</source> - <translation type="unfinished">Wir haben die Gegenstelle zum Weiterleiten mit hoher Bandbreite ausgewählt</translation> + <translation type="unfinished">Wir haben den Peer zum Weiterleiten mit hoher Bandbreite ausgewählt</translation> </message> <message> <source>the peer selected us for high bandwidth relay</source> - <translation type="unfinished">Die Gegenstelle hat uns zum Weiterleiten mit hoher Bandbreite ausgewählt</translation> + <translation type="unfinished">Der Peer hat uns zum Weiterleiten mit hoher Bandbreite ausgewählt</translation> </message> <message> <source>no high bandwidth relay selected</source> @@ -2643,6 +2540,10 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">Netzwerkaktivität deaktiviert</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Keine</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Befehl wird ohne spezifizierte Wallet ausgeführt</translation> </message> @@ -2685,7 +2586,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> @@ -2694,7 +2595,7 @@ Für weitere Informationen über diese Konsole, tippe %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(Gegenstelle: %1)</translation> + <translation type="unfinished">(Peer: %1)</translation> </message> <message> <source>via %1</source> @@ -3042,7 +2943,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 +3025,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> @@ -3373,8 +3274,8 @@ Hinweis: Da die Gebühr auf Basis der Bytes berechnet wird, führt eine Gebühre <translation type="unfinished">Nachricht &signieren</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">Sie können Nachrichten/Vereinbarungen mit Hilfe Ihrer Adressen signieren, um zu beweisen, dass Sie Bitcoins empfangen können, die an diese Adressen überwiesen werden. Seien Sie vorsichtig und signieren Sie nichts Vages oder Willkürliches, um Ihre Indentität vor Phishingangriffen zu schützen. Signieren Sie nur vollständig-detaillierte Aussagen, mit denen Sie auch einverstanden sind.</translation> + <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">Du kannst Nachrichten/Vereinbarungen mit Deinen Legacy-(P2PKH)-Adressen unterzeichnen, um zu beweisen, dass Du Bitcoins empfangen kannst, die an sie gesendet werden. Achte darauf, nichts Vages oder Zufälliges zu signieren, da Phishing-Angriffe versuchen könnten, Dich dazu zu verleiten, Deine Identität zu unterschreiben. Unterschreibe nur ausführliche Erklärungen, denen Du zustimmst.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3461,8 +3362,8 @@ Hinweis: Da die Gebühr auf Basis der Bytes berechnet wird, führt eine Gebühre <translation type="unfinished">Bitte überprüfen Sie die Adresse und versuchen Sie es erneut.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Die eingegebene Adresse verweist nicht auf einen Schlüssel.</translation> + <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">Die eingegebene Adresse bezieht sich nicht auf einen Legacy-Schlüssel (P2PKH). Die Nachrichtensignierung für SegWit und andere Adresstypen, die nicht zu P2PKH gehören, wird in dieser Version von %1 nicht unterstützt. Bitte überprüfe die Adresse und versuche es erneut.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -4030,9 +3931,8 @@ Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. <translation type="unfinished">PSBT kopiert</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">In die Zwischenablage kopiert </translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Fee-Bump PSBT in die Zwischenablage kopiert</translation> </message> <message> <source>Can't sign transaction.</source> @@ -4043,12 +3943,12 @@ Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. <translation type="unfinished">Konnte Transaktion nicht übergeben</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Die Adresse kann nicht angezeigt werden</translation> + <source>Signer error</source> + <translation type="unfinished">Fehler beim Signieren</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</translation> + <source>Can't display address</source> + <translation type="unfinished">Die Adresse kann nicht angezeigt werden</translation> </message> </context> <context> @@ -4107,7 +4007,7 @@ Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. </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 Aufforderung, auf Port %u zu lauschen. Dieser Port wird als "schlecht" eingeschätzt und es ist daher unwahrscheinlich, dass sich Bitcoin Core Gegenstellen mit ihm verbinden. Siehe doc/p2p-bad-ports.md für Details und eine vollständige Liste.</translation> + <translation type="unfinished">%s Aufforderung, auf Port %u zu lauschen. Dieser Port wird als "schlecht" eingeschätzt und es ist daher unwahrscheinlich, dass sich Peers mit ihm verbinden. Siehe doc/p2p-bad-ports.md für Details und eine vollständige Liste.</translation> </message> <message> <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> @@ -4182,10 +4082,6 @@ Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. <translation type="unfinished">Kein Format der Wallet-Datei angegeben. Um createfromdump zu nutzen, muss -format=<format> angegeben werden.</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">Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da %s ansonsten nicht ordnungsgemäß funktionieren wird.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Wenn sie %s nützlich finden, sind Helfer sehr gern gesehen. Besuchen Sie %s um mehr über das Softwareprojekt zu erfahren.</translation> </message> @@ -4276,7 +4172,7 @@ Bitte nutzen Sie entweder "bdb" oder "sqlite".</translation> </message> <message> <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> - <translation type="unfinished">Warnung: Wir scheinen nicht vollständig mit unseren Gegenstellen übereinzustimmen! Sie oder die anderen Knoten müssen unter Umständen Ihre Client-Software aktualisieren.</translation> + <translation type="unfinished">Warnung: Wir scheinen nicht vollständig mit unseren Peers übereinzustimmen! Sie oder die anderen Knoten müssen unter Umständen Ihre Client-Software aktualisieren.</translation> </message> <message> <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> @@ -4291,10 +4187,6 @@ Bitte nutzen Sie entweder "bdb" oder "sqlite".</translation> <translation type="unfinished">-maxmempool muss mindestens %d MB betragen</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ein fataler interner Fehler ist aufgetreten, siehe debug.log für Details</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Kann Adresse in -%s nicht auflösen: '%s'</translation> </message> @@ -4343,6 +4235,12 @@ Bitte nutzen Sie entweder "bdb" oder "sqlite".</translation> <translation type="unfinished">Es war nicht möglich, die Bump-Gebühren zu berechnen, da unbestätigte UTXOs von einem enormen Cluster unbestätigter Transaktionen abhängen.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Fehler beim Entfernen des Snapshot-Chainstate-Verzeichnisses (%s). Entferne es manuell, bevor dem Neustart. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">Kann ungültige Datei peers.dat nicht umbenennen. Bitte Verschieben oder Löschen und noch einmal versuchen.</translation> </message> @@ -4351,6 +4249,14 @@ Bitte nutzen Sie entweder "bdb" oder "sqlite".</translation> <translation type="unfinished">Gebührenschätzung fehlgeschlagen. Fallbackgebühr ist deaktiviert. Warten Sie ein paar Blöcke oder aktivieren Sie %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Fehler beim Leeren der Blockdatei auf die Festplatte. Dies ist wahrscheinlich das Ergebnis eines E/A-Fehlers.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Fehler beim Leeren der Undo-Datei auf den Datenträger. Dies ist wahrscheinlich das Ergebnis eines E/A-Fehlers.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Inkompatible Optionen: -dnsseed=1 wurde explizit angegeben, aber -onlynet verbietet Verbindungen zu IPv4/IPv6</translation> </message> @@ -4359,6 +4265,14 @@ Bitte nutzen Sie entweder "bdb" oder "sqlite".</translation> <translation type="unfinished">Ungültiger Betrag für %s=<amount>: '%s' (muss mindestens die MinRelay-Gebühr von %s betragen, um festhängende Transaktionen zu verhindern)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Das maximale Transaktionsgewicht ist kleiner als das Transaktionsgewicht ohne Inputs</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Das maximale Transaktionsgewicht ist zu niedrig und kann den Change-Output nicht aufnehmen</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Ausgehende Verbindungen sind auf CJDNS beschränkt (-onlynet=cjdns), aber -cjdnsreachable ist nicht angegeben</translation> </message> @@ -4375,6 +4289,14 @@ Bitte nutzen Sie entweder "bdb" oder "sqlite".</translation> <translation type="unfinished">Ausgehende Verbindungen sind auf i2p (-onlynet=i2p) beschränkt, aber -i2psam ist nicht angegeben</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Die Umbenennung von '%s' -> '%s' ist fehlgeschlagen. Das Hintergrund-Verzeichnis chainstate leveldb kann nicht bereinigt werden.</translation> + </message> + <message> + <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">Die Kombination aus den vorausgewählten Inputs und der automatischen Auswahl der Wallet-Inputs überschreitet das maximale Transaktionsgewicht. Bitte versuche, einen kleineren Betrag zu senden oder die UTXOs der Wallet manuell zu konsolidieren.</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">Die Größe der Inputs übersteigt das maximale Gewicht. Bitte versuchen Sie, einen kleineren Betrag zu senden oder die UTXOs Ihrer Wallet manuell zu konsolidieren.</translation> </message> @@ -4417,6 +4339,10 @@ Bitte mit der neuesten Softwareversion versuchen. </translation> </message> <message> + <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">Das Datum und die Uhrzeit des Computers scheinen mehr als %d Minuten nicht mit dem Netzwerk synchronisiert zu sein, was zu einem Konsensus-Fehler führen kann. Nachdem die Uhr des Computers überprüft wurde und der Node neu gestatet wurde, sollte diese Meldung nicht mehr angezeigt werden. Ohne Neustart sollte es nicht mehr automatisch angezeigt werden, nachdem eine Verbindung mit einer ausreichenden Anzahl neuer ausgehender Peers hergestellt wurde, was einige Zeit dauern kann. Das Feld 'timeoffset' der RPC-Methoden 'getpeerinfo' und 'getnetworkinfo' kann überprüft werden, um weitere Informationen zu erhalten.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4429,6 +4355,18 @@ Unable to restore backup of wallet.</source> Die Sicherung der Wallet kann nicht wiederhergestellt werden.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind darf nur für eingehende Verbindungen verwendet werden ("out" wurde übergeben)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Es ist ein schwerwiegender interner Fehler aufgetreten, siehe debug.log für Details:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Für den angegebenen Blockhash '%s' wurden keine Assumeutxo-Daten gefunden.</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">Blocküberprüfung wurde unterbrochen</translation> </message> @@ -4437,6 +4375,10 @@ Die Sicherung der Wallet kann nicht wiederhergestellt werden.</translation> <translation type="unfinished">Konfigurationseinstellungen für %s sind nur auf %s network gültig, wenn in Sektion [%s]</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Beschädigter Block gefunden, was auf einen möglichen Hardwarefehler hinweist.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Beschädigte Blockdatenbank erkannt</translation> </message> @@ -4465,6 +4407,10 @@ Die Sicherung der Wallet kann nicht wiederhergestellt werden.</translation> <translation type="unfinished">Speicherauszugsdatei %sexistiert nicht.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fehler bei der Plausibilitätsprüfung der Elliptischen Kurvenkryptografie. %s wird heruntergefahren.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Fehler beim Bestätigen der Datenbanktransaktion für die Entfernung der Wallet-Transaktionen.</translation> </message> @@ -4614,10 +4560,22 @@ Berechnet: %s, erwartet: %s</translation> <translation type="unfinished">Fehler: Datenbank-Transaktion kann für Wallet %s nicht ausgeführt werden.</translation> </message> <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">Verbindung zum besten Block (%s) konnte nicht hergestellt werden.</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Block konnte nicht getrennt werden.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Fehler: Konnte auf keinem Port hören. Wenn dies so gewünscht wird -listen=0 verwenden.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Block konnte nicht gelesen werden.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Fehler: Wallet konnte während der Initialisierung nicht erneut gescannt werden.</translation> </message> @@ -4630,6 +4588,22 @@ Berechnet: %s, erwartet: %s</translation> <translation type="unfinished">Verifizierung der Datenbank fehlgeschlagen</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">Block konnte nicht geschrieben werden.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Schreiben in die Blockindex-Datenbank fehlgeschlagen.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Schreiben in die Coin-Datenbank fehlgeschlagen.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Das Schreiben der Undo-Daten ist fehlgeschlagen.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">Fehler beim Entfernen der Transaktion: %s</translation> </message> @@ -4726,6 +4700,10 @@ Berechnet: %s, erwartet: %s</translation> <translation type="unfinished">Lade Wallet...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Das maximale Transaktionsgewicht muss zwischen %d und %d liegen.</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Fehlender Betrag</translation> </message> @@ -4754,6 +4732,10 @@ Berechnet: %s, erwartet: %s</translation> <translation type="unfinished">Nicht auflösbare vorausgewählter Input %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Nur Richtung wurde festgelegt, keine Genehmigungen: '%s'</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Kürzungsmodus kann nicht mit einem negativen Wert konfiguriert werden.</translation> </message> @@ -4799,6 +4781,18 @@ Verifikations-Error: %s</translation> <translation type="unfinished">Sektion [%s] ist nicht delegiert.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Der Signierer hat die Adresse nicht wiederholt</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">Unterzeichner wiederholte unerwartete Adresse %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Der Signierer hat einen Fehler zurückgegeben: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Signierung der Transaktion fehlgeschlagen</translation> </message> @@ -4827,6 +4821,18 @@ Verifikations-Error: %s</translation> <translation type="unfinished">Starte Netzwerk-Threads...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Systemfehler beim Leeren: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Systemfehler beim Laden der externen Blockdatei: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Systemfehler beim Speichern des Blocks auf der Festplatte: %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Der Quellcode ist auf %s verfügbar.</translation> </message> @@ -4843,6 +4849,10 @@ Verifikations-Error: %s</translation> <translation type="unfinished">Das Wallet verhindert Zahlungen, die die Mindesttransaktionsgebühr nicht berücksichtigen.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Für diese Adresse gibt es keinen ScriptPubKeyManager</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Dies ist experimentelle Software.</translation> </message> @@ -4883,10 +4893,6 @@ Verifikations-Error: %s</translation> <translation type="unfinished">Transaktion zu groß</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Speicher kann für -maxsigcachesize: '%s' MiB nicht zugewiesen werden:</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Kann auf diesem Computer nicht an %s binden (bind meldete Fehler %s)</translation> </message> @@ -4947,6 +4953,10 @@ Verifikations-Error: %s</translation> <translation type="unfinished">Unbekannte neue Regeln aktiviert (Versionsbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Nicht erkannte Option "%s" in -test=<option> angegeben.</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished">Nicht unterstützte globale Protokollierungsebene %s=%s. Gültige Werte: %s.</translation> </message> diff --git a/src/qt/locale/bitcoin_de_AT.ts b/src/qt/locale/bitcoin_de_AT.ts index 72ec23d469..1c597c6866 100644 --- a/src/qt/locale/bitcoin_de_AT.ts +++ b/src/qt/locale/bitcoin_de_AT.ts @@ -1,749 +1,70 @@ <TS version="2.1" language="de_AT"> <context> - <name>AddressBookPage</name> - <message> - <source>Right-click to edit address or label</source> - <translation type="unfinished">Rechtsklick zum Bearbeiten der Adresse oder der Beschreibung</translation> - </message> - <message> - <source>Create a new address</source> - <translation type="unfinished">Neue Adresse erstellen</translation> - </message> - <message> - <source>&New</source> - <translation type="unfinished">&Neu</translation> - </message> - <message> - <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Ausgewählte Adresse in die Zwischenablage kopieren</translation> - </message> - <message> - <source>&Copy</source> - <translation type="unfinished">&Kopieren</translation> - </message> - <message> - <source>C&lose</source> - <translation type="unfinished">&Schließen</translation> - </message> - <message> - <source>Delete the currently selected address from the list</source> - <translation type="unfinished">Ausgewählte Adresse aus der Liste entfernen</translation> - </message> - <message> - <source>Enter address or label to search</source> - <translation type="unfinished">Zu suchende Adresse oder Bezeichnung eingeben</translation> - </message> - <message> - <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Daten der aktuellen Ansicht in eine Datei exportieren</translation> - </message> - <message> - <source>&Export</source> - <translation type="unfinished">&Exportieren</translation> - </message> - <message> - <source>&Delete</source> - <translation type="unfinished">&Löschen</translation> - </message> - <message> - <source>Choose the address to send coins to</source> - <translation type="unfinished">Wählen Sie die Adresse aus, an die Sie Bitcoins senden möchten</translation> - </message> - <message> - <source>Choose the address to receive coins with</source> - <translation type="unfinished">Wählen Sie die Adresse aus, mit der Sie Bitcoins empfangen wollen</translation> - </message> - <message> - <source>C&hoose</source> - <translation type="unfinished">&Auswählen</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">Dies sind Ihre Bitcoin-Adressen zum Tätigen von Überweisungen. Bitte prüfen Sie den Betrag und die Adresse des Empfängers, bevor Sie Bitcoins überweisen.</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">Dies sind Ihre Bitcoin-Adressen für den Empfang von Zahlungen. Verwenden Sie die 'Neue Empfangsadresse erstellen' Taste auf der Registerkarte "Empfangen", um neue Adressen zu erstellen. -Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> - </message> - <message> - <source>&Copy Address</source> - <translation type="unfinished">&Adresse kopieren</translation> - </message> - <message> - <source>Copy &Label</source> - <translation type="unfinished">&Bezeichnung kopieren</translation> - </message> - <message> - <source>&Edit</source> - <translation type="unfinished">&Bearbeiten</translation> - </message> - <message> - <source>Export Address List</source> - <translation type="unfinished">Adressliste exportieren</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">Durch Komma getrennte Datei</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">Beim Speichern der Adressliste nach %1 ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.</translation> - </message> - <message> - <source>Sending addresses - %1</source> - <translation type="unfinished">Sendeadressen - %1</translation> - </message> - <message> - <source>Receiving addresses - %1</source> - <translation type="unfinished">Empfangsadressen - %1</translation> - </message> - <message> - <source>Exporting Failed</source> - <translation type="unfinished">Exportieren fehlgeschlagen</translation> - </message> -</context> -<context> - <name>AddressTableModel</name> - <message> - <source>Label</source> - <translation type="unfinished">Bezeichnung</translation> - </message> - <message> - <source>Address</source> - <translation type="unfinished">Adresse</translation> - </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(keine Bezeichnung)</translation> - </message> -</context> -<context> - <name>AskPassphraseDialog</name> - <message> - <source>Passphrase Dialog</source> - <translation type="unfinished">Passphrasendialog</translation> - </message> - <message> - <source>Enter passphrase</source> - <translation type="unfinished">Passphrase eingeben</translation> - </message> - <message> - <source>New passphrase</source> - <translation type="unfinished">Neue Passphrase</translation> - </message> - <message> - <source>Repeat new passphrase</source> - <translation type="unfinished">Neue Passphrase bestätigen</translation> - </message> - <message> - <source>Show passphrase</source> - <translation type="unfinished">Zeige Passphrase</translation> - </message> - <message> - <source>Encrypt wallet</source> - <translation type="unfinished">Wallet verschlüsseln</translation> - </message> - <message> - <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">Dieser Vorgang benötigt Ihre Passphrase, um die Wallet zu entsperren.</translation> - </message> - <message> - <source>Unlock wallet</source> - <translation type="unfinished">Wallet entsperren</translation> - </message> - <message> - <source>Change passphrase</source> - <translation type="unfinished">Passphrase ändern</translation> - </message> - <message> - <source>Confirm wallet encryption</source> - <translation type="unfinished">Wallet-Verschlüsselung bestätigen</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">Warnung: Wenn Sie Ihre Wallet verschlüsseln und Ihre Passphrase verlieren, werden Sie <b>ALLE IHRE BITCOINS VERLIEREN</b>!</translation> - </message> - <message> - <source>Are you sure you wish to encrypt your wallet?</source> - <translation type="unfinished">Sind Sie sich sicher, dass Sie Ihre Wallet verschlüsseln möchten?</translation> - </message> - <message> - <source>Wallet encrypted</source> - <translation type="unfinished">Wallet verschlüsselt</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">Geben Sie die neue Passphrase für die Wallet ein.<br/>Bitte benutzen Sie eine Passphrase bestehend aus <b>zehn oder mehr zufälligen Zeichen</b> oder <b>acht oder mehr Wörtern</b>.</translation> - </message> - <message> - <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation type="unfinished">Geben Sie die alte und die neue Wallet-Passphrase ein.</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">Beachten Sie, dass das Verschlüsseln Ihrer Wallet nicht komplett vor Diebstahl Ihrer Bitcoins durch Malware schützt, die Ihren Computer infiziert hat.</translation> - </message> - <message> - <source>Wallet to be encrypted</source> - <translation type="unfinished">Wallet zu verschlüsseln</translation> - </message> - <message> - <source>Your wallet is about to be encrypted. </source> - <translation type="unfinished">Wallet wird verschlüsselt.</translation> - </message> - <message> - <source>Your wallet is now encrypted. </source> - <translation type="unfinished">Deine Wallet ist jetzt verschlüsselt.</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">WICHTIG: Alle vorherigen Wallet-Backups sollten durch die neu erzeugte, verschlüsselte Wallet ersetzt werden. Aus Sicherheitsgründen werden vorherige Backups der unverschlüsselten Wallet nutzlos, sobald Sie die neue, verschlüsselte Wallet verwenden.</translation> - </message> - <message> - <source>Wallet encryption failed</source> - <translation type="unfinished">Wallet-Verschlüsselung fehlgeschlagen</translation> - </message> - <message> - <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">Die Wallet-Verschlüsselung ist aufgrund eines internen Fehlers fehlgeschlagen. Ihre Wallet wurde nicht verschlüsselt.</translation> - </message> - <message> - <source>The supplied passphrases do not match.</source> - <translation type="unfinished">Die eingegebenen Passphrasen stimmen nicht überein.</translation> - </message> - <message> - <source>Wallet unlock failed</source> - <translation type="unfinished">Wallet-Entsperrung fehlgeschlagen.</translation> - </message> - <message> - <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">Die eingegebene Passphrase zur Wallet-Entschlüsselung war nicht korrekt.</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">Die für die Entschlüsselung der Wallet eingegebene Passphrase ist falsch. Sie enthält ein Null-Zeichen (d.h. ein Null-Byte). Wenn die Passphrase mit einer Version dieser Software vor 25.0 festgelegt wurde, versuchen Sie es bitte erneut mit den Zeichen bis zum ersten Null-Zeichen, aber ohne dieses. Wenn dies erfolgreich ist, setzen Sie bitte eine neue Passphrase, um dieses Problem in Zukunft zu vermeiden.</translation> - </message> - <message> - <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">Die Wallet-Passphrase wurde erfolgreich geändert.</translation> - </message> - <message> - <source>Passphrase change failed</source> - <translation type="unfinished">Änderung der Passphrase fehlgeschlagen</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">Die alte Passphrase, die für die Entschlüsselung der Wallet eingegeben wurde, ist falsch. Sie enthält ein Null-Zeichen (d.h. ein Null-Byte). Wenn die Passphrase mit einer Version dieser Software vor 25.0 festgelegt wurde, versuchen Sie es bitte erneut mit den Zeichen bis zum ersten Null-Zeichen, aber ohne dieses.</translation> - </message> - <message> - <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished">Warnung: Die Feststelltaste ist aktiviert!</translation> - </message> -</context> -<context> - <name>BanTableModel</name> - <message> - <source>IP/Netmask</source> - <translation type="unfinished">IP/Netzmaske</translation> - </message> - <message> - <source>Banned Until</source> - <translation type="unfinished">Gesperrt bis</translation> - </message> -</context> -<context> - <name>BitcoinApplication</name> - <message> - <source>Settings file %1 might be corrupt or invalid.</source> - <translation type="unfinished">Die Einstellungsdatei %1 ist möglicherweise beschädigt oder ungültig.</translation> - </message> - <message> - <source>Runaway exception</source> - <translation type="unfinished">Ausreisser Ausnahme</translation> - </message> - <message> - <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> - <translation type="unfinished">Ein fataler Fehler ist aufgetreten. %1 kann nicht länger sicher fortfahren und wird beendet.</translation> - </message> - <message> - <source>Internal error</source> - <translation type="unfinished">Interner Fehler</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">Ein interner Fehler ist aufgetreten. %1 wird versuchen, sicher fortzufahren. Dies ist ein unerwarteter Fehler, der wie unten beschrieben, gemeldet werden kann.</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">Möchten Sie Einstellungen auf Standardwerte zurücksetzen oder abbrechen, ohne Änderungen vorzunehmen?</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">Ein schwerwiegender Fehler ist aufgetreten. Überprüfen Sie, ob die Einstellungsdatei beschreibbar ist, oder versuchen Sie, mit -nosettings zu starten.</translation> - </message> - <message> - <source>Error: %1</source> - <translation type="unfinished">Fehler: %1</translation> - </message> - <message> - <source>%1 didn't yet exit safely…</source> - <translation type="unfinished">%1 noch nicht sicher beendet…</translation> - </message> - <message> - <source>unknown</source> - <translation type="unfinished">unbekannt</translation> - </message> - <message> - <source>Embedded "%1"</source> - <translation type="unfinished">Eingebettet "%1"</translation> - </message> - <message> - <source>Default system font "%1"</source> - <translation type="unfinished">Standard Systemschriftart "%1"</translation> - </message> - <message> - <source>Custom…</source> - <translation type="unfinished">Benutzerdefiniert...</translation> - </message> - <message> - <source>Amount</source> - <translation type="unfinished">Betrag</translation> - </message> - <message> - <source>Enter a Bitcoin address (e.g. %1)</source> - <translation type="unfinished">Bitcoin-Adresse eingeben (z.B. %1)</translation> - </message> - <message> - <source>Ctrl+W</source> - <translation type="unfinished">Strg+W</translation> - </message> - <message> - <source>Unroutable</source> - <translation type="unfinished">Nicht weiterleitbar</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">Eingehend</translation> - </message> - <message> - <source>Outbound</source> - <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment> - <translation type="unfinished">Ausgehend</translation> - </message> - <message> - <source>Full Relay</source> - <extracomment>Peer connection type that relays all network information.</extracomment> - <translation type="unfinished">Volles Relais</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">Blockrelais</translation> - </message> - <message> - <source>Manual</source> - <extracomment>Peer connection type established manually through one of several methods.</extracomment> - <translation type="unfinished">Manuell</translation> - </message> - <message> - <source>Feeler</source> - <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment> - <translation type="unfinished">Fühler</translation> - </message> - <message> - <source>Address Fetch</source> - <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment> - <translation type="unfinished">Adress Abholung</translation> - </message> - <message> - <source>%1 d</source> - <translation type="unfinished">%1 T</translation> - </message> - <message> - <source>%1 m</source> - <translation type="unfinished">%1 min</translation> - </message> - <message> - <source>None</source> - <translation type="unfinished">Keine</translation> - </message> - <message> - <source>N/A</source> - <translation type="unfinished">k.A.</translation> - </message> <message numerus="yes"> <source>%n second(s)</source> <translation type="unfinished"> - <numerusform>%n Sekunde</numerusform> - <numerusform>%n Sekunden</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>%n Minute</numerusform> - <numerusform>%n Minuten</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>%nStunde</numerusform> - <numerusform>%n Stunden</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>%nTag</numerusform> - <numerusform>%n Tage</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>%n Woche</numerusform> - <numerusform>%n Wochen</numerusform> + <numerusform>%n week(s)</numerusform> + <numerusform>%n week(s)</numerusform> </translation> </message> - <message> - <source>%1 and %2</source> - <translation type="unfinished">%1 und %2</translation> - </message> <message numerus="yes"> <source>%n year(s)</source> <translation type="unfinished"> - <numerusform>%nJahr</numerusform> - <numerusform>%n Jahre</numerusform> + <numerusform>%n year(s)</numerusform> + <numerusform>%n year(s)</numerusform> </translation> </message> </context> <context> <name>BitcoinGUI</name> - <message> - <source>&Overview</source> - <translation type="unfinished">und Übersicht</translation> - </message> - <message> - <source>Show general overview of wallet</source> - <translation type="unfinished">Allgemeine Übersicht des Wallets anzeigen.</translation> - </message> - <message> - <source>&Transactions</source> - <translation type="unfinished">Und Überträgen </translation> - </message> - <message> - <source>Create a new wallet</source> - <translation type="unfinished">Neues Wallet erstellen</translation> - </message> - <message> - <source>&Options…</source> - <translation type="unfinished">weitere Möglichkeiten/Einstellungen </translation> - </message> - <message> - <source>&Verify message…</source> - <translation type="unfinished">Nachricht bestätigen </translation> - </message> - <message> - <source>&Help</source> - <translation type="unfinished">&Hilfe</translation> - </message> - <message> - <source>Connecting to peers…</source> - <translation type="unfinished">Verbinde mit Peers...</translation> - </message> - <message> - <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Zahlungen anfordern (erzeugt QR-Codes und "bitcoin:"-URIs)</translation> - </message> - <message> - <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Liste verwendeter Zahlungsadressen und Bezeichnungen anzeigen</translation> - </message> - <message> - <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Liste verwendeter Empfangsadressen und Bezeichnungen anzeigen</translation> - </message> - <message> - <source>&Command-line options</source> - <translation type="unfinished">&Kommandozeilenoptionen</translation> - </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform> %n Block der Transaktionshistorie verarbeitet.</numerusform> - <numerusform> %n Blöcke der Transaktionshistorie verarbeitet.</numerusform> + <numerusform>Processed %n block(s) of transaction history.</numerusform> + <numerusform>Processed %n block(s) of transaction history.</numerusform> </translation> </message> - <message> - <source>%1 behind</source> - <translation type="unfinished">%1 im Rückstand</translation> - </message> - <message> - <source>Catching up…</source> - <translation type="unfinished">Hole auf…</translation> - </message> - <message> - <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">Der letzte empfangene Block ist %1 alt.</translation> - </message> - <message> - <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Transaktionen hiernach werden noch nicht angezeigt.</translation> - </message> - <message> - <source>Error</source> - <translation type="unfinished">Fehler</translation> - </message> - <message> - <source>Warning</source> - <translation type="unfinished">Warnung</translation> - </message> - <message> - <source>Information</source> - <translation type="unfinished">Hinweis</translation> - </message> - <message> - <source>Up to date</source> - <translation type="unfinished">Auf aktuellem Stand</translation> - </message> - <message> - <source>Ctrl+Q</source> - <translation type="unfinished">STRG+Q</translation> - </message> - <message> - <source>Restore Wallet…</source> - <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> - <translation type="unfinished">Wallet wiederherstellen...</translation> - </message> - <message> - <source>Restore a wallet from a backup file</source> - <extracomment>Status tip for Restore Wallet menu item</extracomment> - <translation type="unfinished">Wiederherstellen einer Wallet aus einer Sicherungsdatei</translation> - </message> - <message> - <source>Close all wallets</source> - <translation type="unfinished">Schließe alle Wallets</translation> - </message> - <message> - <source>Migrate Wallet</source> - <translation type="unfinished">Wallet migrieren</translation> - </message> - <message> - <source>Migrate a wallet</source> - <translation type="unfinished">Eine Wallet Migrieren</translation> - </message> - <message> - <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation type="unfinished">Zeige den "%1"-Hilfetext, um eine Liste mit möglichen Kommandozeilenoptionen zu erhalten</translation> - </message> - <message> - <source>&Mask values</source> - <translation type="unfinished">&Blende Werte aus</translation> - </message> - <message> - <source>Mask the values in the Overview tab</source> - <translation type="unfinished">Blende die Werte im Übersichtsreiter aus</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</translation> - </message> - <message> - <source>No wallets available</source> - <translation type="unfinished">Keine Wallets verfügbar</translation> - </message> - <message> - <source>Wallet Data</source> - <extracomment>Name of the wallet data file format.</extracomment> - <translation type="unfinished">Wallet-Daten</translation> - </message> - <message> - <source>Load Wallet Backup</source> - <extracomment>The title for Restore Wallet File Windows</extracomment> - <translation type="unfinished">Wallet-Backup laden</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">Wallet wiederherstellen...</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">Wallet-Name</translation> - </message> - <message> - <source>&Window</source> - <translation type="unfinished">&Programmfenster</translation> - </message> - <message> - <source>Ctrl+M</source> - <translation type="unfinished">STRG+M</translation> - </message> - <message> - <source>Zoom</source> - <translation type="unfinished">Vergrößern</translation> - </message> - <message> - <source>Main Window</source> - <translation type="unfinished">Hauptfenster</translation> - </message> - <message> - <source>%1 client</source> - <translation type="unfinished">%1 Client</translation> - </message> - <message> - <source>&Hide</source> - <translation type="unfinished">&Ausblenden</translation> - </message> - <message> - <source>S&how</source> - <translation type="unfinished">&Anzeigen</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 aktive Verbindung zum Bitcoin-Netzwerk</numerusform> - <numerusform>%n aktive Verbindung(en) zum Bitcoin-Netzwerk</numerusform> + <numerusform>%n active connection(s) to Bitcoin network.</numerusform> + <numerusform>%n active connection(s) to Bitcoin network.</numerusform> </translation> </message> - <message> - <source>Click for more actions.</source> - <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> - <translation type="unfinished">Klicken für sonstige Aktionen.</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">Gegenstellen Reiter anzeigen</translation> - </message> - <message> - <source>Disable network activity</source> - <extracomment>A context menu item.</extracomment> - <translation type="unfinished">Netzwerk Aktivität ausschalten</translation> - </message> - <message> - <source>Enable network activity</source> - <extracomment>A context menu item. The network activity was disabled previously.</extracomment> - <translation type="unfinished">Netzwerk Aktivität einschalten</translation> - </message> - <message> - <source>Error creating wallet</source> - <translation type="unfinished">Fehler beim Erstellen der Wallet</translation> - </message> - <message> - <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> - <translation type="unfinished">Es kann keine neue Wallet erstellt werden, die Software wurde ohne SQLite-Unterstützung kompiliert (erforderlich für Deskriptor-Wallets)</translation> - </message> - <message> - <source>Error: %1</source> - <translation type="unfinished">Fehler: %1</translation> - </message> - <message> - <source>Warning: %1</source> - <translation type="unfinished">Warnung: %1</translation> - </message> - <message> - <source>Date: %1 -</source> - <translation type="unfinished">Datum: %1 -</translation> - </message> - <message> - <source>Amount: %1 -</source> - <translation type="unfinished">Betrag: %1 -</translation> - </message> - <message> - <source>Type: %1 -</source> - <translation type="unfinished">Typ: %1 -</translation> - </message> - <message> - <source>Label: %1 -</source> - <translation type="unfinished">Bezeichnung: %1 -</translation> - </message> - <message> - <source>Address: %1 -</source> - <translation type="unfinished">Adresse: %1 -</translation> - </message> - <message> - <source>Sent transaction</source> - <translation type="unfinished">Gesendete Transaktion</translation> - </message> - <message> - <source>Incoming transaction</source> - <translation type="unfinished">Eingehende Transaktion</translation> - </message> - <message> - <source>HD key generation is <b>enabled</b></source> - <translation type="unfinished">HD Schlüssel Generierung ist <b>aktiviert</b></translation> - </message> - <message> - <source>HD key generation is <b>disabled</b></source> - <translation type="unfinished">HD Schlüssel Generierung ist <b>deaktiviert</b></translation> - </message> - <message> - <source>Private key <b>disabled</b></source> - <translation type="unfinished">Privater Schlüssel <b>deaktiviert</b></translation> - </message> - <message> - <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">Wallet ist <b>verschlüsselt</b> und aktuell <b>entsperrt</b>.</translation> - </message> - <message> - <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">Wallet ist <b>verschlüsselt</b> und aktuell <b>gesperrt</b></translation> - </message> - <message> - <source>Original message:</source> - <translation type="unfinished">Original-Nachricht:</translation> - </message> -</context> -<context> - <name>UnitDisplayStatusBarControl</name> - <message> - <source>Unit to show amounts in. Click to select another unit.</source> - <translation type="unfinished">Die Einheit in der Beträge angezeigt werden. Klicken, um eine andere Einheit auszuwählen.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> - <source>Coin Selection</source> - <translation type="unfinished">Münzauswahl ("Coin Control")</translation> - </message> - <message> - <source>Quantity:</source> - <translation type="unfinished">Anzahl:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">Betrag:</translation> - </message> - <message> - <source>Fee:</source> - <translation type="unfinished">Gebühr:</translation> - </message> - <message> <source>After Fee:</source> <translation type="unfinished">Abzüglich Gebühr:</translation> </message> @@ -832,14 +153,6 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Bytes kopieren</translation> </message> <message> - <source>Copy change</source> - <translation type="unfinished">Wechselgeld kopieren</translation> - </message> - <message> - <source>(%1 locked)</source> - <translation type="unfinished">(%1 gesperrt)</translation> - </message> - <message> <source>Can vary +/- %1 satoshi(s) per input.</source> <translation type="unfinished">Kann pro Eingabe um +/- %1 Satoshi(s) abweichen.</translation> </message> @@ -899,3898 +212,67 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> </context> <context> - <name>MigrateWalletActivity</name> - <message> - <source>Migrate wallet</source> - <translation type="unfinished">Wallet migrieren</translation> - </message> - <message> - <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> - <translation type="unfinished">Sicher, dass die Wallet migriert werden soll? <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">Durch die Migration der Wallet wird diese Wallet in eine oder mehrere Deskriptor-Wallets umgewandelt. Es muss ein neues Wallet-Backup erstellt werden. -Wenn diese Wallet Watchonly-Skripte enthält, wird eine neue Wallet erstellt, die diese Watchonly-Skripte enthält. -Wenn diese Wallet lösbare, aber nicht beobachtete Skripte enthält, wird eine andere und neue Wallet erstellt, die diese Skripte enthält. - -Während des Migrationsprozesses wird vor der Migration ein Backup der Wallet erstellt. Diese Backup-Datei heißt <wallet name>-<timestamp>.legacy.bak und befindet sich im Verzeichnis für diese Wallet. Im Falle einer fehlerhaften Migration kann das Backup mit der Funktion "Wallet wiederherstellen" wiederhergestellt werden.</translation> - </message> - <message> - <source>Migrate Wallet</source> - <translation type="unfinished">Wallet migrieren</translation> - </message> - <message> - <source>Migrating Wallet <b>%1</b>…</source> - <translation type="unfinished">Wallet migrieren <b>%1</b>…</translation> - </message> - <message> - <source>The wallet '%1' was migrated successfully.</source> - <translation type="unfinished">Die Wallet '%1' wurde erfolgreich migriert.</translation> - </message> - <message> - <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Nur-beobachten Scripts wurden in eine neue Wallet namens '%1' überführt.</translation> - </message> - <message> - <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Lösbare aber nicht beobachtete Scripts wurde in eine neue Wallet namens '%1' überführt.</translation> - </message> - <message> - <source>Migration failed</source> - <translation type="unfinished">Migration fehlgeschlagen</translation> - </message> - <message> - <source>Migration Successful</source> - <translation type="unfinished">Migration erfolgreich</translation> - </message> -</context> -<context> - <name>OpenWalletActivity</name> - <message> - <source>Open wallet failed</source> - <translation type="unfinished">Wallet öffnen fehlgeschlagen</translation> - </message> - <message> - <source>Open wallet warning</source> - <translation type="unfinished">Wallet öffnen Warnung</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</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">Öffne Wallet <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">Wallet wiederherstellen...</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">Wiederherstellen der Wallet <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">Wallet Wiederherstellung fehlgeschlagen</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">Wallet Wiederherstellungs Warnung</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">Wallet Wiederherstellungs Nachricht</translation> - </message> -</context> -<context> - <name>WalletController</name> - <message> - <source>Are you sure you wish to close the wallet <i>%1</i>?</source> - <translation type="unfinished">Sind Sie sich sicher, dass Sie die Wallet <i>%1</i> schließen möchten?</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">Wenn Sie die Wallet zu lange schließen, kann es dazu kommen, dass Sie die gesamte Chain neu synchronisieren müssen, wenn Pruning aktiviert ist.</translation> - </message> - <message> - <source>Close all wallets</source> - <translation type="unfinished">Schließe alle Wallets</translation> - </message> - <message> - <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">Sicher, dass Sie alle Wallets schließen möchten?</translation> - </message> -</context> -<context> - <name>CreateWalletDialog</name> - <message> - <source>Create Wallet</source> - <translation type="unfinished">Wallet erstellen</translation> - </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> - </message> - <message> - <source>Please provide a name and, if desired, enable any advanced options</source> - <translation type="unfinished">Bitte einen Namen angeben und, falls gewünscht, alle erweiterten Optionen aktivieren</translation> - </message> - <message> - <source>Wallet Name</source> - <translation type="unfinished">Wallet-Name</translation> - </message> - <message> - <source>Wallet</source> - <translation type="unfinished">Brieftasche</translation> - </message> - <message> - <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation type="unfinished">Verschlüssele das Wallet. Das Wallet wird mit einer Passphrase deiner Wahl verschlüsselt.</translation> - </message> - <message> - <source>Encrypt Wallet</source> - <translation type="unfinished">Wallet verschlüsseln</translation> - </message> - <message> - <source>Advanced Options</source> - <translation type="unfinished">Erweiterte Optionen</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">Deaktiviert private Schlüssel für dieses Wallet. Wallets mit deaktivierten privaten Schlüsseln werden keine privaten Schlüssel haben und können keinen HD Seed oder private Schlüssel importieren. Das ist ideal für Wallets, die nur beobachten.</translation> - </message> - <message> - <source>Disable Private Keys</source> - <translation type="unfinished">Private Keys deaktivieren</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">Erzeugt ein leeres Wallet. Leere Wallets haben zu Anfang keine privaten Schlüssel oder Scripte. Private Schlüssel oder Adressen können importiert werden, ebenso können jetzt oder später HD-Seeds gesetzt werden.</translation> - </message> - <message> - <source>Make Blank Wallet</source> - <translation type="unfinished">Eine leere Wallet erstellen</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">Verwenden Sie ein externes Signiergerät, z. B. eine Hardware-Wallet. Konfigurieren Sie zunächst das Skript für den externen Signierer in den Wallet-Einstellungen.</translation> - </message> - <message> - <source>External signer</source> - <translation type="unfinished">Externer Unterzeichner</translation> - </message> - <message> - <source>Create</source> - <translation type="unfinished">Erstellen</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">Ohne Unterstützung für die Signierung durch externe Geräte Dritter kompiliert (notwendig für Signierung durch externe Geräte Dritter)</translation> - </message> -</context> -<context> - <name>EditAddressDialog</name> - <message> - <source>Edit Address</source> - <translation type="unfinished">Adresse bearbeiten</translation> - </message> - <message> - <source>&Label</source> - <translation type="unfinished">&Bezeichnung</translation> - </message> - <message> - <source>The label associated with this address list entry</source> - <translation type="unfinished">Bezeichnung, die dem Adresslisteneintrag zugeordnet ist.</translation> - </message> - <message> - <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> - <translation type="unfinished">Adresse, die dem Adresslisteneintrag zugeordnet ist. Diese kann nur bei Zahlungsadressen verändert werden.</translation> - </message> - <message> - <source>&Address</source> - <translation type="unfinished">&Adresse</translation> - </message> - <message> - <source>New sending address</source> - <translation type="unfinished">Neue Zahlungsadresse</translation> - </message> - <message> - <source>Edit receiving address</source> - <translation type="unfinished">Empfangsadresse bearbeiten</translation> - </message> - <message> - <source>Edit sending address</source> - <translation type="unfinished">Zahlungsadresse bearbeiten</translation> - </message> - <message> - <source>The entered address "%1" is not a valid Bitcoin address.</source> - <translation type="unfinished">Die eingegebene Adresse "%1" ist keine gültige Bitcoin-Adresse.</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">Die Adresse "%1" existiert bereits als Empfangsadresse mit dem Label "%2" und kann daher nicht als Sendeadresse hinzugefügt werden.</translation> - </message> - <message> - <source>The entered address "%1" is already in the address book with label "%2".</source> - <translation type="unfinished">Die eingegebene Adresse "%1" befindet sich bereits im Adressbuch mit der Bezeichnung "%2".</translation> - </message> - <message> - <source>Could not unlock wallet.</source> - <translation type="unfinished">Wallet konnte nicht entsperrt werden.</translation> - </message> - <message> - <source>New key generation failed.</source> - <translation type="unfinished">Erzeugung eines neuen Schlüssels fehlgeschlagen.</translation> - </message> -</context> -<context> - <name>FreespaceChecker</name> - <message> - <source>A new data directory will be created.</source> - <translation type="unfinished">Es wird ein neues Datenverzeichnis angelegt.</translation> - </message> - <message> - <source>name</source> - <translation type="unfinished">Name</translation> - </message> - <message> - <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation type="unfinished">Verzeichnis existiert bereits. Fügen Sie %1 an, wenn Sie beabsichtigen hier ein neues Verzeichnis anzulegen.</translation> - </message> - <message> - <source>Path already exists, and is not a directory.</source> - <translation type="unfinished">Pfad existiert bereits und ist kein Verzeichnis.</translation> - </message> - <message> - <source>Cannot create data directory here.</source> - <translation type="unfinished">Datenverzeichnis kann hier nicht angelegt werden.</translation> - </message> -</context> -<context> <name>Intro</name> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform>%n GB Speicherplatz verfügbar</numerusform> - <numerusform>%n GB Speicherplatz verfügbar</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>(von %n GB benötigt)</numerusform> - <numerusform>(von %n GB benötigt)</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>(%n GB benötigt für komplette Blockchain)</numerusform> - <numerusform>(%n GB benötigt für komplette Blockchain)</numerusform> + <numerusform>(%n GB needed for full chain)</numerusform> + <numerusform>(%n GB needed for full chain)</numerusform> </translation> </message> - <message> - <source>Choose data directory</source> - <translation type="unfinished">Datenverzeichnis auswählen</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">Mindestens %1 GB Daten werden in diesem Verzeichnis gespeichert, und sie werden mit der Zeit zunehmen.</translation> - </message> - <message> - <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">Etwa %1 GB Daten werden in diesem Verzeichnis gespeichert.</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>(für Wiederherstellung ausreichende Sicherung %n Tag alt)</numerusform> - <numerusform>(für Wiederherstellung ausreichende Sicherung %n Tage alt)</numerusform> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> </translation> </message> - <message> - <source>%1 will download and store a copy of the Bitcoin block chain.</source> - <translation type="unfinished">%1 wird eine Kopie der Bitcoin-Blockchain herunterladen und speichern.</translation> - </message> - <message> - <source>The wallet will also be stored in this directory.</source> - <translation type="unfinished">Die Wallet wird ebenfalls in diesem Verzeichnis gespeichert.</translation> - </message> - <message> - <source>Error: Specified data directory "%1" cannot be created.</source> - <translation type="unfinished">Fehler: Angegebenes Datenverzeichnis "%1" kann nicht angelegt werden.</translation> - </message> - <message> - <source>Error</source> - <translation type="unfinished">Fehler</translation> - </message> - <message> - <source>Welcome</source> - <translation type="unfinished">Willkommen</translation> - </message> - <message> - <source>Welcome to %1.</source> - <translation type="unfinished">Willkommen zu %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">Da Sie das Programm gerade zum ersten Mal starten, können Sie nun auswählen wo %1 seine Daten ablegen wird.</translation> - </message> - <message> - <source>Limit block chain storage to</source> - <translation type="unfinished">Blockchain-Speicher beschränken auf</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">Um diese Einstellung wiederherzustellen, muss die gesamte Blockchain neu heruntergeladen werden. Es ist schneller, die gesamte Chain zuerst herunterzuladen und später zu bearbeiten. Deaktiviert einige erweiterte Funktionen.</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">Diese initiale Synchronisation führt zur hohen Last und kann Hardwareprobleme, die bisher nicht aufgetreten sind, mit ihrem Computer verursachen. Jedes Mal, wenn Sie %1 ausführen, wird der Download zum letzten Synchronisationspunkt fortgesetzt.</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">Wenn Sie auf OK klicken, beginnt %1 mit dem Herunterladen und Verarbeiten der gesamten %4-Blockchain (%2GB), beginnend mit den frühesten Transaktionen in %3 beim ersten Start von %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">Wenn Sie bewusst den Blockchain-Speicher begrenzen (pruning), müssen die historischen Daten dennoch heruntergeladen und verarbeitet werden. Diese Daten werden aber zum späteren Zeitpunkt gelöscht, um die Festplattennutzung niedrig zu halten.</translation> - </message> - <message> - <source>Use the default data directory</source> - <translation type="unfinished">Standard-Datenverzeichnis verwenden</translation> - </message> - <message> - <source>Use a custom data directory:</source> - <translation type="unfinished">Ein benutzerdefiniertes Datenverzeichnis verwenden:</translation> - </message> -</context> -<context> - <name>HelpMessageDialog</name> - <message> - <source>version</source> - <translation type="unfinished">Version</translation> - </message> - <message> - <source>About %1</source> - <translation type="unfinished">Über %1</translation> - </message> - <message> - <source>Command-line options</source> - <translation type="unfinished">Kommandozeilenoptionen</translation> - </message> -</context> -<context> - <name>ShutdownWindow</name> - <message> - <source>%1 is shutting down…</source> - <translation type="unfinished">%1 wird beendet...</translation> - </message> - <message> - <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">Fahren Sie den Computer nicht herunter, bevor dieses Fenster verschwindet.</translation> - </message> -</context> -<context> - <name>ModalOverlay</name> - <message> - <source>Form</source> - <translation type="unfinished">Formular</translation> - </message> - <message> - <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation type="unfinished">Neueste Transaktionen werden eventuell noch nicht angezeigt, daher könnte Ihr Kontostand veraltet sein. Er wird korrigiert, sobald Ihr Wallet die Synchronisation mit dem Bitcoin-Netzwerk erfolgreich abgeschlossen hat. Details dazu finden sich weiter unten.</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">Versuche, Bitcoins aus noch nicht angezeigten Transaktionen auszugeben, werden vom Netzwerk nicht akzeptiert.</translation> - </message> - <message> - <source>Number of blocks left</source> - <translation type="unfinished">Anzahl verbleibender Blöcke</translation> - </message> - <message> - <source>Unknown…</source> - <translation type="unfinished">Unbekannt...</translation> - </message> - <message> - <source>calculating…</source> - <translation type="unfinished">berechne...</translation> - </message> - <message> - <source>Last block time</source> - <translation type="unfinished">Letzte Blockzeit</translation> - </message> - <message> - <source>Progress</source> - <translation type="unfinished">Fortschritt</translation> - </message> - <message> - <source>Progress increase per hour</source> - <translation type="unfinished">Fortschritt pro Stunde</translation> - </message> - <message> - <source>Estimated time left until synced</source> - <translation type="unfinished">Abschätzung der verbleibenden Zeit bis synchronisiert</translation> - </message> - <message> - <source>Hide</source> - <translation type="unfinished">Ausblenden</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 synchronisiert gerade. Es lädt Header und Blöcke von Gegenstellen und validiert sie bis zum Erreichen der Spitze der Blockkette.</translation> - </message> - <message> - <source>Unknown. Syncing Headers (%1, %2%)…</source> - <translation type="unfinished">Unbekannt. Synchronisiere Headers (%1, %2%)...</translation> - </message> - <message> - <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> - <translation type="unfinished">Unbekannt. vorsynchronisiere Header (%1, %2%)...</translation> - </message> -</context> -<context> - <name>OpenURIDialog</name> - <message> - <source>Open bitcoin URI</source> - <translation type="unfinished">Öffne bitcoin URI</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">Adresse aus der Zwischenablage einfügen</translation> - </message> -</context> -<context> - <name>OptionsDialog</name> - <message> - <source>Options</source> - <translation type="unfinished">Konfiguration</translation> - </message> - <message> - <source>&Main</source> - <translation type="unfinished">&Allgemein</translation> - </message> - <message> - <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">%1 nach der Anmeldung im System automatisch ausführen.</translation> - </message> - <message> - <source>&Start %1 on system login</source> - <translation type="unfinished">&Starte %1 nach Systemanmeldung</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">Durch das Aktivieren von Pruning wird der zum Speichern von Transaktionen benötigte Speicherplatz erheblich reduziert. Alle Blöcke werden weiterhin vollständig validiert. Um diese Einstellung rückgängig zu machen, muss die gesamte Blockchain erneut heruntergeladen werden.</translation> - </message> - <message> - <source>Size of &database cache</source> - <translation type="unfinished">Größe des &Datenbankpufferspeichers</translation> - </message> - <message> - <source>Number of script &verification threads</source> - <translation type="unfinished">Anzahl an Skript-&Verifizierungs-Threads</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">Vollständiger Pfad zu %1 einem Bitcoin Core kompatibelen Script (z.B.: C:\Downloads\hwi.exe oder /Users/you/Downloads/hwi.py). Achtung: Malware kann Bitcoins stehlen!</translation> - </message> - <message> - <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> - <translation type="unfinished">IP-Adresse des Proxies (z.B. 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">Zeigt an, ob der gelieferte Standard SOCKS5 Proxy verwendet wurde, um die Peers mit diesem Netzwerktyp zu erreichen.</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">Minimiert die Anwendung anstatt sie zu beenden wenn das Fenster geschlossen wird. Wenn dies aktiviert ist, müssen Sie die Anwendung über "Beenden" im Menü schließen.</translation> - </message> - <message> - <source>Font in the Overview tab: </source> - <translation type="unfinished">Schriftart im Überblicks-Tab:</translation> - </message> - <message> - <source>Options set in this dialog are overridden by the command line:</source> - <translation type="unfinished">Einstellungen in diesem Dialog werden von der Kommandozeile überschrieben:</translation> - </message> - <message> - <source>Open the %1 configuration file from the working directory.</source> - <translation type="unfinished">Öffnen Sie die %1 Konfigurationsdatei aus dem Arbeitsverzeichnis.</translation> - </message> - <message> - <source>Open Configuration File</source> - <translation type="unfinished">Konfigurationsdatei öffnen</translation> - </message> - <message> - <source>Reset all client options to default.</source> - <translation type="unfinished">Setzt die Clientkonfiguration auf Standardwerte zurück.</translation> - </message> - <message> - <source>&Reset Options</source> - <translation type="unfinished">Konfiguration &zurücksetzen</translation> - </message> - <message> - <source>&Network</source> - <translation type="unfinished">&Netzwerk</translation> - </message> - <message> - <source>Prune &block storage to</source> - <translation type="unfinished">&Blockspeicher kürzen auf</translation> - </message> - <message> - <source>Reverting this setting requires re-downloading the entire blockchain.</source> - <translation type="unfinished">Wenn diese Einstellung rückgängig gemacht wird, muss die komplette Blockchain erneut heruntergeladen werden.</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">Maximale Größe des Datenbank-Caches. Ein größerer Cache kann zu einer schnelleren Synchronisierung beitragen, danach ist der Vorteil für die meisten Anwendungsfälle weniger ausgeprägt. Eine Verringerung der Cache-Größe reduziert den Speicherverbrauch. Ungenutzter Mempool-Speicher wird für diesen Cache gemeinsam genutzt.</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">Legen Sie die Anzahl der Skriptüberprüfungs-Threads fest. Negative Werte entsprechen der Anzahl der Kerne, die Sie für das System frei lassen möchten.</translation> - </message> - <message> - <source>(0 = auto, <0 = leave that many cores free)</source> - <translation type="unfinished">(0 = automatisch, <0 = so viele Kerne frei lassen)</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">Dies ermöglicht Ihnen oder einem Drittanbieter-Tool die Kommunikation mit dem Knoten über Befehlszeilen- und JSON-RPC-Befehle.</translation> - </message> - <message> - <source>Enable R&PC server</source> - <extracomment>An Options window setting to enable the RPC server.</extracomment> - <translation type="unfinished">RPC-Server aktivieren</translation> - </message> - <message> - <source>W&allet</source> - <translation type="unfinished">B&rieftasche</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">Wählen Sie, ob die Gebühr standardmäßig vom Betrag abgezogen werden soll oder nicht.</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">Standardmäßig die Gebühr vom Betrag abziehen</translation> - </message> - <message> - <source>Expert</source> - <translation type="unfinished">Experten-Optionen</translation> - </message> - <message> - <source>Enable coin &control features</source> - <translation type="unfinished">"&Coin Control"-Funktionen aktivieren</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">Wenn Sie das Ausgeben von unbestätigtem Wechselgeld deaktivieren, kann das Wechselgeld einer Transaktion nicht verwendet werden, bis es mindestens eine Bestätigung erhalten hat. Dies wirkt sich auf die Berechnung des Kontostands aus.</translation> - </message> - <message> - <source>&Spend unconfirmed change</source> - <translation type="unfinished">&Unbestätigtes Wechselgeld darf ausgegeben werden</translation> - </message> - <message> - <source>Enable &PSBT controls</source> - <extracomment>An options window setting to enable PSBT controls.</extracomment> - <translation type="unfinished">&PBST-Kontrollen aktivieren</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">Ob PSBT-Kontrollen angezeigt werden sollen. </translation> - </message> - <message> - <source>External Signer (e.g. hardware wallet)</source> - <translation type="unfinished">Gerät für externe Signierung (z. B.: Hardware wallet)</translation> - </message> - <message> - <source>&External signer script path</source> - <translation type="unfinished">&Pfad zum Script des externen Gerätes zur Signierung</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">Automatisch den Bitcoin-Clientport auf dem Router öffnen. Dies funktioniert nur, wenn Ihr Router UPnP unterstützt und dies aktiviert ist.</translation> - </message> - <message> - <source>Map port using &UPnP</source> - <translation type="unfinished">Portweiterleitung via &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">Öffnet automatisch den Bitcoin-Client-Port auf dem Router. Dies funktioniert nur, wenn Ihr Router NAT-PMP unterstützt und es aktiviert ist. Der externe Port kann zufällig sein.</translation> - </message> - <message> - <source>Map port using NA&T-PMP</source> - <translation type="unfinished">Map-Port mit NA&T-PMP</translation> - </message> - <message> - <source>Accept connections from outside.</source> - <translation type="unfinished">Akzeptiere Verbindungen von außerhalb.</translation> - </message> - <message> - <source>Allow incomin&g connections</source> - <translation type="unfinished">Erlaube &eingehende Verbindungen</translation> - </message> - <message> - <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> - <translation type="unfinished">Über einen SOCKS5-Proxy mit dem Bitcoin-Netzwerk verbinden.</translation> - </message> - <message> - <source>&Connect through SOCKS5 proxy (default proxy):</source> - <translation type="unfinished">Über einen SOCKS5-Proxy &verbinden (Standardproxy):</translation> - </message> - <message> - <source>Proxy &IP:</source> - <translation type="unfinished">Proxy-&IP:</translation> - </message> - <message> - <source>Port of the proxy (e.g. 9050)</source> - <translation type="unfinished">Port des Proxies (z.B. 9050)</translation> - </message> - <message> - <source>Used for reaching peers via:</source> - <translation type="unfinished">Benutzt um Gegenstellen zu erreichen über:</translation> - </message> - <message> - <source>&Window</source> - <translation type="unfinished">&Programmfenster</translation> - </message> - <message> - <source>Show the icon in the system tray.</source> - <translation type="unfinished">Zeigt das Symbol in der Leiste an.</translation> - </message> - <message> - <source>&Show tray icon</source> - <translation type="unfinished">&Zeige Statusleistensymbol</translation> - </message> - <message> - <source>Show only a tray icon after minimizing the window.</source> - <translation type="unfinished">Nur ein Symbol im Infobereich anzeigen, nachdem das Programmfenster minimiert wurde.</translation> - </message> - <message> - <source>&Minimize to the tray instead of the taskbar</source> - <translation type="unfinished">In den Infobereich anstatt in die Taskleiste &minimieren</translation> - </message> - <message> - <source>M&inimize on close</source> - <translation type="unfinished">Beim Schließen m&inimieren</translation> - </message> - <message> - <source>&Display</source> - <translation type="unfinished">&Anzeige</translation> - </message> - <message> - <source>User Interface &language:</source> - <translation type="unfinished">&Sprache der Benutzeroberfläche:</translation> - </message> - <message> - <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> - <translation type="unfinished">Die Sprache der Benutzeroberflächen kann hier festgelegt werden. Diese Einstellung wird nach einem Neustart von %1 wirksam werden.</translation> - </message> - <message> - <source>&Unit to show amounts in:</source> - <translation type="unfinished">&Einheit der Beträge:</translation> - </message> - <message> - <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> - <translation type="unfinished">Wählen Sie die standardmäßige Untereinheit, die in der Benutzeroberfläche und beim Überweisen von Bitcoins angezeigt werden soll.</translation> - </message> - <message> - <source>Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source> - <translation type="unfinished">URLs von Drittanbietern (z. B. eines Block-Explorers), erscheinen als Kontextmenüpunkte auf der Registerkarte. %s in der URL wird durch den Transaktionshash ersetzt. Mehrere URLs werden durch senkrechte Striche | getrennt.</translation> - </message> - <message> - <source>&Third-party transaction URLs</source> - <translation type="unfinished">&Transaktions-URLs von Drittparteien</translation> - </message> - <message> - <source>Whether to show coin control features or not.</source> - <translation type="unfinished">Legt fest, ob die "Coin Control"-Funktionen angezeigt werden.</translation> - </message> - <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> - <translation type="unfinished">Verbinde mit dem Bitcoin-Netzwerk über einen separaten SOCKS5-Proxy für Tor-Onion-Dienste.</translation> - </message> - <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> - <translation type="unfinished">Nutze separaten SOCKS&5-Proxy um Gegenstellen über Tor-Onion-Dienste zu erreichen:</translation> - </message> - <message> - <source>&Cancel</source> - <translation type="unfinished">&Abbrechen</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">Ohne Unterstützung für die Signierung durch externe Geräte Dritter kompiliert (notwendig für Signierung durch externe Geräte Dritter)</translation> - </message> - <message> - <source>default</source> - <translation type="unfinished">Standard</translation> - </message> - <message> - <source>none</source> - <translation type="unfinished">keine</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">Zurücksetzen der Konfiguration bestätigen</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">Client-Neustart erforderlich, um Änderungen zu aktivieren.</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">Aktuelle Einstellungen werden in "%1" gespeichert.</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">Client wird beendet. Möchten Sie den Vorgang fortsetzen?</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">Konfigurationsoptionen</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">Die Konfigurationsdatei wird verwendet, um erweiterte Benutzeroptionen festzulegen, die die GUI-Einstellungen überschreiben. Darüber hinaus werden alle Befehlszeilenoptionen diese Konfigurationsdatei überschreiben.</translation> - </message> - <message> - <source>Continue</source> - <translation type="unfinished">Weiter</translation> - </message> - <message> - <source>Cancel</source> - <translation type="unfinished">Abbrechen</translation> - </message> - <message> - <source>Error</source> - <translation type="unfinished">Fehler</translation> - </message> - <message> - <source>The configuration file could not be opened.</source> - <translation type="unfinished">Die Konfigurationsdatei konnte nicht geöffnet werden.</translation> - </message> - <message> - <source>This change would require a client restart.</source> - <translation type="unfinished">Diese Änderung würde einen Client-Neustart erfordern.</translation> - </message> - <message> - <source>The supplied proxy address is invalid.</source> - <translation type="unfinished">Die eingegebene Proxy-Adresse ist ungültig.</translation> - </message> -</context> -<context> - <name>OptionsModel</name> - <message> - <source>Could not read setting "%1", %2.</source> - <translation type="unfinished">Die folgende Einstellung konnte nicht gelesen werden "%1", %2.</translation> - </message> -</context> -<context> - <name>OverviewPage</name> - <message> - <source>Form</source> - <translation type="unfinished">Formular</translation> - </message> - <message> - <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> - <translation type="unfinished">Die angezeigten Informationen sind möglicherweise nicht mehr aktuell. Ihre Wallet wird automatisch synchronisiert, nachdem eine Verbindung zum Bitcoin-Netzwerk hergestellt wurde. Dieser Prozess ist jedoch derzeit noch nicht abgeschlossen.</translation> - </message> - <message> - <source>Watch-only:</source> - <translation type="unfinished">Beobachtet:</translation> - </message> - <message> - <source>Available:</source> - <translation type="unfinished">Verfügbar:</translation> - </message> - <message> - <source>Your current spendable balance</source> - <translation type="unfinished">Ihr aktuell verfügbarer Kontostand</translation> - </message> - <message> - <source>Pending:</source> - <translation type="unfinished">Ausstehend:</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">Gesamtbetrag aus unbestätigten Transaktionen, der noch nicht im aktuell verfügbaren Kontostand enthalten ist</translation> - </message> - <message> - <source>Immature:</source> - <translation type="unfinished">Unreif:</translation> - </message> - <message> - <source>Mined balance that has not yet matured</source> - <translation type="unfinished">Erarbeiteter Betrag der noch nicht gereift ist</translation> - </message> - <message> - <source>Balances</source> - <translation type="unfinished">Kontostände</translation> - </message> - <message> - <source>Total:</source> - <translation type="unfinished">Gesamtbetrag:</translation> - </message> - <message> - <source>Your current total balance</source> - <translation type="unfinished">Ihr aktueller Gesamtbetrag</translation> - </message> - <message> - <source>Your current balance in watch-only addresses</source> - <translation type="unfinished">Ihr aktueller Kontostand in nur-beobachteten Adressen</translation> - </message> - <message> - <source>Spendable:</source> - <translation type="unfinished">Verfügbar:</translation> - </message> - <message> - <source>Recent transactions</source> - <translation type="unfinished">Letzte Transaktionen</translation> - </message> - <message> - <source>Unconfirmed transactions to watch-only addresses</source> - <translation type="unfinished">Unbestätigte Transaktionen an nur-beobachtete Adressen</translation> - </message> - <message> - <source>Mined balance in watch-only addresses that has not yet matured</source> - <translation type="unfinished">Erarbeiteter Betrag in nur-beobachteten Adressen der noch nicht gereift ist</translation> - </message> - <message> - <source>Current total balance in watch-only addresses</source> - <translation type="unfinished">Aktueller Gesamtbetrag in nur-beobachteten Adressen</translation> - </message> - <message> - <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> - <translation type="unfinished">Datenschutz-Modus aktiviert für den Übersichtsreiter. Um die Werte einzublenden, deaktiviere Einstellungen->Werte ausblenden.</translation> - </message> -</context> -<context> - <name>PSBTOperationsDialog</name> - <message> - <source>PSBT Operations</source> - <translation type="unfinished">PSBT-Operationen</translation> - </message> - <message> - <source>Sign Tx</source> - <translation type="unfinished">Signiere Tx</translation> - </message> - <message> - <source>Broadcast Tx</source> - <translation type="unfinished">Rundsende Tx</translation> - </message> - <message> - <source>Copy to Clipboard</source> - <translation type="unfinished">Kopiere in Zwischenablage</translation> - </message> - <message> - <source>Save…</source> - <translation type="unfinished">Speichern...</translation> - </message> - <message> - <source>Close</source> - <translation type="unfinished">Schließen</translation> - </message> - <message> - <source>Failed to load transaction: %1</source> - <translation type="unfinished">Laden der Transaktion fehlgeschlagen: %1</translation> - </message> - <message> - <source>Failed to sign transaction: %1</source> - <translation type="unfinished">Signieren der Transaktion fehlgeschlagen: %1</translation> - </message> - <message> - <source>Cannot sign inputs while wallet is locked.</source> - <translation type="unfinished">Eingaben können nicht unterzeichnet werden, wenn die Wallet gesperrt ist.</translation> - </message> - <message> - <source>Could not sign any more inputs.</source> - <translation type="unfinished">Konnte keinerlei weitere Eingaben signieren.</translation> - </message> - <message> - <source>Signed %1 inputs, but more signatures are still required.</source> - <translation type="unfinished">%1 Eingaben signiert, doch noch sind weitere Signaturen erforderlich.</translation> - </message> - <message> - <source>Signed transaction successfully. Transaction is ready to broadcast.</source> - <translation type="unfinished">Transaktion erfolgreich signiert. Transaktion ist bereit für Rundsendung.</translation> - </message> - <message> - <source>Unknown error processing transaction.</source> - <translation type="unfinished">Unbekannter Fehler bei der Transaktionsverarbeitung</translation> - </message> - <message> - <source>Transaction broadcast successfully! Transaction ID: %1</source> - <translation type="unfinished">Transaktion erfolgreich rundgesendet! Transaktions-ID: %1</translation> - </message> - <message> - <source>Transaction broadcast failed: %1</source> - <translation type="unfinished">Rundsenden der Transaktion fehlgeschlagen: %1</translation> - </message> - <message> - <source>PSBT copied to clipboard.</source> - <translation type="unfinished">PSBT in Zwischenablage kopiert.</translation> - </message> - <message> - <source>Save Transaction Data</source> - <translation type="unfinished">Speichere Transaktionsdaten</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">Teilweise signierte Transaktion (binär)</translation> - </message> - <message> - <source>PSBT saved to disk.</source> - <translation type="unfinished">PSBT auf Platte gespeichert.</translation> - </message> - <message> - <source>Sends %1 to %2</source> - <translation type="unfinished">Schickt %1 an %2</translation> - </message> - <message> - <source>own address</source> - <translation type="unfinished">eigene Adresse</translation> - </message> - <message> - <source>Unable to calculate transaction fee or total transaction amount.</source> - <translation type="unfinished">Kann die Gebühr oder den Gesamtbetrag der Transaktion nicht berechnen.</translation> - </message> - <message> - <source>Pays transaction fee: </source> - <translation type="unfinished">Zahlt Transaktionsgebühr:</translation> - </message> - <message> - <source>Total Amount</source> - <translation type="unfinished">Gesamtbetrag</translation> - </message> - <message> - <source>or</source> - <translation type="unfinished">oder</translation> - </message> - <message> - <source>Transaction has %1 unsigned inputs.</source> - <translation type="unfinished">Transaktion hat %1 unsignierte Eingaben.</translation> - </message> - <message> - <source>Transaction is missing some information about inputs.</source> - <translation type="unfinished">Der Transaktion fehlen einige Informationen über Eingaben.</translation> - </message> - <message> - <source>Transaction still needs signature(s).</source> - <translation type="unfinished">Transaktion erfordert weiterhin Signatur(en).</translation> - </message> - <message> - <source>(But no wallet is loaded.)</source> - <translation type="unfinished">(Aber kein Wallet ist geladen.)</translation> - </message> - <message> - <source>(But this wallet cannot sign transactions.)</source> - <translation type="unfinished">(doch diese Wallet kann Transaktionen nicht signieren)</translation> - </message> - <message> - <source>(But this wallet does not have the right keys.)</source> - <translation type="unfinished">(doch diese Wallet hat nicht die richtigen Schlüssel)</translation> - </message> - <message> - <source>Transaction is fully signed and ready for broadcast.</source> - <translation type="unfinished">Transaktion ist vollständig signiert und zur Rundsendung bereit.</translation> - </message> - <message> - <source>Transaction status is unknown.</source> - <translation type="unfinished">Transaktionsstatus ist unbekannt.</translation> - </message> -</context> -<context> - <name>PaymentServer</name> - <message> - <source>Payment request error</source> - <translation type="unfinished">Fehler bei der Zahlungsanforderung</translation> - </message> - <message> - <source>Cannot start bitcoin: click-to-pay handler</source> - <translation type="unfinished">Kann Bitcoin nicht starten: Klicken-zum-Bezahlen-Verarbeiter</translation> - </message> - <message> - <source>URI handling</source> - <translation type="unfinished">URI-Verarbeitung</translation> - </message> - <message> - <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> - <translation type="unfinished">'bitcoin://' ist kein gültiger URL. Bitte 'bitcoin:' nutzen.</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">Zahlungsanforderung kann nicht verarbeitet werden, da BIP70 nicht unterstützt wird. -Aufgrund der weit verbreiteten Sicherheitslücken in BIP70 wird dringend empfohlen, die Anweisungen des Händlers zum Wechsel des Wallets zu ignorieren. -Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BIP21-kompatiblen URI bereitzustellen.</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 kann nicht analysiert werden! Dies kann durch eine ungültige Bitcoin-Adresse oder fehlerhafte URI-Parameter verursacht werden.</translation> - </message> - <message> - <source>Payment request file handling</source> - <translation type="unfinished">Zahlungsanforderungsdatei-Verarbeitung</translation> - </message> -</context> -<context> - <name>PeerTableModel</name> - <message> - <source>User Agent</source> - <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment> - <translation type="unfinished">User-Agent</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">Gegenstelle</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">Alter</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">Richtung</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">Übertragen</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">Empfangen</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">Adresse</translation> - </message> - <message> - <source>Type</source> - <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment> - <translation type="unfinished">Typ</translation> - </message> - <message> - <source>Network</source> - <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment> - <translation type="unfinished">Netzwerk</translation> - </message> - <message> - <source>Inbound</source> - <extracomment>An Inbound Connection from a Peer.</extracomment> - <translation type="unfinished">Eingehend</translation> - </message> - <message> - <source>Outbound</source> - <extracomment>An Outbound Connection to a Peer.</extracomment> - <translation type="unfinished">Ausgehend</translation> - </message> -</context> -<context> - <name>QRImageWidget</name> - <message> - <source>&Save Image…</source> - <translation type="unfinished">&Bild speichern...</translation> - </message> - <message> - <source>&Copy Image</source> - <translation type="unfinished">Grafik &kopieren</translation> - </message> - <message> - <source>Resulting URI too long, try to reduce the text for label / message.</source> - <translation type="unfinished">Resultierende URI ist zu lang, bitte den Text für Bezeichnung/Nachricht kürzen.</translation> - </message> - <message> - <source>Error encoding URI into QR Code.</source> - <translation type="unfinished">Beim Kodieren der URI in den QR-Code ist ein Fehler aufgetreten.</translation> - </message> - <message> - <source>QR code support not available.</source> - <translation type="unfinished">QR Code Funktionalität nicht vorhanden</translation> - </message> - <message> - <source>Save QR Code</source> - <translation type="unfinished">QR-Code speichern</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-Bild</translation> - </message> -</context> -<context> - <name>RPCConsole</name> - <message> - <source>N/A</source> - <translation type="unfinished">k.A.</translation> - </message> - <message> - <source>Client version</source> - <translation type="unfinished">Client-Version</translation> - </message> - <message> - <source>&Information</source> - <translation type="unfinished">Hinweis</translation> - </message> - <message> - <source>General</source> - <translation type="unfinished">Allgemein</translation> - </message> - <message> - <source>Datadir</source> - <translation type="unfinished">Datenverzeichnis</translation> - </message> - <message> - <source>To specify a non-default location of the data directory use the '%1' option.</source> - <translation type="unfinished">Verwenden Sie die Option '%1' um einen anderen, nicht standardmäßigen Speicherort für das Datenverzeichnis festzulegen.</translation> - </message> - <message> - <source>Blocksdir</source> - <translation type="unfinished">Blockverzeichnis</translation> - </message> - <message> - <source>To specify a non-default location of the blocks directory use the '%1' option.</source> - <translation type="unfinished">Verwenden Sie die Option '%1' um einen anderen, nicht standardmäßigen Speicherort für das Blöckeverzeichnis festzulegen.</translation> - </message> - <message> - <source>Startup time</source> - <translation type="unfinished">Startzeit</translation> - </message> - <message> - <source>Network</source> - <translation type="unfinished">Netzwerk</translation> - </message> - <message> - <source>Number of connections</source> - <translation type="unfinished">Anzahl der Verbindungen</translation> - </message> - <message> - <source>Block chain</source> - <translation type="unfinished">Blockchain</translation> - </message> - <message> - <source>Memory Pool</source> - <translation type="unfinished">Speicher-Pool</translation> - </message> - <message> - <source>Current number of transactions</source> - <translation type="unfinished">Aktuelle Anzahl der Transaktionen</translation> - </message> - <message> - <source>Memory usage</source> - <translation type="unfinished">Speichernutzung</translation> - </message> - <message> - <source>(none)</source> - <translation type="unfinished">(keine)</translation> - </message> - <message> - <source>&Reset</source> - <translation type="unfinished">&Zurücksetzen</translation> - </message> - <message> - <source>Received</source> - <translation type="unfinished">Empfangen</translation> - </message> - <message> - <source>Sent</source> - <translation type="unfinished">Übertragen</translation> - </message> - <message> - <source>&Peers</source> - <translation type="unfinished">&Gegenstellen</translation> - </message> - <message> - <source>Banned peers</source> - <translation type="unfinished">Gesperrte Gegenstellen</translation> - </message> - <message> - <source>Select a peer to view detailed information.</source> - <translation type="unfinished">Gegenstelle auswählen, um detaillierte Informationen zu erhalten.</translation> - </message> - <message> - <source>The transport layer version: %1</source> - <translation type="unfinished">Die Transportschicht-Version: %1</translation> - </message> - <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Die BIP324-Sitzungs-ID-Zeichenfolge in hexadezimaler Form, falls vorhanden.</translation> - </message> - <message> - <source>Whether we relay transactions to this peer.</source> - <translation type="unfinished">Ob wir Adressen an diese Gegenstelle weiterleiten.</translation> - </message> - <message> - <source>Transaction Relay</source> - <translation type="unfinished">Transaktions-Relay</translation> - </message> - <message> - <source>Starting Block</source> - <translation type="unfinished">Start Block</translation> - </message> - <message> - <source>Synced Headers</source> - <translation type="unfinished">Synchronisierte Header</translation> - </message> - <message> - <source>Synced Blocks</source> - <translation type="unfinished">Synchronisierte Blöcke</translation> - </message> - <message> - <source>Last Transaction</source> - <translation type="unfinished">Letzte Transaktion</translation> - </message> - <message> - <source>The mapped Autonomous System used for diversifying peer selection.</source> - <translation type="unfinished">Das zugeordnete autonome System zur Diversifizierung der Gegenstellen-Auswahl.</translation> - </message> - <message> - <source>Mapped AS</source> - <translation type="unfinished">Zugeordnetes 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">Ob wir Adressen an diese Gegenstelle weiterleiten.</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">Adress-Relay</translation> - </message> - <message> - <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source> - <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment> - <translation type="unfinished">Die Gesamtzahl der von dieser Gegenstelle empfangenen Adressen, die aufgrund von Ratenbegrenzung verworfen (nicht verarbeitet) wurden.</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">Die Gesamtzahl der von dieser Gegenstelle empfangenen Adressen, die aufgrund von Ratenbegrenzung verworfen (nicht verarbeitet) wurden.</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">Verarbeitete Adressen</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">Ratenbeschränkte Adressen</translation> - </message> - <message> - <source>User Agent</source> - <translation type="unfinished">User-Agent</translation> - </message> - <message> - <source>Current block height</source> - <translation type="unfinished">Aktuelle Blockhöhe</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">Öffnet die %1-Debug-Protokolldatei aus dem aktuellen Datenverzeichnis. Dies kann bei großen Protokolldateien einige Sekunden dauern.</translation> - </message> - <message> - <source>Decrease font size</source> - <translation type="unfinished">Schrift verkleinern</translation> - </message> - <message> - <source>Increase font size</source> - <translation type="unfinished">Schrift vergrößern</translation> - </message> - <message> - <source>Permissions</source> - <translation type="unfinished">Berechtigungen</translation> - </message> - <message> - <source>The direction and type of peer connection: %1</source> - <translation type="unfinished">Die Richtung und der Typ der Gegenstellen-Verbindung: %1</translation> - </message> - <message> - <source>Direction/Type</source> - <translation type="unfinished">Richtung/Typ</translation> - </message> - <message> - <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> - <translation type="unfinished">Das Netzwerkprotokoll, über das diese Gegenstelle verbunden ist, ist: IPv4, IPv6, Onion, I2P oder CJDNS.</translation> - </message> - <message> - <source>Services</source> - <translation type="unfinished">Dienste</translation> - </message> - <message> - <source>High bandwidth BIP152 compact block relay: %1</source> - <translation type="unfinished">Kompakte BIP152 Blockweiterleitung mit hoher Bandbreite: %1</translation> - </message> - <message> - <source>High Bandwidth</source> - <translation type="unfinished">Hohe Bandbreite</translation> - </message> - <message> - <source>Connection Time</source> - <translation type="unfinished">Verbindungsdauer</translation> - </message> - <message> - <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source> - <translation type="unfinished">Abgelaufene Zeit seitdem ein neuer Block mit erfolgreichen initialen Gültigkeitsprüfungen von dieser Gegenstelle empfangen wurde.</translation> - </message> - <message> - <source>Last Block</source> - <translation type="unfinished">Letzter 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">Abgelaufene Zeit seit eine neue Transaktion, die in unseren Speicherpool hineingelassen wurde, von dieser Gegenstelle empfangen wurde.</translation> - </message> - <message> - <source>Last Send</source> - <translation type="unfinished">Letzte Übertragung</translation> - </message> - <message> - <source>Last Receive</source> - <translation type="unfinished">Letzter Empfang</translation> - </message> - <message> - <source>Ping Time</source> - <translation type="unfinished">Ping-Zeit</translation> - </message> - <message> - <source>The duration of a currently outstanding ping.</source> - <translation type="unfinished">Die Laufzeit eines aktuell ausstehenden Ping.</translation> - </message> - <message> - <source>Ping Wait</source> - <translation type="unfinished">Ping-Wartezeit</translation> - </message> - <message> - <source>Min Ping</source> - <translation type="unfinished">Minimaler Ping</translation> - </message> - <message> - <source>Time Offset</source> - <translation type="unfinished">Zeitversatz</translation> - </message> - <message> - <source>Last block time</source> - <translation type="unfinished">Letzte Blockzeit</translation> - </message> - <message> - <source>&Open</source> - <translation type="unfinished">&Öffnen</translation> - </message> - <message> - <source>&Console</source> - <translation type="unfinished">&Konsole</translation> - </message> - <message> - <source>&Network Traffic</source> - <translation type="unfinished">&Netzwerkauslastung</translation> - </message> - <message> - <source>Totals</source> - <translation type="unfinished">Gesamtbetrag:</translation> - </message> - <message> - <source>Debug log file</source> - <translation type="unfinished">Debug-Protokolldatei</translation> - </message> - <message> - <source>Clear console</source> - <translation type="unfinished">Konsole zurücksetzen</translation> - </message> - <message> - <source>In:</source> - <translation type="unfinished">Eingehend:</translation> - </message> - <message> - <source>Out:</source> - <translation type="unfinished">Ausgehend:</translation> - </message> - <message> - <source>Inbound: initiated by peer</source> - <extracomment>Explanatory text for an inbound peer connection.</extracomment> - <translation type="unfinished">Eingehend: wurde von Gegenstelle initiiert</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">Ausgehende vollständige Weiterleitung: Standard</translation> - </message> - <message> - <source>Outbound Block Relay: does not relay transactions or addresses</source> - <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment> - <translation type="unfinished">Ausgehende Blockweiterleitung: leitet Transaktionen und Adressen nicht weiter</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">Ausgehend Manuell: durch die RPC %1 oder %2/%3 Konfigurationsoptionen hinzugefügt</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">Ausgehender Fühler: kurzlebig, zum Testen von Adressen</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">Ausgehende Adressensammlung: kurzlebig, zum Anfragen von Adressen</translation> - </message> - <message> - <source>detecting: peer could be v1 or v2</source> - <extracomment>Explanatory text for "detecting" transport type.</extracomment> - <translation type="unfinished">Erkennen: Peer könnte v1 oder v2 sein</translation> - </message> - <message> - <source>v1: unencrypted, plaintext transport protocol</source> - <extracomment>Explanatory text for v1 transport type.</extracomment> - <translation type="unfinished">V1: Unverschlüsseltes Klartext-Transportprotokoll</translation> - </message> - <message> - <source>v2: BIP324 encrypted transport protocol</source> - <extracomment>Explanatory text for v2 transport type.</extracomment> - <translation type="unfinished">v2: BIP324 verschlüsseltes Transportprotokoll</translation> - </message> - <message> - <source>we selected the peer for high bandwidth relay</source> - <translation type="unfinished">Wir haben die Gegenstelle zum Weiterleiten mit hoher Bandbreite ausgewählt</translation> - </message> - <message> - <source>the peer selected us for high bandwidth relay</source> - <translation type="unfinished">Die Gegenstelle hat uns zum Weiterleiten mit hoher Bandbreite ausgewählt</translation> - </message> - <message> - <source>no high bandwidth relay selected</source> - <translation type="unfinished">Keine Weiterleitung mit hoher Bandbreite ausgewählt</translation> - </message> - <message> - <source>Ctrl++</source> - <extracomment>Main shortcut to increase the RPC console font size.</extracomment> - <translation type="unfinished">Strg++</translation> - </message> - <message> - <source>Ctrl+=</source> - <extracomment>Secondary shortcut to increase the RPC console font size.</extracomment> - <translation type="unfinished">Strg+=</translation> - </message> - <message> - <source>Ctrl+-</source> - <extracomment>Main shortcut to decrease the RPC console font size.</extracomment> - <translation type="unfinished">Strg+-</translation> - </message> - <message> - <source>Ctrl+_</source> - <extracomment>Secondary shortcut to decrease the RPC console font size.</extracomment> - <translation type="unfinished">Strg+_</translation> - </message> - <message> - <source>&Copy address</source> - <extracomment>Context menu action to copy the address of a peer.</extracomment> - <translation type="unfinished">&Adresse kopieren</translation> - </message> - <message> - <source>&Disconnect</source> - <translation type="unfinished">&Trennen</translation> - </message> - <message> - <source>1 &hour</source> - <translation type="unfinished">1 &Stunde</translation> - </message> - <message> - <source>1 d&ay</source> - <translation type="unfinished">1 T&ag</translation> - </message> - <message> - <source>1 &week</source> - <translation type="unfinished">1 &Woche</translation> - </message> - <message> - <source>1 &year</source> - <translation type="unfinished">1 &Jahr</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">&Kopiere IP/Netzmaske</translation> - </message> - <message> - <source>&Unban</source> - <translation type="unfinished">&Entsperren</translation> - </message> - <message> - <source>Network activity disabled</source> - <translation type="unfinished">Netzwerkaktivität deaktiviert</translation> - </message> - <message> - <source>Executing command without any wallet</source> - <translation type="unfinished">Befehl wird ohne spezifizierte Wallet ausgeführt</translation> - </message> - <message> - <source>Ctrl+I</source> - <translation type="unfinished">Strg+I</translation> - </message> - <message> - <source>Ctrl+T</source> - <translation type="unfinished">Strg+T</translation> - </message> - <message> - <source>Ctrl+N</source> - <translation type="unfinished">Strg+N</translation> - </message> - <message> - <source>Ctrl+P</source> - <translation type="unfinished">Strg+P</translation> - </message> - <message> - <source>Node window - [%1]</source> - <translation type="unfinished">Node-Fenster - [%1]</translation> - </message> - <message> - <source>Executing command using "%1" wallet</source> - <translation type="unfinished">Befehl wird mit Wallet "%1" ausgeführt</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">Willkommen bei der %1 RPC Konsole. -Benutze die Auf/Ab Pfeiltasten, um durch die Historie zu navigieren, und %2, um den Bildschirm zu löschen. -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> - </message> - <message> - <source>Executing…</source> - <extracomment>A console message indicating an entered command is currently being executed.</extracomment> - <translation type="unfinished">Ausführen…</translation> - </message> - <message> - <source>(peer: %1)</source> - <translation type="unfinished">(Gegenstelle: %1)</translation> - </message> - <message> - <source>via %1</source> - <translation type="unfinished">über %1</translation> - </message> - <message> - <source>Yes</source> - <translation type="unfinished">Ja</translation> - </message> - <message> - <source>No</source> - <translation type="unfinished">Nein</translation> - </message> - <message> - <source>To</source> - <translation type="unfinished">An</translation> - </message> - <message> - <source>From</source> - <translation type="unfinished">Von</translation> - </message> - <message> - <source>Ban for</source> - <translation type="unfinished">Sperren für</translation> - </message> - <message> - <source>Never</source> - <translation type="unfinished">Nie</translation> - </message> - <message> - <source>Unknown</source> - <translation type="unfinished">Unbekannt</translation> - </message> -</context> -<context> - <name>ReceiveCoinsDialog</name> - <message> - <source>&Amount:</source> - <translation type="unfinished">&Betrag:</translation> - </message> - <message> - <source>&Label:</source> - <translation type="unfinished">&Bezeichnung:</translation> - </message> - <message> - <source>&Message:</source> - <translation type="unfinished">&Nachricht:</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">Eine optionale Nachricht, die an die Zahlungsanforderung angehängt wird. Sie wird angezeigt, wenn die Anforderung geöffnet wird. Hinweis: Diese Nachricht wird nicht mit der Zahlung über das Bitcoin-Netzwerk gesendet.</translation> - </message> - <message> - <source>An optional label to associate with the new receiving address.</source> - <translation type="unfinished">Eine optionale Bezeichnung, die der neuen Empfangsadresse zugeordnet wird.</translation> - </message> - <message> - <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation type="unfinished">Verwenden Sie dieses Formular, um Zahlungen anzufordern. Alle Felder sind <b>optional</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">Ein optional angeforderter Betrag. Lassen Sie dieses Feld leer oder setzen Sie es auf 0, um keinen spezifischen Betrag anzufordern.</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">Ein optionales Etikett zu einer neuen Empfängeradresse (für dich zum Identifizieren einer Rechnung). Es wird auch der Zahlungsanforderung beigefügt.</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">Eine optionale Nachricht, die der Zahlungsanforderung beigefügt wird und dem Absender angezeigt werden kann.</translation> - </message> - <message> - <source>&Create new receiving address</source> - <translation type="unfinished">&Neue Empfangsadresse erstellen</translation> - </message> - <message> - <source>Clear all fields of the form.</source> - <translation type="unfinished">Alle Formularfelder zurücksetzen.</translation> - </message> - <message> - <source>Clear</source> - <translation type="unfinished">Zurücksetzen</translation> - </message> - <message> - <source>Requested payments history</source> - <translation type="unfinished">Verlauf der angeforderten Zahlungen</translation> - </message> - <message> - <source>Show the selected request (does the same as double clicking an entry)</source> - <translation type="unfinished">Ausgewählte Zahlungsanforderungen anzeigen (entspricht einem Doppelklick auf einen Eintrag)</translation> - </message> - <message> - <source>Show</source> - <translation type="unfinished">Anzeigen</translation> - </message> - <message> - <source>Remove the selected entries from the list</source> - <translation type="unfinished">Ausgewählte Einträge aus der Liste entfernen</translation> - </message> - <message> - <source>Remove</source> - <translation type="unfinished">Entfernen</translation> - </message> - <message> - <source>Copy &URI</source> - <translation type="unfinished">&URI kopieren</translation> - </message> - <message> - <source>&Copy address</source> - <translation type="unfinished">&Adresse kopieren</translation> - </message> - <message> - <source>Copy &label</source> - <translation type="unfinished">&Bezeichnung kopieren</translation> - </message> - <message> - <source>Copy &message</source> - <translation type="unfinished">&Nachricht kopieren</translation> - </message> - <message> - <source>Copy &amount</source> - <translation type="unfinished">&Betrag kopieren</translation> - </message> - <message> - <source>Not recommended due to higher fees and less protection against typos.</source> - <translation type="unfinished">Nicht zu empfehlen aufgrund höherer Gebühren und geringerem Schutz vor Tippfehlern.</translation> - </message> - <message> - <source>Generates an address compatible with older wallets.</source> - <translation type="unfinished">Generiert eine Adresse, die mit älteren Wallets kompatibel ist.</translation> - </message> - <message> - <source>Generates a native segwit address (BIP-173). Some old wallets don't support it.</source> - <translation type="unfinished">Generiert eine native Segwit-Adresse (BIP-173). Einige alte Wallets unterstützen es nicht.</translation> - </message> - <message> - <source>Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source> - <translation type="unfinished">Bech32m (BIP-350) ist ein Upgrade auf Bech32, Wallet-Unterstützung ist immer noch eingeschränkt.</translation> - </message> - <message> - <source>Could not unlock wallet.</source> - <translation type="unfinished">Wallet konnte nicht entsperrt werden.</translation> - </message> - <message> - <source>Could not generate new %1 address</source> - <translation type="unfinished">Konnte neue %1 Adresse nicht erzeugen.</translation> - </message> -</context> -<context> - <name>ReceiveRequestDialog</name> - <message> - <source>Request payment to …</source> - <translation type="unfinished">Zahlung anfordern an ...</translation> - </message> - <message> - <source>Address:</source> - <translation type="unfinished">Adresse:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">Betrag:</translation> - </message> - <message> - <source>Label:</source> - <translation type="unfinished">Bezeichnung:</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">Nachricht:</translation> - </message> - <message> - <source>Copy &URI</source> - <translation type="unfinished">&URI kopieren</translation> - </message> - <message> - <source>Copy &Address</source> - <translation type="unfinished">&Adresse kopieren</translation> - </message> - <message> - <source>&Verify</source> - <translation type="unfinished">&Überprüfen</translation> - </message> - <message> - <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">Verifizieren Sie diese Adresse z.B. auf dem Display Ihres Hardware-Wallets</translation> - </message> - <message> - <source>&Save Image…</source> - <translation type="unfinished">&Bild speichern...</translation> - </message> - <message> - <source>Payment information</source> - <translation type="unfinished">Zahlungsinformationen</translation> - </message> - <message> - <source>Request payment to %1</source> - <translation type="unfinished">Zahlung anfordern an %1</translation> - </message> -</context> -<context> - <name>RecentRequestsTableModel</name> - <message> - <source>Date</source> - <translation type="unfinished">Datum</translation> - </message> - <message> - <source>Label</source> - <translation type="unfinished">Bezeichnung</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">Nachricht</translation> - </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(keine Bezeichnung)</translation> - </message> - <message> - <source>(no message)</source> - <translation type="unfinished">(keine Nachricht)</translation> - </message> - <message> - <source>(no amount requested)</source> - <translation type="unfinished">(kein Betrag angefordert)</translation> - </message> - <message> - <source>Requested</source> - <translation type="unfinished">Angefordert</translation> - </message> -</context> + </context> <context> <name>SendCoinsDialog</name> <message> - <source>Send Coins</source> - <translation type="unfinished">Bitcoins überweisen</translation> - </message> - <message> - <source>Coin Control Features</source> - <translation type="unfinished">"Coin Control"-Funktionen</translation> - </message> - <message> - <source>automatically selected</source> - <translation type="unfinished">automatisch ausgewählt</translation> - </message> - <message> - <source>Insufficient funds!</source> - <translation type="unfinished">Unzureichender Kontostand!</translation> - </message> - <message> - <source>Quantity:</source> - <translation type="unfinished">Anzahl:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">Betrag:</translation> - </message> - <message> - <source>Fee:</source> - <translation type="unfinished">Gebühr:</translation> - </message> - <message> - <source>After Fee:</source> - <translation type="unfinished">Abzüglich Gebühr:</translation> - </message> - <message> - <source>Change:</source> - <translation type="unfinished">Wechselgeld:</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">Wenn dies aktiviert ist, aber die Wechselgeld-Adresse leer oder ungültig ist, wird das Wechselgeld an eine neu generierte Adresse gesendet.</translation> - </message> - <message> - <source>Custom change address</source> - <translation type="unfinished">Benutzerdefinierte Wechselgeld-Adresse</translation> - </message> - <message> - <source>Transaction Fee:</source> - <translation type="unfinished">Transaktionsgebühr:</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">Die Verwendung der "fallbackfee" kann dazu führen, dass eine gesendete Transaktion erst nach mehreren Stunden oder Tagen (oder nie) bestätigt wird. Erwägen Sie, Ihre Gebühr manuell auszuwählen oder warten Sie, bis Sie die gesamte Chain validiert haben.</translation> - </message> - <message> - <source>Warning: Fee estimation is currently not possible.</source> - <translation type="unfinished">Achtung: Berechnung der Gebühr ist momentan nicht möglich.</translation> - </message> - <message> - <source>per kilobyte</source> - <translation type="unfinished">pro Kilobyte</translation> - </message> - <message> - <source>Hide</source> - <translation type="unfinished">Ausblenden</translation> - </message> - <message> - <source>Recommended:</source> - <translation type="unfinished">Empfehlungen:</translation> - </message> - <message> - <source>Custom:</source> - <translation type="unfinished">Benutzerdefiniert:</translation> - </message> - <message> - <source>Send to multiple recipients at once</source> - <translation type="unfinished">An mehrere Empfänger auf einmal überweisen</translation> - </message> - <message> - <source>Add &Recipient</source> - <translation type="unfinished">Empfänger &hinzufügen</translation> - </message> - <message> - <source>Clear all fields of the form.</source> - <translation type="unfinished">Alle Formularfelder zurücksetzen.</translation> - </message> - <message> - <source>Inputs…</source> - <translation type="unfinished">Eingaben...</translation> - </message> - <message> - <source>Choose…</source> - <translation type="unfinished">Auswählen...</translation> - </message> - <message> - <source>Hide transaction fee settings</source> - <translation type="unfinished">Einstellungen für Transaktionsgebühr nicht anzeigen</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">Gib manuell eine Gebühr pro kB (1.000 Bytes) der virtuellen Transaktionsgröße an. - -Hinweis: Da die Gebühr auf Basis der Bytes berechnet wird, führt eine Gebührenrate von "100 Satoshis per kvB" für eine Transaktion von 500 virtuellen Bytes (die Hälfte von 1 kvB) letztlich zu einer Gebühr von nur 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">Nur die minimale Gebühr zu bezahlen ist so lange in Ordnung, wie weniger Transaktionsvolumen als Platz in den Blöcken vorhanden ist. Aber Vorsicht, diese Option kann dazu führen, dass Transaktionen nicht bestätigt werden, wenn mehr Bedarf an Bitcoin-Transaktionen besteht als das Netzwerk verarbeiten kann.</translation> - </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> - </message> - <message> - <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> - <translation type="unfinished">(Intelligente Gebühr noch nicht initialisiert. Das dauert normalerweise ein paar Blocks…)</translation> - </message> - <message> - <source>Confirmation time target:</source> - <translation type="unfinished">Bestätigungsziel:</translation> - </message> - <message> - <source>Enable Replace-By-Fee</source> - <translation type="unfinished">Aktiviere Replace-By-Fee</translation> - </message> - <message> - <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> - <translation type="unfinished">Mit Replace-By-Fee (BIP-125) kann die Transaktionsgebühr nach dem Senden erhöht werden. Ohne dies wird eine höhere Gebühr empfohlen, um das Risiko einer hohen Transaktionszeit zu reduzieren.</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">&Zurücksetzen</translation> - </message> - <message> - <source>Balance:</source> - <translation type="unfinished">Kontostand:</translation> - </message> - <message> - <source>Confirm the send action</source> - <translation type="unfinished">Überweisung bestätigen</translation> - </message> - <message> - <source>S&end</source> - <translation type="unfinished">&Überweisen</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">Anzahl kopieren</translation> </message> <message> - <source>Copy amount</source> - <translation type="unfinished">Betrag kopieren</translation> - </message> - <message> - <source>Copy fee</source> - <translation type="unfinished">Gebühr kopieren</translation> - </message> - <message> <source>Copy after fee</source> <translation type="unfinished">Abzüglich Gebühr kopieren</translation> </message> - <message> - <source>Copy bytes</source> - <translation type="unfinished">Bytes kopieren</translation> - </message> - <message> - <source>Copy change</source> - <translation type="unfinished">Wechselgeld kopieren</translation> - </message> - <message> - <source>%1 (%2 blocks)</source> - <translation type="unfinished">%1 (%2 Blöcke)</translation> - </message> - <message> - <source>Sign on device</source> - <extracomment>"device" usually means a hardware wallet.</extracomment> - <translation type="unfinished">Gerät anmelden</translation> - </message> - <message> - <source>Connect your hardware wallet first.</source> - <translation type="unfinished">Verbinden Sie zunächst Ihre Hardware-Wallet</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">Pfad für externes Signierskript in Optionen festlegen -> Wallet</translation> - </message> - <message> - <source>Cr&eate Unsigned</source> - <translation type="unfinished">Unsigniert &erzeugen</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">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> - <translation type="unfinished">%1 an '%2'</translation> - </message> - <message> - <source>%1 to %2</source> - <translation type="unfinished">%1 an %2</translation> - </message> - <message> - <source>To review recipient list click "Show Details…"</source> - <translation type="unfinished">Um die Empfängerliste zu sehen, klicke auf "Zeige Details…"</translation> - </message> - <message> - <source>Sign failed</source> - <translation type="unfinished">Signierung der Nachricht fehlgeschlagen</translation> - </message> - <message> - <source>External signer not found</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Es konnte kein externes Gerät zum signieren gefunden werden</translation> - </message> - <message> - <source>External signer failure</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Signierung durch externes Gerät fehlgeschlagen</translation> - </message> - <message> - <source>Save Transaction Data</source> - <translation type="unfinished">Speichere Transaktionsdaten</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">Teilweise signierte Transaktion (binär)</translation> - </message> - <message> - <source>PSBT saved</source> - <extracomment>Popup message when a PSBT has been saved to a file</extracomment> - <translation type="unfinished">PSBT gespeichert</translation> - </message> - <message> - <source>External balance:</source> - <translation type="unfinished">Externe Bilanz:</translation> - </message> - <message> - <source>or</source> - <translation type="unfinished">oder</translation> - </message> - <message> - <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> - <translation type="unfinished">Sie können die Gebühr später erhöhen (signalisiert Replace-By-Fee, BIP-125).</translation> - </message> - <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> - <translation type="unfinished">Überprüfen Sie bitte Ihr Transaktionsvorhaben. Dadurch wird eine Partiell Signierte Bitcoin-Transaktion (PSBT) erstellt, die Sie speichern oder kopieren und dann z. B. mit einer Offline-Wallet %1 oder einer PSBT-kompatible Hardware-Wallet nutzen können.</translation> - </message> - <message> - <source>%1 from wallet '%2'</source> - <translation type="unfinished">%1 von Wallet '%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">Möchtest du diese Transaktion erstellen?</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">Bitte überprüfen Sie Ihre Transaktion. Sie können diese Transaktion erstellen und versenden oder eine Partiell Signierte Bitcoin Transaction (PSBT) erstellen, die Sie speichern oder kopieren und dann z.B. mit einer offline %1 Wallet oder einer PSBT-kompatiblen Hardware-Wallet signieren können.</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">Bitte überprüfen sie ihre Transaktion.</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">Transaktionsgebühr</translation> - </message> - <message> - <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation type="unfinished">Replace-By-Fee, BIP-125 wird nicht angezeigt.</translation> - </message> - <message> - <source>Total Amount</source> - <translation type="unfinished">Gesamtbetrag</translation> - </message> - <message> - <source>Unsigned Transaction</source> - <comment>PSBT copied</comment> - <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> - <translation type="unfinished">Unsignierte Transaktion</translation> - </message> - <message> - <source>The PSBT has been copied to the clipboard. You can also save it.</source> - <translation type="unfinished">Die PSBT wurde in die Zwischenablage kopiert. Kann auch abgespeichert werden.</translation> - </message> - <message> - <source>PSBT saved to disk</source> - <translation type="unfinished">PSBT auf Festplatte gespeichert</translation> - </message> - <message> - <source>Confirm send coins</source> - <translation type="unfinished">Überweisung bestätigen</translation> - </message> - <message> - <source>Watch-only balance:</source> - <translation type="unfinished">Nur-Anzeige Saldo:</translation> - </message> - <message> - <source>The recipient address is not valid. Please recheck.</source> - <translation type="unfinished">Die Zahlungsadresse ist ungültig, bitte nochmals überprüfen.</translation> - </message> - <message> - <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">Der zu zahlende Betrag muss größer als 0 sein.</translation> - </message> - <message> - <source>The amount exceeds your balance.</source> - <translation type="unfinished">Der angegebene Betrag übersteigt Ihren Kontostand.</translation> - </message> - <message> - <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation type="unfinished">Der angegebene Betrag übersteigt aufgrund der Transaktionsgebühr in Höhe von %1 Ihren Kontostand.</translation> - </message> - <message> - <source>Duplicate address found: addresses should only be used once each.</source> - <translation type="unfinished">Doppelte Adresse entdeckt: Adressen sollten jeweils nur einmal benutzt werden.</translation> - </message> - <message> - <source>Transaction creation failed!</source> - <translation type="unfinished">Transaktionserstellung fehlgeschlagen!</translation> - </message> - <message> - <source>A fee higher than %1 is considered an absurdly high fee.</source> - <translation type="unfinished">Eine höhere Gebühr als %1 wird als unsinnig hohe Gebühr angesehen.</translation> - </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Block</numerusform> - <numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Blöcken</numerusform> + <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> + <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> </translation> </message> - <message> - <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished">Warnung: Ungültige Bitcoin-Adresse</translation> - </message> - <message> - <source>Warning: Unknown change address</source> - <translation type="unfinished">Warnung: Unbekannte Wechselgeld-Adresse</translation> - </message> - <message> - <source>Confirm custom change address</source> - <translation type="unfinished">Bestätige benutzerdefinierte Wechselgeld-Adresse</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">Die ausgewählte Wechselgeld-Adresse ist nicht Bestandteil dieses Wallets. Einige oder alle Mittel aus Ihrem Wallet könnten an diese Adresse gesendet werden. Wollen Sie das wirklich?</translation> - </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(keine Bezeichnung)</translation> - </message> -</context> -<context> - <name>SendCoinsEntry</name> - <message> - <source>A&mount:</source> - <translation type="unfinished">Betra&g:</translation> - </message> - <message> - <source>Pay &To:</source> - <translation type="unfinished">E&mpfänger:</translation> - </message> - <message> - <source>&Label:</source> - <translation type="unfinished">&Bezeichnung:</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">Bereits verwendete Adresse auswählen</translation> - </message> - <message> - <source>The Bitcoin address to send the payment to</source> - <translation type="unfinished">Die Zahlungsadresse der Überweisung</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">Adresse aus der Zwischenablage einfügen</translation> - </message> - <message> - <source>Remove this entry</source> - <translation type="unfinished">Diesen Eintrag entfernen</translation> - </message> - <message> - <source>The amount to send in the selected unit</source> - <translation type="unfinished">Zu sendender Betrag in der ausgewählten Einheit</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">Die Gebühr wird vom zu überweisenden Betrag abgezogen. Der Empfänger wird also weniger Bitcoins erhalten, als Sie im Betrags-Feld eingegeben haben. Falls mehrere Empfänger ausgewählt wurden, wird die Gebühr gleichmäßig verteilt.</translation> - </message> - <message> - <source>S&ubtract fee from amount</source> - <translation type="unfinished">Gebühr vom Betrag ab&ziehen</translation> - </message> - <message> - <source>Use available balance</source> - <translation type="unfinished">Benutze verfügbaren Kontostand</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">Nachricht:</translation> - </message> - <message> - <source>Enter a label for this address to add it to the list of used addresses</source> - <translation type="unfinished">Bezeichnung für diese Adresse eingeben, um sie zur Liste bereits verwendeter Adressen hinzuzufügen.</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">Eine an die "bitcoin:"-URI angefügte Nachricht, die zusammen mit der Transaktion gespeichert wird. Hinweis: Diese Nachricht wird nicht über das Bitcoin-Netzwerk gesendet.</translation> - </message> -</context> -<context> - <name>SendConfirmationDialog</name> - <message> - <source>Send</source> - <translation type="unfinished">Senden</translation> - </message> - <message> - <source>Create Unsigned</source> - <translation type="unfinished">Unsigniert erstellen</translation> - </message> -</context> -<context> - <name>SignVerifyMessageDialog</name> - <message> - <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">Signaturen - eine Nachricht signieren / verifizieren</translation> - </message> - <message> - <source>&Sign Message</source> - <translation type="unfinished">Nachricht &signieren</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">Sie können Nachrichten/Vereinbarungen mit Hilfe Ihrer Adressen signieren, um zu beweisen, dass Sie Bitcoins empfangen können, die an diese Adressen überwiesen werden. Seien Sie vorsichtig und signieren Sie nichts Vages oder Willkürliches, um Ihre Indentität vor Phishingangriffen zu schützen. Signieren Sie nur vollständig-detaillierte Aussagen, mit denen Sie auch einverstanden sind.</translation> - </message> - <message> - <source>The Bitcoin address to sign the message with</source> - <translation type="unfinished">Die Bitcoin-Adresse, mit der die Nachricht signiert wird</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">Bereits verwendete Adresse auswählen</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">Adresse aus der Zwischenablage einfügen</translation> - </message> - <message> - <source>Enter the message you want to sign here</source> - <translation type="unfinished">Zu signierende Nachricht hier eingeben</translation> - </message> - <message> - <source>Signature</source> - <translation type="unfinished">Signatur</translation> - </message> - <message> - <source>Copy the current signature to the system clipboard</source> - <translation type="unfinished">Aktuelle Signatur in die Zwischenablage kopieren</translation> - </message> - <message> - <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">Die Nachricht signieren, um den Besitz dieser Bitcoin-Adresse zu beweisen</translation> - </message> - <message> - <source>Sign &Message</source> - <translation type="unfinished">&Nachricht signieren</translation> - </message> - <message> - <source>Reset all sign message fields</source> - <translation type="unfinished">Alle "Nachricht signieren"-Felder zurücksetzen</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">&Zurücksetzen</translation> - </message> - <message> - <source>&Verify Message</source> - <translation type="unfinished">Nachricht &verifizieren</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">Geben Sie die Zahlungsadresse des Empfängers, Nachricht (achten Sie darauf Zeilenumbrüche, Leerzeichen, Tabulatoren usw. exakt zu kopieren) und Signatur unten ein, um die Nachricht zu verifizieren. Vorsicht, interpretieren Sie nicht mehr in die Signatur hinein, als in der signierten Nachricht selber enthalten ist, um nicht von einem Man-in-the-middle-Angriff hinters Licht geführt zu werden. Beachten Sie, dass dies nur beweist, dass die signierende Partei über diese Adresse Überweisungen empfangen kann.</translation> - </message> - <message> - <source>The Bitcoin address the message was signed with</source> - <translation type="unfinished">Die Bitcoin-Adresse, mit der die Nachricht signiert wurde</translation> - </message> - <message> - <source>The signed message to verify</source> - <translation type="unfinished">Die zu überprüfende signierte Nachricht</translation> - </message> - <message> - <source>The signature given when the message was signed</source> - <translation type="unfinished">Die beim Signieren der Nachricht geleistete Signatur</translation> - </message> - <message> - <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation type="unfinished">Die Nachricht verifizieren, um sicherzustellen, dass diese mit der angegebenen Bitcoin-Adresse signiert wurde</translation> - </message> - <message> - <source>Verify &Message</source> - <translation type="unfinished">&Nachricht verifizieren</translation> - </message> - <message> - <source>Reset all verify message fields</source> - <translation type="unfinished">Alle "Nachricht verifizieren"-Felder zurücksetzen</translation> - </message> - <message> - <source>Click "Sign Message" to generate signature</source> - <translation type="unfinished">Auf "Nachricht signieren" klicken, um die Signatur zu erzeugen</translation> - </message> - <message> - <source>The entered address is invalid.</source> - <translation type="unfinished">Die eingegebene Adresse ist ungültig.</translation> - </message> - <message> - <source>Please check the address and try again.</source> - <translation type="unfinished">Bitte überprüfen Sie die Adresse und versuchen Sie es erneut.</translation> - </message> - <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Die eingegebene Adresse verweist nicht auf einen Schlüssel.</translation> - </message> - <message> - <source>Wallet unlock was cancelled.</source> - <translation type="unfinished">Wallet-Entsperrung wurde abgebrochen.</translation> - </message> - <message> - <source>No error</source> - <translation type="unfinished">Kein Fehler</translation> - </message> - <message> - <source>Private key for the entered address is not available.</source> - <translation type="unfinished">Privater Schlüssel zur eingegebenen Adresse ist nicht verfügbar.</translation> - </message> - <message> - <source>Message signing failed.</source> - <translation type="unfinished">Signierung der Nachricht fehlgeschlagen.</translation> - </message> - <message> - <source>Message signed.</source> - <translation type="unfinished">Nachricht signiert.</translation> - </message> - <message> - <source>The signature could not be decoded.</source> - <translation type="unfinished">Die Signatur konnte nicht dekodiert werden.</translation> - </message> - <message> - <source>Please check the signature and try again.</source> - <translation type="unfinished">Bitte überprüfen Sie die Signatur und versuchen Sie es erneut.</translation> - </message> - <message> - <source>The signature did not match the message digest.</source> - <translation type="unfinished">Die Signatur entspricht nicht dem "Message Digest".</translation> - </message> - <message> - <source>Message verification failed.</source> - <translation type="unfinished">Verifizierung der Nachricht fehlgeschlagen.</translation> - </message> - <message> - <source>Message verified.</source> - <translation type="unfinished">Nachricht verifiziert.</translation> - </message> -</context> -<context> - <name>SplashScreen</name> - <message> - <source>(press q to shutdown and continue later)</source> - <translation type="unfinished">(drücke q, um herunterzufahren und später fortzuführen)</translation> - </message> - <message> - <source>press q to shutdown</source> - <translation type="unfinished">q zum Herunterfahren drücken</translation> - </message> -</context> + </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">steht im Konflikt mit einer Transaktion mit %1 Bestätigungen</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/unbestätigt, im Speicherpool</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/unbestätigt, nicht im Speicherpool</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">eingestellt</translation> - </message> - <message> - <source>%1/unconfirmed</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment> - <translation type="unfinished">%1/unbestätigt</translation> - </message> - <message> - <source>%1 confirmations</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment> - <translation type="unfinished">%1 Bestätigungen</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">Datum</translation> - </message> - <message> - <source>Source</source> - <translation type="unfinished">Quelle</translation> - </message> - <message> - <source>Generated</source> - <translation type="unfinished">Erzeugt</translation> - </message> - <message> - <source>From</source> - <translation type="unfinished">Von</translation> - </message> - <message> - <source>unknown</source> - <translation type="unfinished">unbekannt</translation> - </message> - <message> - <source>To</source> - <translation type="unfinished">An</translation> - </message> - <message> - <source>own address</source> - <translation type="unfinished">eigene Adresse</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">beobachtet</translation> - </message> - <message> - <source>label</source> - <translation type="unfinished">Bezeichnung</translation> - </message> - <message> - <source>Credit</source> - <translation type="unfinished">Gutschrift</translation> - </message> <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> - <numerusform>reift noch %n weiteren Block</numerusform> - <numerusform>reift noch %n weitere Blöcken</numerusform> + <numerusform>matures in %n more block(s)</numerusform> + <numerusform>matures in %n more block(s)</numerusform> </translation> </message> <message> - <source>not accepted</source> - <translation type="unfinished">nicht angenommen</translation> - </message> - <message> - <source>Debit</source> - <translation type="unfinished">Belastung</translation> - </message> - <message> - <source>Total debit</source> - <translation type="unfinished">Gesamtbelastung</translation> - </message> - <message> - <source>Total credit</source> - <translation type="unfinished">Gesamtgutschrift</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">Transaktionsgebühr</translation> - </message> - <message> - <source>Net amount</source> - <translation type="unfinished">Nettobetrag</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">Nachricht</translation> - </message> - <message> - <source>Comment</source> - <translation type="unfinished">Kommentar</translation> - </message> - <message> - <source>Transaction ID</source> - <translation type="unfinished">Transaktionskennung</translation> - </message> - <message> - <source>Transaction total size</source> - <translation type="unfinished">Gesamte Transaktionsgröße</translation> - </message> - <message> - <source>Transaction virtual size</source> - <translation type="unfinished">Virtuelle Größe der Transaktion</translation> - </message> - <message> - <source>Output index</source> - <translation type="unfinished">Ausgabeindex</translation> - </message> - <message> - <source>%1 (Certificate was not verified)</source> - <translation type="unfinished">%1 (Zertifikat wurde nicht verifiziert)</translation> - </message> - <message> - <source>Merchant</source> - <translation type="unfinished">Händler</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">Erzeugte Bitcoins müssen %1 Blöcke lang reifen, bevor sie ausgegeben werden können. Als Sie diesen Block erzeugten, wurde er an das Netzwerk übertragen, um ihn der Blockchain hinzuzufügen. Falls dies fehlschlägt wird der Status in "nicht angenommen" geändert und Sie werden keine Bitcoins gutgeschrieben bekommen. Das kann gelegentlich passieren, wenn ein anderer Knoten einen Block fast zeitgleich erzeugt.</translation> - </message> - <message> - <source>Debug information</source> - <translation type="unfinished">Debug-Informationen</translation> - </message> - <message> - <source>Transaction</source> - <translation type="unfinished">Transaktion</translation> - </message> - <message> - <source>Inputs</source> - <translation type="unfinished">Eingaben</translation> - </message> - <message> <source>Amount</source> <translation type="unfinished">Betrag</translation> </message> - <message> - <source>true</source> - <translation type="unfinished">wahr</translation> - </message> - <message> - <source>false</source> - <translation type="unfinished">falsch</translation> - </message> -</context> -<context> - <name>TransactionDescDialog</name> - <message> - <source>This pane shows a detailed description of the transaction</source> - <translation type="unfinished">Dieser Bereich zeigt eine detaillierte Beschreibung der Transaktion an</translation> - </message> - <message> - <source>Details for %1</source> - <translation type="unfinished">Details für %1</translation> - </message> -</context> -<context> - <name>TransactionTableModel</name> - <message> - <source>Date</source> - <translation type="unfinished">Datum</translation> - </message> - <message> - <source>Type</source> - <translation type="unfinished">Typ</translation> - </message> - <message> - <source>Label</source> - <translation type="unfinished">Bezeichnung</translation> - </message> - <message> - <source>Unconfirmed</source> - <translation type="unfinished">Unbestätigt</translation> - </message> - <message> - <source>Abandoned</source> - <translation type="unfinished">Eingestellt</translation> - </message> - <message> - <source>Confirming (%1 of %2 recommended confirmations)</source> - <translation type="unfinished">Wird bestätigt (%1 von %2 empfohlenen Bestätigungen)</translation> - </message> - <message> - <source>Confirmed (%1 confirmations)</source> - <translation type="unfinished">Bestätigt (%1 Bestätigungen)</translation> - </message> - <message> - <source>Conflicted</source> - <translation type="unfinished">in Konflikt stehend</translation> - </message> - <message> - <source>Immature (%1 confirmations, will be available after %2)</source> - <translation type="unfinished">Unreif (%1 Bestätigungen, wird verfügbar sein nach %2)</translation> - </message> - <message> - <source>Generated but not accepted</source> - <translation type="unfinished">Generiert, aber nicht akzeptiert</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">Empfangen über</translation> - </message> - <message> - <source>Received from</source> - <translation type="unfinished">Empfangen von</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">Überwiesen an</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">Erarbeitet</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">beobachtet</translation> - </message> - <message> - <source>(n/a)</source> - <translation type="unfinished">(k.A.)</translation> - </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(keine Bezeichnung)</translation> - </message> - <message> - <source>Transaction status. Hover over this field to show number of confirmations.</source> - <translation type="unfinished">Transaktionsstatus. Fahren Sie mit der Maus über dieses Feld, um die Anzahl der Bestätigungen zu sehen.</translation> - </message> - <message> - <source>Date and time that the transaction was received.</source> - <translation type="unfinished">Datum und Zeit als die Transaktion empfangen wurde.</translation> - </message> - <message> - <source>Type of transaction.</source> - <translation type="unfinished">Art der Transaktion</translation> - </message> - <message> - <source>Whether or not a watch-only address is involved in this transaction.</source> - <translation type="unfinished">Zeigt an, ob eine beobachtete Adresse in diese Transaktion involviert ist.</translation> - </message> - <message> - <source>User-defined intent/purpose of the transaction.</source> - <translation type="unfinished">Benutzerdefinierter Verwendungszweck der Transaktion</translation> - </message> - <message> - <source>Amount removed from or added to balance.</source> - <translation type="unfinished">Der Betrag, der dem Kontostand abgezogen oder hinzugefügt wurde.</translation> - </message> -</context> -<context> - <name>TransactionView</name> - <message> - <source>All</source> - <translation type="unfinished">Alle</translation> - </message> - <message> - <source>Today</source> - <translation type="unfinished">Heute</translation> - </message> - <message> - <source>This week</source> - <translation type="unfinished">Diese Woche</translation> - </message> - <message> - <source>This month</source> - <translation type="unfinished">Diesen Monat</translation> - </message> - <message> - <source>Last month</source> - <translation type="unfinished">Letzten Monat</translation> - </message> - <message> - <source>This year</source> - <translation type="unfinished">Dieses Jahr</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">Empfangen über</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">Überwiesen an</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">Erarbeitet</translation> - </message> - <message> - <source>Other</source> - <translation type="unfinished">Andere</translation> - </message> - <message> - <source>Enter address, transaction id, or label to search</source> - <translation type="unfinished">Zu suchende Adresse, Transaktion oder Bezeichnung eingeben</translation> - </message> - <message> - <source>Min amount</source> - <translation type="unfinished">Mindestbetrag</translation> - </message> - <message> - <source>Range…</source> - <translation type="unfinished">Bereich…</translation> - </message> - <message> - <source>&Copy address</source> - <translation type="unfinished">&Adresse kopieren</translation> - </message> - <message> - <source>Copy &label</source> - <translation type="unfinished">&Bezeichnung kopieren</translation> - </message> - <message> - <source>Copy &amount</source> - <translation type="unfinished">&Betrag kopieren</translation> - </message> - <message> - <source>Copy transaction &ID</source> - <translation type="unfinished">Transaktionskennung kopieren</translation> - </message> - <message> - <source>Copy &raw transaction</source> - <translation type="unfinished">&Rohdaten der Transaktion kopieren</translation> - </message> - <message> - <source>Copy full transaction &details</source> - <translation type="unfinished">Vollständige Transaktions&details kopieren</translation> - </message> - <message> - <source>&Show transaction details</source> - <translation type="unfinished">Transaktionsdetails &anzeigen</translation> - </message> - <message> - <source>Increase transaction &fee</source> - <translation type="unfinished">Transaktions&gebühr erhöhen</translation> - </message> - <message> - <source>A&bandon transaction</source> - <translation type="unfinished">Transaktion a&bbrechen</translation> - </message> - <message> - <source>&Edit address label</source> - <translation type="unfinished">Adressbezeichnung &bearbeiten</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">Zeige in %1</translation> - </message> - <message> - <source>Export Transaction History</source> - <translation type="unfinished">Transaktionsverlauf exportieren</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">Durch Komma getrennte Datei</translation> - </message> - <message> - <source>Confirmed</source> - <translation type="unfinished">Bestätigt</translation> - </message> - <message> - <source>Watch-only</source> - <translation type="unfinished">beobachtet</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">Datum</translation> - </message> - <message> - <source>Type</source> - <translation type="unfinished">Typ</translation> - </message> - <message> - <source>Label</source> - <translation type="unfinished">Bezeichnung</translation> - </message> - <message> - <source>Address</source> - <translation type="unfinished">Adresse</translation> - </message> - <message> - <source>Exporting Failed</source> - <translation type="unfinished">Exportieren fehlgeschlagen</translation> - </message> - <message> - <source>There was an error trying to save the transaction history to %1.</source> - <translation type="unfinished">Beim Speichern des Transaktionsverlaufs nach %1 ist ein Fehler aufgetreten.</translation> - </message> - <message> - <source>Exporting Successful</source> - <translation type="unfinished">Exportieren erfolgreich</translation> - </message> - <message> - <source>The transaction history was successfully saved to %1.</source> - <translation type="unfinished">Speichern des Transaktionsverlaufs nach %1 war erfolgreich.</translation> - </message> - <message> - <source>Range:</source> - <translation type="unfinished">Zeitraum:</translation> - </message> - <message> - <source>to</source> - <translation type="unfinished">bis</translation> - </message> -</context> -<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">Es wurde keine Wallet geladen. -Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. -- ODER-</translation> - </message> - <message> - <source>Create a new wallet</source> - <translation type="unfinished">Neues Wallet erstellen</translation> - </message> - <message> - <source>Error</source> - <translation type="unfinished">Fehler</translation> - </message> - <message> - <source>Unable to decode PSBT from clipboard (invalid base64)</source> - <translation type="unfinished">Konnte PSBT aus Zwischenablage nicht entschlüsseln (ungültiges Base64)</translation> - </message> - <message> - <source>Load Transaction Data</source> - <translation type="unfinished">Lade Transaktionsdaten</translation> - </message> - <message> - <source>Partially Signed Transaction (*.psbt)</source> - <translation type="unfinished">Teilsignierte Transaktion (*.psbt)</translation> - </message> - <message> - <source>PSBT file must be smaller than 100 MiB</source> - <translation type="unfinished">PSBT-Datei muss kleiner als 100 MiB sein</translation> - </message> - <message> - <source>Unable to decode PSBT</source> - <translation type="unfinished">PSBT konnte nicht entschlüsselt werden</translation> - </message> -</context> -<context> - <name>WalletModel</name> - <message> - <source>Send Coins</source> - <translation type="unfinished">Bitcoins überweisen</translation> - </message> - <message> - <source>Fee bump error</source> - <translation type="unfinished">Gebührenerhöhungsfehler</translation> - </message> - <message> - <source>Increasing transaction fee failed</source> - <translation type="unfinished">Erhöhung der Transaktionsgebühr fehlgeschlagen</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">Möchten Sie die Gebühr erhöhen?</translation> - </message> - <message> - <source>Current fee:</source> - <translation type="unfinished">Aktuelle Gebühr:</translation> - </message> - <message> - <source>Increase:</source> - <translation type="unfinished">Erhöhung:</translation> - </message> - <message> - <source>New fee:</source> - <translation type="unfinished">Neue Gebühr:</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">Warnung: Hierdurch kann die zusätzliche Gebühr durch Verkleinerung von Wechselgeld Outputs oder nötigenfalls durch Hinzunahme weitere Inputs beglichen werden. Ein neuer Wechselgeld Output kann dabei entstehen, falls noch keiner existiert. Diese Änderungen können möglicherweise private Daten preisgeben.</translation> - </message> - <message> - <source>Confirm fee bump</source> - <translation type="unfinished">Gebührenerhöhung bestätigen</translation> - </message> - <message> - <source>Can't draft transaction.</source> - <translation type="unfinished">Kann Transaktion nicht entwerfen.</translation> - </message> - <message> - <source>PSBT copied</source> - <translation type="unfinished">PSBT kopiert</translation> - </message> - <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">In die Zwischenablage kopiert </translation> - </message> - <message> - <source>Can't sign transaction.</source> - <translation type="unfinished">Signierung der Transaktion fehlgeschlagen.</translation> - </message> - <message> - <source>Could not commit transaction</source> - <translation type="unfinished">Konnte Transaktion nicht übergeben</translation> - </message> - <message> - <source>Can't display address</source> - <translation type="unfinished">Die Adresse kann nicht angezeigt werden</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</translation> - </message> -</context> -<context> - <name>WalletView</name> - <message> - <source>&Export</source> - <translation type="unfinished">&Exportieren</translation> - </message> - <message> - <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Daten der aktuellen Ansicht in eine Datei exportieren</translation> - </message> - <message> - <source>Backup Wallet</source> - <translation type="unfinished">Wallet sichern</translation> - </message> - <message> - <source>Wallet Data</source> - <extracomment>Name of the wallet data file format.</extracomment> - <translation type="unfinished">Wallet-Daten</translation> - </message> - <message> - <source>Backup Failed</source> - <translation type="unfinished">Sicherung fehlgeschlagen</translation> - </message> - <message> - <source>There was an error trying to save the wallet data to %1.</source> - <translation type="unfinished">Beim Speichern der Wallet-Daten nach %1 ist ein Fehler aufgetreten.</translation> - </message> - <message> - <source>Backup Successful</source> - <translation type="unfinished">Sicherung erfolgreich</translation> - </message> - <message> - <source>The wallet data was successfully saved to %1.</source> - <translation type="unfinished">Speichern der Wallet-Daten nach %1 war erfolgreich.</translation> - </message> - <message> - <source>Cancel</source> - <translation type="unfinished">Abbrechen</translation> - </message> -</context> -<context> - <name>bitcoin-core</name> - <message> - <source>The %s developers</source> - <translation type="unfinished">Die %s-Entwickler</translation> - </message> - <message> - <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> - <translation type="unfinished">%s korrupt. Versuche mit dem Wallet-Werkzeug bitcoin-wallet zu retten, oder eine Sicherung wiederherzustellen.</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 konnte den -assumeutxo-Snapshot-Status nicht validieren. Dies deutet auf ein Hardwareproblem, einen Fehler in der Software oder eine fehlerhafte Softwareänderung hin, die das Laden eines ungültigen Schnappschusses ermöglichte. Infolgedessen wird der Knoten heruntergefahren und verwendet keinen Zustand mehr, der auf dem Snapshot aufgebaut wurde, wodurch die Chain Height von %d auf %d zurückgesetzt wird. Beim nächsten Neustart nimmt der Knoten die Synchronisierung ab %d ohne Verwendung von Snapshot-Daten wieder auf. Bitte melden Sie diesen Vorfall an %s und geben Sie an, wie Sie den Snapshot erhalten haben. Der ungültige Snapshot-Chainstatus wird auf der Festplatte belassen, falls er bei der Diagnose des Problems, das diesen Fehler verursacht hat, hilfreich ist.</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 Aufforderung, auf Port %u zu lauschen. Dieser Port wird als "schlecht" eingeschätzt und es ist daher unwahrscheinlich, dass sich Bitcoin Core Gegenstellen mit ihm verbinden. Siehe doc/p2p-bad-ports.md für Details und eine vollständige Liste.</translation> - </message> - <message> - <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> - <translation type="unfinished">Kann Wallet Version nicht von Version %i auf Version %i abstufen. Wallet Version bleibt unverändert.</translation> - </message> - <message> - <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">Datenverzeichnis %s kann nicht gesperrt werden. Evtl. wurde %s bereits gestartet.</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">Kann ein aufgespaltenes nicht-HD Wallet nicht von Version %i auf Version %i aktualisieren, ohne auf Unterstützung von Keypools vor der Aufspaltung zu aktualisieren. Bitte benutze Version%i oder keine bestimmte Version.</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">Der Speicherplatz für %s reicht möglicherweise nicht für die Block-Dateien aus. In diesem Verzeichnis werden ca. %u GB an Daten gespeichert.</translation> - </message> - <message> - <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> - <translation type="unfinished">Veröffentlicht unter der MIT-Softwarelizenz, siehe beiliegende Datei %s oder %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">Fehler beim Laden der Wallet. Wallet erfordert das Herunterladen von Blöcken, und die Software unterstützt derzeit nicht das Laden von Wallets, während Blöcke außer der Reihe heruntergeladen werden, wenn assumeutxo-Snapshots verwendet werden. Die Wallet sollte erfolgreich geladen werden können, nachdem die Node-Synchronisation die Höhe %s erreicht hat.</translation> - </message> - <message> - <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source> - <translation type="unfinished">Fehler beim Lesen von %s! Transaktionsdaten fehlen oder sind nicht korrekt. Wallet wird erneut gescannt.</translation> - </message> - <message> - <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> - <translation type="unfinished">Fehler: Dumpdatei Format Eintrag ist Ungültig. Habe "%s" bekommen, aber "format" erwartet.</translation> - </message> - <message> - <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">Fehler: Dumpdatei Identifikationseintrag ist ungültig. Habe "%s" bekommen, aber "%s" erwartet.</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">Fehler: Die Version der Speicherauszugsdatei ist %s und wird nicht unterstützt. Diese Version von bitcoin-wallet unterstützt nur Speicherauszugsdateien der Version 1.</translation> - </message> - <message> - <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> - <translation type="unfinished">Fehler: Legacy Wallets unterstützen nur die Adresstypen "legacy", "p2sh-segwit" und "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">Fehler: Es können keine Deskriptoren für diese Legacy-Wallet erstellt werden. Stellen Sie sicher, dass Sie die Passphrase der Wallet angeben, wenn diese verschlüsselt ist.</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">Datei %s existiert bereits. Wenn Sie das wirklich tun wollen, dann bewegen Sie zuvor die existierende Datei woanders hin.</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">Ungültige oder beschädigte peers.dat (%s). Wenn Sie glauben, dass dies ein Programmierfehler ist, melden Sie ihn bitte an %s. Zur Abhilfe können Sie die Datei (%s) aus dem Weg räumen (umbenennen, verschieben oder löschen), so dass beim nächsten Start eine neue Datei erstellt wird.</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">Mehr als eine Onion-Bindungsadresse angegeben. Verwende %s für den automatisch erstellten Tor-Onion-Dienst.</translation> - </message> - <message> - <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> - <translation type="unfinished">Keine Dumpdatei angegeben. Um createfromdump zu benutzen, muss -dumpfile=<filename> angegeben werden.</translation> - </message> - <message> - <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> - <translation type="unfinished">Keine Dumpdatei angegeben. Um dump verwenden zu können, muss -dumpfile=<filename> angegeben werden.</translation> - </message> - <message> - <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> - <translation type="unfinished">Kein Format der Wallet-Datei angegeben. Um createfromdump zu nutzen, muss -format=<format> angegeben werden.</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">Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da %s ansonsten nicht ordnungsgemäß funktionieren wird.</translation> - </message> - <message> - <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> - <translation type="unfinished">Wenn sie %s nützlich finden, sind Helfer sehr gern gesehen. Besuchen Sie %s um mehr über das Softwareprojekt zu erfahren.</translation> - </message> - <message> - <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> - <translation type="unfinished">Prune-Modus wurde kleiner als das Minimum in Höhe von %d MiB konfiguriert. Bitte verwenden Sie einen größeren Wert.</translation> - </message> - <message> - <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> - <translation type="unfinished">Der Prune-Modus ist mit -reindex-chainstate nicht kompatibel. Verwende stattdessen den vollen -reindex.</translation> - </message> - <message> - <source>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source> - <translation type="unfinished">Prune (Kürzung): Die letzte Synchronisation der Wallet liegt vor gekürzten (gelöschten) Blöcken. Es ist ein -reindex (erneuter Download der gesamten Blockchain im Fall eines gekürzten Nodes) notwendig.</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">Umbenennung von '%s' -> '%s' fehlgeschlagen. Sie sollten dieses Problem beheben, indem Sie das ungültige Snapshot-Verzeichnis %s manuell verschieben oder löschen, andernfalls wird der gleiche Fehler beim nächsten Start erneut auftreten.</translation> - </message> - <message> - <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> - <translation type="unfinished">SQLite-Datenbank: Unbekannte SQLite-Wallet-Schema-Version %d. Nur Version %d wird unterstützt.</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">Die Block-Datenbank enthält einen Block, der scheinbar aus der Zukunft kommt. Dies kann daran liegen, dass die Systemzeit Ihres Computers falsch eingestellt ist. Stellen Sie die Block-Datenbank erst dann wieder her, wenn Sie sich sicher sind, dass Ihre Systemzeit korrekt eingestellt ist.</translation> - </message> - <message> - <source>The transaction amount is too small to send after the fee has been deducted</source> - <translation type="unfinished">Der Transaktionsbetrag ist zu klein, um ihn nach Abzug der Gebühr zu senden.</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">Dieser Fehler kann auftreten, wenn diese Wallet nicht ordnungsgemäß heruntergefahren und zuletzt mithilfe eines Builds mit einer neueren Version von Berkeley DB geladen wurde. Verwenden Sie in diesem Fall die Software, die diese Wallet zuletzt geladen hat</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">Dies ist eine Vorab-Testversion - Verwendung auf eigene Gefahr - nicht für Mining- oder Handelsanwendungen nutzen!</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">Dies ist die maximale Transaktionsgebühr, die Sie (zusätzlich zur normalen Gebühr) zahlen, um die Vermeidung von teilweisen Ausgaben gegenüber der regulären Münzauswahl zu priorisieren.</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">Dies ist die Transaktionsgebühr, die ggf. abgeschrieben wird, wenn das Wechselgeld "Staub" ist in dieser Stufe.</translation> - </message> - <message> - <source>This is the transaction fee you may pay when fee estimates are not available.</source> - <translation type="unfinished">Das ist die Transaktionsgebühr, welche Sie zahlen müssten, wenn die Gebührenschätzungen nicht verfügbar sind.</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">Gesamtlänge des Netzwerkversionstrings (%i) erreicht die maximale Länge (%i). Reduzieren Sie Anzahl oder Größe von uacomments.</translation> - </message> - <message> - <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> - <translation type="unfinished">Fehler beim Verarbeiten von Blöcken. Sie müssen die Datenbank mit Hilfe des Arguments '-reindex-chainstate' neu aufbauen.</translation> - </message> - <message> - <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> - <translation type="unfinished">Angegebenes Format "%s" der Wallet-Datei ist unbekannt. -Bitte nutzen Sie entweder "bdb" oder "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">Nicht unterstützte kategoriespezifische Protokollierungsebene %1$s=%2$s. Erwartet %1$s=<category>:<loglevel>. Gültige Kategorien: %3$s. Gültige Loglevels: %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">Nicht unterstütztes Chainstate-Datenbankformat gefunden. Bitte starte mit -reindex-chainstate neu. Dadurch wird die Chainstate-Datenbank neu erstellt.</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">Wallet erfolgreich erstellt. Der Legacy-Wallet-Typ ist veraltet und die Unterstützung für das Erstellen und Öffnen von Legacy-Wallets wird in Zukunft entfernt.</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">Wallet erfolgreich geladen. Der Legacy-Wallet-Typ ist veraltet und die Unterstützung für das Erstellen und Öffnen von Legacy-Wallets wird in Zukunft entfernt. Legacy-Wallets können mit migratewallet auf eine Deskriptor-Wallet migriert werden.</translation> - </message> - <message> - <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> - <translation type="unfinished">Warnung: Dumpdatei Wallet Format "%s" passt nicht zum auf der Kommandozeile angegebenen Format "%s".</translation> - </message> - <message> - <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> - <translation type="unfinished">Warnung: Es wurden private Schlüssel in der Wallet {%s} entdeckt, welche private Schlüssel jedoch deaktiviert hat.</translation> - </message> - <message> - <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> - <translation type="unfinished">Warnung: Wir scheinen nicht vollständig mit unseren Gegenstellen übereinzustimmen! Sie oder die anderen Knoten müssen unter Umständen Ihre Client-Software aktualisieren.</translation> - </message> - <message> - <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> - <translation type="unfinished">Zeugnisdaten für Blöcke nach Höhe %d müssen validiert werden. Bitte mit -reindex neu starten.</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">Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um zum ungekürzten Modus zurückzukehren. Dies erfordert, dass die gesamte Blockchain erneut heruntergeladen wird.</translation> - </message> - <message> - <source>-maxmempool must be at least %d MB</source> - <translation type="unfinished">-maxmempool muss mindestens %d MB betragen</translation> - </message> - <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ein fataler interner Fehler ist aufgetreten, siehe debug.log für Details</translation> - </message> - <message> - <source>Cannot resolve -%s address: '%s'</source> - <translation type="unfinished">Kann Adresse in -%s nicht auflösen: '%s'</translation> - </message> - <message> - <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> - <translation type="unfinished">Kann -forcednsseed nicht auf true setzen, wenn -dnsseed auf false gesetzt ist.</translation> - </message> - <message> - <source>Cannot set -peerblockfilters without -blockfilterindex.</source> - <translation type="unfinished">Kann -peerblockfilters nicht ohne -blockfilterindex setzen.</translation> - </message> - <message> - <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">Es konnte nicht in das Datenverzeichnis '%s' geschrieben werden; Überprüfen Sie die Berechtigungen.</translation> - </message> - <message> - <source>%s is set very high! Fees this large could be paid on a single transaction.</source> - <translation type="unfinished">%s ist sehr hoch gesetzt! Gebühren dieser Höhe könnten für eine einzelne Transaktion gezahlt werden.</translation> - </message> - <message> - <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> - <translation type="unfinished">Es ist nicht möglich, bestimmte Verbindungen anzubieten und gleichzeitig addrman ausgehende Verbindungen finden zu lassen.</translation> - </message> - <message> - <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source> - <translation type="unfinished">Fehler beim Laden von %s: Externe Unterzeichner-Brieftasche wird geladen, ohne dass die Unterstützung für externe Unterzeichner kompiliert wurde</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">Fehler beim Lesen von %s! Alle Schlüssel wurden korrekt gelesen, aber Transaktionsdaten oder Adressmetadaten fehlen oder sind falsch.</translation> - </message> - <message> - <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> - <translation type="unfinished">Fehler: Adressbuchdaten im Wallet können nicht als zum migrierten Wallet gehörend identifiziert werden</translation> - </message> - <message> - <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source> - <translation type="unfinished">Fehler: Doppelte Deskriptoren, die während der Migration erstellt wurden. Diese Wallet ist möglicherweise beschädigt.</translation> - </message> - <message> - <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source> - <translation type="unfinished">Fehler: Transaktion in\m Wallet %s kann nicht als zu migrierten Wallet gehörend identifiziert werden</translation> - </message> - <message> - <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> - <translation type="unfinished">Es war nicht möglich, die Bump-Gebühren zu berechnen, da unbestätigte UTXOs von einem enormen Cluster unbestätigter Transaktionen abhängen.</translation> - </message> - <message> - <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> - <translation type="unfinished">Kann ungültige Datei peers.dat nicht umbenennen. Bitte Verschieben oder Löschen und noch einmal versuchen.</translation> - </message> - <message> - <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> - <translation type="unfinished">Gebührenschätzung fehlgeschlagen. Fallbackgebühr ist deaktiviert. Warten Sie ein paar Blöcke oder aktivieren Sie %s.</translation> - </message> - <message> - <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> - <translation type="unfinished">Inkompatible Optionen: -dnsseed=1 wurde explizit angegeben, aber -onlynet verbietet Verbindungen zu 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">Ungültiger Betrag für %s=<amount>: '%s' (muss mindestens die MinRelay-Gebühr von %s betragen, um festhängende Transaktionen zu verhindern)</translation> - </message> - <message> - <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> - <translation type="unfinished">Ausgehende Verbindungen sind auf CJDNS beschränkt (-onlynet=cjdns), aber -cjdnsreachable ist nicht angegeben</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">Ausgehende Verbindungen sind eingeschränkt auf Tor (-onlynet=onion), aber der Proxy, um das Tor-Netzwerk zu erreichen ist nicht vorhanden (no -proxy= and no -onion= given) oder ausdrücklich verboten (-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">Ausgehende Verbindungen sind eingeschränkt auf Tor (-onlynet=onion), aber der Proxy, um das Tor-Netzwerk zu erreichen ist nicht vorhanden. Kein -proxy, -onion oder -listenonion ist angegeben.</translation> - </message> - <message> - <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source> - <translation type="unfinished">Ausgehende Verbindungen sind auf i2p (-onlynet=i2p) beschränkt, aber -i2psam ist nicht angegeben</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">Die Größe der Inputs übersteigt das maximale Gewicht. Bitte versuchen Sie, einen kleineren Betrag zu senden oder die UTXOs Ihrer Wallet manuell zu konsolidieren.</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">Die vorgewählte Gesamtsumme der Coins deckt das Transaktionsziel nicht ab. Bitte erlauben Sie, dass andere Eingaben automatisch ausgewählt werden, oder fügen Sie manuell mehr Coins hinzu</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">Die Transaktion erfordert ein Ziel mit einem Wert ungleich 0, eine Gebühr ungleich 0 oder eine vorausgewählte Eingabe</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">UTXO-Snapshot konnte nicht validiert werden. Starten Sie neu, um den normalen anfänglichen Block-Download fortzusetzen, oder versuchen Sie, einen anderen Snapshot zu laden.</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">Unbestätigte UTXOs sind verfügbar, aber deren Ausgabe erzeugt eine Kette von Transaktionen, die vom Mempool abgelehnt werden</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">Unerwarteter Legacy-Eintrag in Deskriptor-Wallet gefunden. Lade Wallet %s - -Die Wallet könnte manipuliert oder in böser Absicht erstellt worden sein. -</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">Nicht erkannter Deskriptor gefunden. Beim Laden vom Wallet %s - -Die Wallet wurde möglicherweise in einer neueren Version erstellt. -Bitte mit der neuesten Softwareversion versuchen. -</translation> - </message> - <message> - <source> -Unable to cleanup failed migration</source> - <translation type="unfinished"> -Fehlgeschlagene Migration kann nicht bereinigt werden</translation> - </message> - <message> - <source> -Unable to restore backup of wallet.</source> - <translation type="unfinished"> -Die Sicherung der Wallet kann nicht wiederhergestellt werden.</translation> - </message> - <message> - <source>Block verification was interrupted</source> - <translation type="unfinished">Blocküberprüfung wurde unterbrochen</translation> - </message> - <message> - <source>Config setting for %s only applied on %s network when in [%s] section.</source> - <translation type="unfinished">Konfigurationseinstellungen für %s sind nur auf %s network gültig, wenn in Sektion [%s]</translation> - </message> - <message> - <source>Corrupted block database detected</source> - <translation type="unfinished">Beschädigte Blockdatenbank erkannt</translation> - </message> - <message> - <source>Could not find asmap file %s</source> - <translation type="unfinished">Konnte die asmap Datei %s nicht finden</translation> - </message> - <message> - <source>Could not parse asmap file %s</source> - <translation type="unfinished">Konnte die asmap Datei %s nicht analysieren</translation> - </message> - <message> - <source>Disk space is too low!</source> - <translation type="unfinished">Freier Plattenspeicher zu gering!</translation> - </message> - <message> - <source>Do you want to rebuild the block database now?</source> - <translation type="unfinished">Möchten Sie die Blockdatenbank jetzt neu aufbauen?</translation> - </message> - <message> - <source>Done loading</source> - <translation type="unfinished">Laden abgeschlossen</translation> - </message> - <message> - <source>Dump file %s does not exist.</source> - <translation type="unfinished">Speicherauszugsdatei %sexistiert nicht.</translation> - </message> - <message> - <source>Error committing db txn for wallet transactions removal</source> - <translation type="unfinished">Fehler beim Bestätigen der Datenbanktransaktion für die Entfernung der Wallet-transaktionen.</translation> - </message> - <message> - <source>Error creating %s</source> - <translation type="unfinished">Error beim Erstellen von %s</translation> - </message> - <message> - <source>Error initializing block database</source> - <translation type="unfinished">Fehler beim Initialisieren der Blockdatenbank</translation> - </message> - <message> - <source>Error initializing wallet database environment %s!</source> - <translation type="unfinished">Fehler beim Initialisieren der Wallet-Datenbankumgebung %s!</translation> - </message> - <message> - <source>Error loading %s</source> - <translation type="unfinished">Fehler beim Laden von %s</translation> - </message> - <message> - <source>Error loading %s: Private keys can only be disabled during creation</source> - <translation type="unfinished">Fehler beim Laden von %s: Private Schlüssel können nur bei der Erstellung deaktiviert werden</translation> - </message> - <message> - <source>Error loading %s: Wallet corrupted</source> - <translation type="unfinished">Fehler beim Laden von %s: Das Wallet ist beschädigt</translation> - </message> - <message> - <source>Error loading %s: Wallet requires newer version of %s</source> - <translation type="unfinished">Fehler beim Laden von %s: Das Wallet benötigt eine neuere Version von %s</translation> - </message> - <message> - <source>Error loading block database</source> - <translation type="unfinished">Fehler beim Laden der Blockdatenbank</translation> - </message> - <message> - <source>Error opening block database</source> - <translation type="unfinished">Fehler beim Öffnen der Blockdatenbank</translation> - </message> - <message> - <source>Error reading configuration file: %s</source> - <translation type="unfinished">Fehler beim Lesen der Konfigurationsdatei: %s</translation> - </message> - <message> - <source>Error reading from database, shutting down.</source> - <translation type="unfinished">Fehler beim Lesen der Datenbank, Ausführung wird beendet.</translation> - </message> - <message> - <source>Error reading next record from wallet database</source> - <translation type="unfinished">Fehler beim Lesen des nächsten Eintrags aus der Wallet Datenbank</translation> - </message> - <message> - <source>Error starting db txn for wallet transactions removal</source> - <translation type="unfinished">Fehler beim Starten der Datenbanktransaktion für die Entfernung der Wallet-Transaktionen.</translation> - </message> - <message> - <source>Error: Cannot extract destination from the generated scriptpubkey</source> - <translation type="unfinished">Fehler: Das Ziel kann nicht aus dem generierten scriptpubkey extrahiert werden</translation> - </message> - <message> - <source>Error: Couldn't create cursor into database</source> - <translation type="unfinished">Fehler: Konnte den Cursor in der Datenbank nicht erzeugen</translation> - </message> - <message> - <source>Error: Disk space is low for %s</source> - <translation type="unfinished">Fehler: Zu wenig Speicherplatz auf der Festplatte %s</translation> - </message> - <message> - <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> - <translation type="unfinished">Fehler: Prüfsumme der Speicherauszugsdatei stimmt nicht überein. -Berechnet: %s, erwartet: %s</translation> - </message> - <message> - <source>Error: Failed to create new watchonly wallet</source> - <translation type="unfinished">Fehler: Fehler beim Erstellen einer neuen watchonly Wallet</translation> - </message> - <message> - <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">Fehler: Schlüssel ist kein Hex: %s</translation> - </message> - <message> - <source>Error: Got value that was not hex: %s</source> - <translation type="unfinished">Fehler: Wert ist kein Hex: %s</translation> - </message> - <message> - <source>Error: Keypool ran out, please call keypoolrefill first</source> - <translation type="unfinished">Fehler: Schlüsselspeicher ausgeschöpft, bitte zunächst keypoolrefill ausführen</translation> - </message> - <message> - <source>Error: Missing checksum</source> - <translation type="unfinished">Fehler: Fehlende Prüfsumme</translation> - </message> - <message> - <source>Error: No %s addresses available.</source> - <translation type="unfinished">Fehler: Keine %s Adressen verfügbar..</translation> - </message> - <message> - <source>Error: This wallet already uses SQLite</source> - <translation type="unfinished">Fehler: Diese Wallet verwendet bereits SQLite</translation> - </message> - <message> - <source>Error: This wallet is already a descriptor wallet</source> - <translation type="unfinished">Fehler: Diese Wallet ist bereits eine Deskriptor-Brieftasche</translation> - </message> - <message> - <source>Error: Unable to begin reading all records in the database</source> - <translation type="unfinished">Fehler: Lesen aller Datensätze in der Datenbank nicht möglich</translation> - </message> - <message> - <source>Error: Unable to make a backup of your wallet</source> - <translation type="unfinished">Fehler: Kann neuen Eintrag nicht in Wallet schreiben</translation> - </message> - <message> - <source>Error: Unable to parse version %u as a uint32_t</source> - <translation type="unfinished">Fehler: Kann Version %u nicht als uint32_t lesen.</translation> - </message> - <message> - <source>Error: Unable to read all records in the database</source> - <translation type="unfinished">Fehler: Alle Datensätze in der Datenbank können nicht gelesen werden</translation> - </message> - <message> - <source>Error: Unable to read wallet's best block locator record</source> - <translation type="unfinished">Fehler: Konnte Wallet Eintrag für Ort des besten Blocks nicht lesen.</translation> - </message> - <message> - <source>Error: Unable to remove watchonly address book data</source> - <translation type="unfinished">Fehler: Watchonly-Adressbuchdaten können nicht entfernt werden</translation> - </message> - <message> - <source>Error: Unable to write record to new wallet</source> - <translation type="unfinished">Fehler: Kann neuen Eintrag nicht in Wallet schreiben</translation> - </message> - <message> - <source>Error: Unable to write solvable wallet best block locator record</source> - <translation type="unfinished">Fehler: Konnte Wallet Eintrag für Ort des besten Blocks nicht schreiben.</translation> - </message> - <message> - <source>Error: Unable to write watchonly wallet best block locator record</source> - <translation type="unfinished">Fehler: Konnte Nur-beobachten-Wallet Eintrag für Ort des besten Blocks nicht schreiben.</translation> - </message> - <message> - <source>Error: address book copy failed for wallet %s</source> - <translation type="unfinished">Fehler: Adressbuchkopie für Wallet %s fehlgeschlagen</translation> - </message> - <message> - <source>Error: database transaction cannot be executed for wallet %s</source> - <translation type="unfinished">Fehler: Datenbank-Transaktion kann für Wallet %s nicht ausgeführt werden.</translation> - </message> - <message> - <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation type="unfinished">Fehler: Es konnte kein Port abgehört werden. Wenn dies so gewünscht wird -listen=0 verwenden.</translation> - </message> - <message> - <source>Failed to rescan the wallet during initialization</source> - <translation type="unfinished">Fehler: Wallet konnte während der Initialisierung nicht erneut gescannt werden.</translation> - </message> - <message> - <source>Failed to start indexes, shutting down..</source> - <translation type="unfinished">Start der Indizes fehlgeschlagen, wird beendet..</translation> - </message> - <message> - <source>Failed to verify database</source> - <translation type="unfinished">Verifizierung der Datenbank fehlgeschlagen</translation> - </message> - <message> - <source>Failure removing transaction: %s</source> - <translation type="unfinished">Fehler beim Entfernen der Transaktion: %s</translation> - </message> - <message> - <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> - <translation type="unfinished">Der Gebührensatz (%s) ist niedriger als die Mindestgebührensatz (%s) Einstellung.</translation> - </message> - <message> - <source>Ignoring duplicate -wallet %s.</source> - <translation type="unfinished">Ignoriere doppeltes -wallet %s.</translation> - </message> - <message> - <source>Importing…</source> - <translation type="unfinished">Importiere...</translation> - </message> - <message> - <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished">Fehlerhafter oder kein Genesis-Block gefunden. Falsches Datenverzeichnis für das Netzwerk?</translation> - </message> - <message> - <source>Initialization sanity check failed. %s is shutting down.</source> - <translation type="unfinished">Initialisierungsplausibilitätsprüfung fehlgeschlagen. %s wird beendet.</translation> - </message> - <message> - <source>Input not found or already spent</source> - <translation type="unfinished">Eingabe nicht gefunden oder bereits ausgegeben</translation> - </message> - <message> - <source>Insufficient dbcache for block verification</source> - <translation type="unfinished">Unzureichender dbcache für die Blocküberprüfung</translation> - </message> - <message> - <source>Insufficient funds</source> - <translation type="unfinished">Unzureichender Kontostand</translation> - </message> - <message> - <source>Invalid -i2psam address or hostname: '%s'</source> - <translation type="unfinished">Ungültige -i2psam Adresse oder Hostname: '%s'</translation> - </message> - <message> - <source>Invalid -onion address or hostname: '%s'</source> - <translation type="unfinished">Ungültige Onion-Adresse oder ungültiger Hostname: '%s'</translation> - </message> - <message> - <source>Invalid -proxy address or hostname: '%s'</source> - <translation type="unfinished">Ungültige Proxy-Adresse oder ungültiger Hostname: '%s'</translation> - </message> - <message> - <source>Invalid P2P permission: '%s'</source> - <translation type="unfinished">Ungültige P2P Genehmigung: '%s'</translation> - </message> - <message> - <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> - <translation type="unfinished">Ungültiger Betrag für %s=<amount>: '%s' (muss mindestens %ssein)</translation> - </message> - <message> - <source>Invalid amount for %s=<amount>: '%s'</source> - <translation type="unfinished">Ungültiger Betrag für %s=<amount>: '%s'</translation> - </message> - <message> - <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation type="unfinished">Ungültiger Betrag für -%s=<amount>: '%s'</translation> - </message> - <message> - <source>Invalid netmask specified in -whitelist: '%s'</source> - <translation type="unfinished">Ungültige Netzmaske angegeben in -whitelist: '%s'</translation> - </message> - <message> - <source>Invalid port specified in %s: '%s'</source> - <translation type="unfinished">Ungültiger Port angegeben in %s: '%s'</translation> - </message> - <message> - <source>Invalid pre-selected input %s</source> - <translation type="unfinished">Ungültige vorausgewählte Eingabe %s</translation> - </message> - <message> - <source>Listening for incoming connections failed (listen returned error %s)</source> - <translation type="unfinished">Das Abhören für eingehende Verbindungen ist fehlgeschlagen (Das Abhören hat Fehler %s zurückgegeben)</translation> - </message> - <message> - <source>Loading P2P addresses…</source> - <translation type="unfinished">Lade P2P-Adressen...</translation> - </message> - <message> - <source>Loading banlist…</source> - <translation type="unfinished">Lade Bannliste…</translation> - </message> - <message> - <source>Loading block index…</source> - <translation type="unfinished">Lade Block-Index...</translation> - </message> - <message> - <source>Loading wallet…</source> - <translation type="unfinished">Lade Wallet...</translation> - </message> - <message> - <source>Missing amount</source> - <translation type="unfinished">Fehlender Betrag</translation> - </message> - <message> - <source>Missing solving data for estimating transaction size</source> - <translation type="unfinished">Fehlende Auflösungsdaten zur Schätzung der Transaktionsgröße</translation> - </message> - <message> - <source>Need to specify a port with -whitebind: '%s'</source> - <translation type="unfinished">Angabe eines Ports benötigt für -whitebind: '%s'</translation> - </message> - <message> - <source>No addresses available</source> - <translation type="unfinished">Keine Adressen verfügbar</translation> - </message> - <message> - <source>Not enough file descriptors available.</source> - <translation type="unfinished">Nicht genügend Datei-Deskriptoren verfügbar.</translation> - </message> - <message> - <source>Not found pre-selected input %s</source> - <translation type="unfinished">Nicht gefundener vorausgewählter Input %s</translation> - </message> - <message> - <source>Not solvable pre-selected input %s</source> - <translation type="unfinished">Nicht auflösbare vorausgewählter Input %s</translation> - </message> - <message> - <source>Prune cannot be configured with a negative value.</source> - <translation type="unfinished">Kürzungsmodus kann nicht mit einem negativen Wert konfiguriert werden.</translation> - </message> - <message> - <source>Prune mode is incompatible with -txindex.</source> - <translation type="unfinished">Kürzungsmodus ist nicht mit -txindex kompatibel.</translation> - </message> - <message> - <source>Pruning blockstore…</source> - <translation type="unfinished">Kürze den Blockspeicher…</translation> - </message> - <message> - <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> - <translation type="unfinished">Reduziere -maxconnections von %d zu %d, aufgrund von Systemlimitierungen.</translation> - </message> - <message> - <source>Replaying blocks…</source> - <translation type="unfinished">Spiele alle Blocks erneut ein…</translation> - </message> - <message> - <source>Rescanning…</source> - <translation type="unfinished">Wiederhole Scan...</translation> - </message> - <message> - <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> - <translation type="unfinished">SQLite-Datenbank: Anweisung, die Datenbank zu verifizieren fehlgeschlagen: %s</translation> - </message> - <message> - <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> - <translation type="unfinished">SQLite-Datenbank: Anfertigung der Anweisung zum Verifizieren der Datenbank fehlgeschlagen: %s</translation> - </message> - <message> - <source>SQLiteDatabase: Failed to read database verification error: %s</source> - <translation type="unfinished">Datenbank konnte nicht gelesen werden -Verifikations-Error: %s</translation> - </message> - <message> - <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> - <translation type="unfinished">SQLiteDatabase: Unerwartete Anwendungs-ID. %u statt %u erhalten.</translation> - </message> - <message> - <source>Section [%s] is not recognized.</source> - <translation type="unfinished">Sektion [%s] ist nicht delegiert.</translation> - </message> - <message> - <source>Signing transaction failed</source> - <translation type="unfinished">Signierung der Transaktion fehlgeschlagen</translation> - </message> - <message> - <source>Specified -walletdir "%s" does not exist</source> - <translation type="unfinished">Angegebenes Verzeichnis "%s" existiert nicht</translation> - </message> - <message> - <source>Specified -walletdir "%s" is a relative path</source> - <translation type="unfinished">Angegebenes Verzeichnis "%s" ist ein relativer Pfad</translation> - </message> - <message> - <source>Specified -walletdir "%s" is not a directory</source> - <translation type="unfinished">Angegebenes Verzeichnis "%s" ist kein Verzeichnis</translation> - </message> - <message> - <source>Specified blocks directory "%s" does not exist.</source> - <translation type="unfinished">Angegebener Blöcke-Ordner "%s" existiert nicht.</translation> - </message> - <message> - <source>Specified data directory "%s" does not exist.</source> - <translation type="unfinished">Das angegebene Datenverzeichnis "%s" existiert nicht.</translation> - </message> - <message> - <source>Starting network threads…</source> - <translation type="unfinished">Starte Netzwerk-Threads...</translation> - </message> - <message> - <source>The source code is available from %s.</source> - <translation type="unfinished">Der Quellcode ist auf %s verfügbar.</translation> - </message> - <message> - <source>The specified config file %s does not exist</source> - <translation type="unfinished">Die angegebene Konfigurationsdatei %sexistiert nicht</translation> - </message> - <message> - <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">Der Transaktionsbetrag ist zu niedrig, um die Gebühr zu bezahlen.</translation> - </message> - <message> - <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation type="unfinished">Das Wallet verhindert Zahlungen, die die Mindesttransaktionsgebühr nicht berücksichtigen.</translation> - </message> - <message> - <source>This is experimental software.</source> - <translation type="unfinished">Dies ist experimentelle Software.</translation> - </message> - <message> - <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation type="unfinished">Dies ist die kleinstmögliche Gebühr, die beim Senden einer Transaktion fällig wird.</translation> - </message> - <message> - <source>This is the transaction fee you will pay if you send a transaction.</source> - <translation type="unfinished">Dies ist die Gebühr, die beim Senden einer Transaktion fällig wird.</translation> - </message> - <message> - <source>Transaction %s does not belong to this wallet</source> - <translation type="unfinished">Transaktion %s gehört nicht zu dieser Brieftasche</translation> - </message> - <message> - <source>Transaction amount too small</source> - <translation type="unfinished">Transaktionsbetrag zu niedrig</translation> - </message> - <message> - <source>Transaction amounts must not be negative</source> - <translation type="unfinished">Transaktionsbeträge dürfen nicht negativ sein.</translation> - </message> - <message> - <source>Transaction change output index out of range</source> - <translation type="unfinished">Ausgangsindex der Transaktionsänderung außerhalb des Bereichs</translation> - </message> - <message> - <source>Transaction must have at least one recipient</source> - <translation type="unfinished">Die Transaktion muss mindestens einen Empfänger enthalten.</translation> - </message> - <message> - <source>Transaction needs a change address, but we can't generate it.</source> - <translation type="unfinished">Für die Transaktion wird eine neue Adresse benötigt, aber wir können sie nicht generieren.</translation> - </message> - <message> - <source>Transaction too large</source> - <translation type="unfinished">Transaktion zu groß</translation> - </message> - <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Speicher kann für -maxsigcachesize: '%s' MiB nicht zugewiesen werden:</translation> - </message> - <message> - <source>Unable to bind to %s on this computer (bind returned error %s)</source> - <translation type="unfinished">Kann auf diesem Computer nicht an %s binden (bind meldete Fehler %s)</translation> - </message> - <message> - <source>Unable to bind to %s on this computer. %s is probably already running.</source> - <translation type="unfinished">Kann auf diesem Computer nicht an %s binden. Evtl. wurde %s bereits gestartet.</translation> - </message> - <message> - <source>Unable to create the PID file '%s': %s</source> - <translation type="unfinished">Erstellung der PID-Datei '%s': %s ist nicht möglich</translation> - </message> - <message> - <source>Unable to find UTXO for external input</source> - <translation type="unfinished">UTXO für externe Eingabe konnte nicht gefunden werden</translation> - </message> - <message> - <source>Unable to generate initial keys</source> - <translation type="unfinished">Initialschlüssel können nicht generiert werden</translation> - </message> - <message> - <source>Unable to generate keys</source> - <translation type="unfinished">Schlüssel können nicht generiert werden</translation> - </message> - <message> - <source>Unable to open %s for writing</source> - <translation type="unfinished">Unfähig %s zum Schreiben zu öffnen</translation> - </message> - <message> - <source>Unable to parse -maxuploadtarget: '%s'</source> - <translation type="unfinished">Kann -maxuploadtarget: '%s' nicht parsen</translation> - </message> - <message> - <source>Unable to start HTTP server. See debug log for details.</source> - <translation type="unfinished">Kann HTTP-Server nicht starten. Siehe Debug-Log für Details.</translation> - </message> - <message> - <source>Unable to unload the wallet before migrating</source> - <translation type="unfinished">Die Wallet kann vor der Migration nicht entladen werden</translation> - </message> - <message> - <source>Unknown -blockfilterindex value %s.</source> - <translation type="unfinished">Unbekannter -blockfilterindex Wert %s.</translation> - </message> - <message> - <source>Unknown address type '%s'</source> - <translation type="unfinished">Unbekannter Adresstyp '%s'</translation> - </message> - <message> - <source>Unknown change type '%s'</source> - <translation type="unfinished">Unbekannter Änderungstyp '%s'</translation> - </message> - <message> - <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">Unbekannter Netztyp in -onlynet angegeben: '%s'</translation> - </message> - <message> - <source>Unknown new rules activated (versionbit %i)</source> - <translation type="unfinished">Unbekannte neue Regeln aktiviert (Versionsbit %i)</translation> - </message> - <message> - <source>Unsupported global logging level %s=%s. Valid values: %s.</source> - <translation type="unfinished">Nicht unterstützte globale Protokollierungsebene %s=%s. Gültige Werte: %s.</translation> - </message> - <message> - <source>Wallet file creation failed: %s</source> - <translation type="unfinished">Wallet Datei konnte nicht angelegt werden: %s</translation> - </message> - <message> - <source>acceptstalefeeestimates is not supported on %s chain.</source> - <translation type="unfinished">acceptstalefeeestimates wird auf der %s Chain nicht unterstützt.</translation> - </message> - <message> - <source>Unsupported logging category %s=%s.</source> - <translation type="unfinished">Nicht unterstützte Protokollkategorie %s=%s.</translation> - </message> - <message> - <source>Error: Could not add watchonly tx %s to watchonly wallet</source> - <translation type="unfinished">Fehler: Konnte Nur-beobachten TX %s der Nur-beobachten-Wallet nicht hinzufügen.</translation> - </message> - <message> - <source>Error: Could not delete watchonly transactions. </source> - <translation type="unfinished">Fehler: Watchonly-Transaktionen konnten nicht gelöscht werden.</translation> - </message> - <message> - <source>User Agent comment (%s) contains unsafe characters.</source> - <translation type="unfinished">Der User Agent Kommentar (%s) enthält unsichere Zeichen.</translation> - </message> - <message> - <source>Verifying blocks…</source> - <translation type="unfinished">Überprüfe Blöcke...</translation> - </message> - <message> - <source>Verifying wallet(s)…</source> - <translation type="unfinished">Überprüfe Wallet(s)...</translation> - </message> - <message> - <source>Wallet needed to be rewritten: restart %s to complete</source> - <translation type="unfinished">Wallet musste neu geschrieben werden: starten Sie %s zur Fertigstellung neu</translation> - </message> - <message> - <source>Settings file could not be read</source> - <translation type="unfinished">Einstellungsdatei konnte nicht gelesen werden</translation> - </message> - <message> - <source>Settings file could not be written</source> - <translation type="unfinished">Einstellungsdatei kann nicht geschrieben werden</translation> - </message> -</context> + </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_de_CH.ts b/src/qt/locale/bitcoin_de_CH.ts index 2792a1bc98..ffbc761ac1 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> @@ -184,6 +184,10 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Geben Sie die alte und die neue Wallet-Passphrase ein.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Weiter</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">Beachten Sie, dass das Verschlüsseln Ihrer Wallet nicht komplett vor Diebstahl Ihrer Bitcoins durch Malware schützt, die Ihren Computer infiziert hat.</translation> </message> @@ -427,7 +431,11 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <numerusform>%n Jahre</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">Standard-Wallet</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -447,18 +455,110 @@ 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>Change the passphrase used for wallet encryption</source> + <translation type="unfinished">Ändert die Passphrase, die für die Wallet-Verschlüsselung benutzt wird</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> + <translation type="unfinished">&Optionen…</translation> + </message> + <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">Wallet &verschlüsseln…</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation type="unfinished">Verschlüsselt die zu Ihrer Wallet gehörenden privaten Schlüssel</translation> + </message> + <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">Wallet &sichern…</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">Passphrase &ändern…</translation> + </message> + <message> + <source>Sign &message…</source> + <translation type="unfinished">&Nachricht unterzeichnen…</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation type="unfinished">Nachrichten signieren, um den Besitz Ihrer Bitcoin-Adressen zu beweisen</translation> </message> <message> <source>&Verify message…</source> - <translation type="unfinished">Nachricht bestätigen </translation> + <translation type="unfinished">Nachricht &verifizieren…</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation type="unfinished">Nachrichten verifizieren, um sicherzustellen, dass diese mit den angegebenen Bitcoin-Adressen signiert wurden</translation> + </message> + <message> + <source>&Load PSBT from file…</source> + <translation type="unfinished">&Lade PSBT aus Datei…</translation> + </message> + <message> + <source>Open &URI…</source> + <translation type="unfinished">Öffne &URI…</translation> + </message> + <message> + <source>Close Wallet…</source> + <translation type="unfinished">Schließe Wallet…</translation> + </message> + <message> + <source>Create Wallet…</source> + <translation type="unfinished">Erstelle Wallet…</translation> + </message> + <message> + <source>Close All Wallets…</source> + <translation type="unfinished">Schließe alle Wallets…</translation> + </message> + <message> + <source>&File</source> + <translation type="unfinished">&Datei</translation> + </message> + <message> + <source>&Settings</source> + <translation type="unfinished">&Einstellungen</translation> </message> <message> <source>&Help</source> <translation type="unfinished">&Hilfe</translation> </message> <message> + <source>Tabs toolbar</source> + <translation type="unfinished">Registerkartenleiste</translation> + </message> + <message> + <source>Syncing Headers (%1%)…</source> + <translation type="unfinished">Synchronisiere Headers (%1%)…</translation> + </message> + <message> + <source>Synchronizing with network…</source> + <translation type="unfinished">Synchronisiere mit Netzwerk...</translation> + </message> + <message> + <source>Indexing blocks on disk…</source> + <translation type="unfinished">Indiziere Blöcke auf Datenträger...</translation> + </message> + <message> + <source>Processing blocks on disk…</source> + <translation type="unfinished">Verarbeite Blöcke auf Datenträger...</translation> + </message> + <message> <source>Connecting to peers…</source> <translation type="unfinished">Verbinde mit Peers...</translation> </message> @@ -522,6 +622,50 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">STRG+Q</translation> </message> <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation type="unfinished">Lade teilsignierte Bitcoin-Transaktion</translation> + </message> + <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Lade PSBT aus Zwischenablage…</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation type="unfinished">Lade teilsignierte Bitcoin-Transaktion aus Zwischenablage</translation> + </message> + <message> + <source>Node window</source> + <translation type="unfinished">Knotenfenster</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation type="unfinished">Öffne Knotenkonsole für Fehlersuche und Diagnose</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation type="unfinished">&Versandadressen</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation type="unfinished">&Empfangsadressen</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation type="unfinished">Öffne bitcoin: URI</translation> + </message> + <message> + <source>Open Wallet</source> + <translation type="unfinished">Wallet öffnen</translation> + </message> + <message> + <source>Open a wallet</source> + <translation type="unfinished">Eine Wallet öffnen</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Wallet schließen</translation> + </message> + <message> <source>Restore Wallet…</source> <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> <translation type="unfinished">Wallet wiederherstellen...</translation> @@ -556,10 +700,6 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Blende die Werte im Übersichtsreiter aus</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Keine Wallets verfügbar</translation> </message> @@ -616,7 +756,7 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> <numerusform>%n aktive Verbindung zum Bitcoin-Netzwerk</numerusform> - <numerusform>%n aktive Verbindung(en) zum Bitcoin-Netzwerk</numerusform> + <numerusform>%n aktive Verbindungen zum Bitcoin-Netzwerk</numerusform> </translation> </message> <message> @@ -640,6 +780,10 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Netzwerk Aktivität einschalten</translation> </message> <message> + <source>Pre-syncing Headers (%1%)…</source> + <translation type="unfinished">Synchronisiere Header (%1%)…</translation> + </message> + <message> <source>Error creating wallet</source> <translation type="unfinished">Fehler beim Erstellen der Wallet</translation> </message> @@ -960,10 +1104,6 @@ Während des Migrationsprozesses wird vor der Migration ein Backup der Wallet er <translation type="unfinished">Wallet öffnen Warnung</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</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">Öffne Wallet <b>%1</b>…</translation> @@ -2087,6 +2227,14 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">Anzahl der Verbindungen</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Lokale Adressen</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Netzwerk-Adressen, die dein Bitcoin-Node aktuell verwendet, um mit anderen Nodes zu kommunizieren.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Blockchain</translation> </message> @@ -2131,12 +2279,16 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">Gegenstelle auswählen, um detaillierte Informationen zu erhalten.</translation> </message> <message> - <source>The transport layer version: %1</source> - <translation type="unfinished">Die Transportschicht-Version: %1</translation> + <source>Hide Peers Detail</source> + <translation type="unfinished">Gegenstellen Reiter verstecken</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Die BIP324-Sitzungs-ID-Zeichenfolge in hexadezimaler Form, falls vorhanden.</translation> + <source>Ctrl+X</source> + <translation type="unfinished">Strg+X</translation> + </message> + <message> + <source>The transport layer version: %1</source> + <translation type="unfinished">Die Transportschicht-Version: %1</translation> </message> <message> <source>Whether we relay transactions to this peer.</source> @@ -2205,6 +2357,10 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">User-Agent</translation> </message> <message> + <source>Node window</source> + <translation type="unfinished">Knotenfenster</translation> + </message> + <message> <source>Current block height</source> <translation type="unfinished">Aktuelle Blockhöhe</translation> </message> @@ -2233,6 +2389,10 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">Richtung/Typ</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">Die BIP324-Sitzungs-ID-Zeichenfolge in hexadezimaler Form.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">Das Netzwerkprotokoll, über das diese Gegenstelle verbunden ist, ist: IPv4, IPv6, Onion, I2P oder CJDNS.</translation> </message> @@ -2445,6 +2605,10 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <translation type="unfinished">Netzwerkaktivität deaktiviert</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Keine</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Befehl wird ohne spezifizierte Wallet ausgeführt</translation> </message> @@ -3171,10 +3335,6 @@ Hinweis: Da die Gebühr auf Basis der Bytes berechnet wird, führt eine Gebühre <translation type="unfinished">Nachricht &signieren</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">Sie können Nachrichten/Vereinbarungen mit Hilfe Ihrer Adressen signieren, um zu beweisen, dass Sie Bitcoins empfangen können, die an diese Adressen überwiesen werden. Seien Sie vorsichtig und signieren Sie nichts Vages oder Willkürliches, um Ihre Indentität vor Phishingangriffen zu schützen. Signieren Sie nur vollständig-detaillierte Aussagen, mit denen Sie auch einverstanden sind.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Die Bitcoin-Adresse, mit der die Nachricht signiert wird</translation> </message> @@ -3259,10 +3419,6 @@ Hinweis: Da die Gebühr auf Basis der Bytes berechnet wird, führt eine Gebühre <translation type="unfinished">Bitte überprüfen Sie die Adresse und versuchen Sie es erneut.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Die eingegebene Adresse verweist nicht auf einen Schlüssel.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Wallet-Entsperrung wurde abgebrochen.</translation> </message> @@ -3828,11 +3984,6 @@ Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. <translation type="unfinished">PSBT kopiert</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">In die Zwischenablage kopiert </translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">Signierung der Transaktion fehlgeschlagen.</translation> </message> @@ -3844,10 +3995,6 @@ Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. <source>Can't display address</source> <translation type="unfinished">Die Adresse kann nicht angezeigt werden</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Standard-Wallet</translation> - </message> </context> <context> <name>WalletView</name> @@ -3980,10 +4127,6 @@ Gehen Sie zu Datei > Wallet Öffnen, um eine Wallet zu laden. <translation type="unfinished">Kein Format der Wallet-Datei angegeben. Um createfromdump zu nutzen, muss -format=<format> angegeben werden.</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">Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da %s ansonsten nicht ordnungsgemäß funktionieren wird.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Wenn sie %s nützlich finden, sind Helfer sehr gern gesehen. Besuchen Sie %s um mehr über das Softwareprojekt zu erfahren.</translation> </message> @@ -4093,10 +4236,6 @@ Bitte nutzen Sie entweder "bdb" oder "sqlite".</translation> <translation type="unfinished">-maxmempool muss mindestens %d MB betragen</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ein fataler interner Fehler ist aufgetreten, siehe debug.log für Details</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Kann Adresse in -%s nicht auflösen: '%s'</translation> </message> @@ -4215,7 +4354,8 @@ Please try running the latest software version. <translation type="unfinished">Nicht erkannter Deskriptor gefunden. Beim laden vom Wallet %s Die Wallet wurde möglicherweise in einer neueren Version erstellt. -Bitte mit der neuesten Softwareversion versuchen.</translation> +Bitte mit der neuesten Softwareversion versuchen. +</translation> </message> <message> <source> @@ -4230,6 +4370,10 @@ Unable to restore backup of wallet.</source> Die Sicherung der Wallet kann nicht wiederhergestellt werden.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind darf nur für eingehende Verbindungen verwendet werden ("out" wurde übergeben)</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">Blocküberprüfung wurde unterbrochen</translation> </message> @@ -4555,6 +4699,10 @@ Berechnet: %s, erwartet: %s</translation> <translation type="unfinished">Nicht auflösbare vorausgewählter Input %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Nur Richtung festgelegt, keine Genehmigungen: '%s'</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Kürzungsmodus kann nicht mit einem negativen Wert konfiguriert werden.</translation> </message> @@ -4684,10 +4832,6 @@ Verifikations-Error: %s</translation> <translation type="unfinished">Transaktion zu groß</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Speicher kann für -maxsigcachesize: '%s' MiB nicht zugewiesen werden:</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Kann auf diesem Computer nicht an %s binden (bind meldete Fehler %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_el.ts b/src/qt/locale/bitcoin_el.ts index 61d6807947..a73d0a0b5c 100644 --- a/src/qt/locale/bitcoin_el.ts +++ b/src/qt/locale/bitcoin_el.ts @@ -2,6 +2,10 @@ <context> <name>AddressBookPage</name> <message> + <source>Create a new address</source> + <translation type="unfinished">Δημιουργία νέας διεύθυνσης </translation> + </message> + <message> <source>&New</source> <translation type="unfinished">&Νέo</translation> </message> @@ -86,6 +90,10 @@ Signing is only possible with addresses of the type 'legacy'.</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,6 +176,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Εισαγάγετε τον παλιό και νέο κωδικό πρόσβασης σας για το πορτοφόλι.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Συνεχίστε</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Θυμίσου ότι το να κρυπτογραφείς το πορτοφόλι σου δεν μπορεί να προστατέψει πλήρως τα bitcoins σου από κλοπή από κακόβουλο λογισμικό που έχει μολύνει τον υπολογιστή σου</translation> </message> @@ -283,6 +295,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> @@ -389,7 +405,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n έτη</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">Προεπιλεγμένο πορτοφόλι</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -467,7 +487,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Αλλαγή της φράσης πρόσβασης για την κρυπτογράφηση του πορτοφολιού</translation> + <translation type="unfinished">Αλλαγή του κωδικού κρυπτογράφησης του πορτοφολιού</translation> </message> <message> <source>&Send</source> @@ -684,11 +704,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Migrate Wallet</source> - <translation type="unfinished">Μεταφορά Πορτοφολιού</translation> + <translation type="unfinished">Μετεγκατάσταση Πορτοφολιού</translation> </message> <message> <source>Migrate a wallet</source> - <translation type="unfinished">Μεταφορά ενός πορτοφολιού</translation> + <translation type="unfinished">Μετεγκατάσταση ενός πορτοφολιού</translation> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> @@ -703,10 +723,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -758,8 +774,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>1%n ενεργές συνδέσεις στο δίκτυο Bitcoin.</numerusform> - <numerusform>%n ενεργές συνδέσεις στο δίκτυο Bitcoin.</numerusform> + <numerusform>%n active connection(s) to Bitcoin network.</numerusform> + <numerusform>%n active connection(s) to Bitcoin network.</numerusform> </translation> </message> <message> @@ -1113,10 +1129,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -2235,6 +2247,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <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> @@ -2315,14 +2331,22 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Μεταφορά</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Η συμβολοσειρά αναγνωριστικού περιόδου σύνδεσης BIP324 σε δεκαεξαδική μορφή, εάν υπάρχει.</translation> + <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 +2371,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> @@ -2375,14 +2429,26 @@ If you are receiving this error you should request the merchant provide a BIP21 <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> @@ -2391,10 +2457,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 +2539,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> @@ -2502,6 +2625,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Η δραστηριότητα δικτύου είναι απενεργοποιημένη</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Κανένα</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Εκτέλεση εντολής χωρίς πορτοφόλι</translation> </message> @@ -2515,6 +2642,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 +2791,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,10 +3090,19 @@ 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> <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">Δημιουργεί μια συναλλαγή Bitcoin με μερική υπογραφή (PSBT) για χρήση με π.χ. ένα πορτοφόλι%1 εκτός σύνδεσης ή ένα πορτοφόλι υλικού συμβατό με το PSBT.</translation> + </message> + <message> <source>%1 to '%2'</source> <translation type="unfinished">%1 προς το '%2'</translation> </message> @@ -2951,6 +3124,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 +3165,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 +3188,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 +3240,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>Αναμένεται η έναρξη επιβεβαίωσης εντός %n μπλοκ.</numerusform> + <numerusform>Αναμένεται η έναρξη επιβεβαίωσης εντός %n μπλοκ.</numerusform> </translation> </message> <message> @@ -3107,6 +3304,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Το τέλος θα αφαιρεθεί από το ποσό που αποστέλλεται. Ο παραλήπτης θα λάβει λιγότερα bitcoins από ό,τι εισάγετε στο πεδίο ποσό. Εάν επιλεγούν πολλοί παραλήπτες, το έξοδο διαιρείται εξίσου.</translation> </message> <message> + <source>S&ubtract fee from amount</source> + <translation type="unfinished">Α&φερέστε το τέλος από το ποσό</translation> + </message> + <message> <source>Use available balance</source> <translation type="unfinished">Χρησιμοποιήστε το διαθέσιμο υπόλοιπο</translation> </message> @@ -3145,10 +3346,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">&Υπογραφή Μηνύματος</translation> </message> <message> - <source>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">Μπορείτε να υπογράψετε μηνύματα/συμφωνίες με τις διευθύνσεις σας για να αποδείξετε ότι μπορείτε να λάβετε τα bitcoins που τους αποστέλλονται. Προσέξτε να μην υπογράψετε τίποτα ασαφές ή τυχαίο, καθώς οι επιθέσεις ηλεκτρονικού "ψαρέματος" ενδέχεται να σας εξαπατήσουν να υπογράψετε την ταυτότητά σας σε αυτούς. Υπογράψτε μόνο πλήρως λεπτομερείς δηλώσεις που συμφωνείτε.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Διεύθυνση Bitcoin που θα σταλεί το μήνυμα</translation> </message> @@ -3233,10 +3430,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Ελέγξτε τη διεύθυνση και δοκιμάστε ξανά.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Η καταχωρημένη διεύθυνση δεν αναφέρεται σε ένα κλειδί.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Το ξεκλείδωμα του Πορτοφολιού ακυρώθηκε.</translation> </message> @@ -3357,8 +3550,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> @@ -3798,10 +3991,6 @@ Go to File > Open Wallet to load a wallet. <source>Can't display address</source> <translation type="unfinished">Αδυναμία προβολής διεύθυνσης</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Προεπιλεγμένο πορτοφόλι</translation> - </message> </context> <context> <name>WalletView</name> @@ -3890,10 +4079,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Δεν δόθηκε φορμά αρχείου πορτοφολιού. Για τη χρήση του createfromdump, πρέπει να δοθεί -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> - <translation type="unfinished">Ελέγξτε ότι η ημερομηνία και η ώρα του υπολογιστή σας είναι σωστές! Αν το ρολόι σας είναι λάθος, το %s δεν θα λειτουργήσει σωστά.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Παρακαλώ συμβάλλετε αν βρείτε %s χρήσιμο. Επισκεφθείτε το %s για περισσότερες πληροφορίες σχετικά με το λογισμικό.</translation> </message> @@ -3930,6 +4115,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Αυτό είναι το τέλος συναλλαγής που μπορείτε να πληρώσετε όταν δεν υπάρχουν εκτιμήσεις τελών.</translation> </message> <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation type="unfinished">Το συνολικό μήκος της συμβολοσειράς έκδοσης δικτύου (%i) υπερβαίνει το μέγιστο μήκος (%i). Μειώστε τον αριθμό ή το μέγεθος των προϊόντων.</translation> + </message> + <message> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> <translation type="unfinished">Δεν είναι δυνατή η επανάληψη των μπλοκ. Θα χρειαστεί να ξαναφτιάξετε τη βάση δεδομένων χρησιμοποιώντας το -reindex-chainstate.</translation> </message> @@ -3946,12 +4135,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Πρέπει να ξαναφτιάξετε τη βάση δεδομένων χρησιμοποιώντας το -reindex για να επιστρέψετε στη λειτουργία χωρίς εκτύπωση. Αυτό θα ξαναφορτώσει ολόκληρο το blockchain</translation> </message> <message> - <source>-maxmempool must be at least %d MB</source> - <translation type="unfinished">-maxmempool πρέπει να είναι τουλάχιστον %d MB</translation> + <source>%s is set very high!</source> + <translation type="unfinished">%s είναι πολύ υψηλή!</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Προέκυψε ένα κρίσιμο εσωτερικό σφάλμα. Ανατρέξτε στο debug.log για λεπτομέρειες</translation> + <source>-maxmempool must be at least %d MB</source> + <translation type="unfinished">-maxmempool πρέπει να είναι τουλάχιστον %d MB</translation> </message> <message> <source>Cannot resolve -%s address: '%s'</source> @@ -3959,7 +4148,19 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">Αδύνατη η εγγραφή στον κατάλογο δεδομένων '%s'. Ελέγξτε τα δικαιώματα.</translation> + <translation type="unfinished">Δεν είναι δυνατή η εγγραφή στον κατάλογο δεδομένων '%s'. ελέγξτε τα δικαιώματα.</translation> + </message> + <message> + <source>%s 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> @@ -4106,10 +4307,18 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Μη έγκυρη άδεια P2P: '%s'</translation> </message> <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation type="unfinished">Μη έγκυρο ποσό για -%s=<amount>: '%s'</translation> + </message> + <message> <source>Invalid netmask specified in -whitelist: '%s'</source> <translation type="unfinished">Μη έγκυρη μάσκα δικτύου που καθορίζεται στο -whitelist: '%s'</translation> </message> <message> + <source>Listening for incoming connections failed (listen returned error %s)</source> + <translation type="unfinished">Η ακρόαση για εισερχόμενες συνδέσεις απέτυχε (ακούστε επιστραμμένο σφάλμα %s)</translation> + </message> + <message> <source>Loading P2P addresses…</source> <translation type="unfinished">Φόρτωση διευθύνσεων P2P...</translation> </message> @@ -4190,6 +4399,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> @@ -4274,6 +4487,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Άγνωστος τύπος διεύθυνσης '%s'</translation> </message> <message> + <source>Unknown change type '%s'</source> + <translation type="unfinished"> Άγνωστος τύπος αλλαγής '%s'</translation> + </message> + <message> <source>Unknown network specified in -onlynet: '%s'</source> <translation type="unfinished">Έχει οριστεί άγνωστo δίκτυο στο -onlynet: '%s'</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..4cda8f900b 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,11 +297,15 @@ 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> + <message> + <source>default wallet</source> + <translation type="unfinished">defaŭlta monujo</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -477,10 +481,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Fermi ĉiujn monujojn</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">defaŭlta monujo</translation> - </message> - <message> <source>Wallet Name</source> <extracomment>Label of the input field where the name of the wallet is entered.</extracomment> <translation type="unfinished">Monujo-Nomo</translation> @@ -704,10 +704,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Malfermi monujon averto</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">defaŭlta monujo</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Malfermi la Monujon</translation> @@ -834,8 +830,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"> @@ -1342,6 +1338,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&Malekzili</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Neniu</translation> + </message> + <message> <source>To</source> <translation type="unfinished">Al</translation> </message> @@ -1722,10 +1722,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Bonvolu kontroli la adreson kaj reprovi.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">La adreso, kiun vi enmetis, referencas neniun ŝlosilon.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Malŝloso de monujo estas nuligita.</translation> </message> @@ -2057,11 +2053,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Send Coins</source> <translation type="unfinished">Sendi Bitmonon</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">defaŭlta monujo</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -2144,6 +2136,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..9f4091eadd 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">Haz clic derecho para editar 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">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> @@ -129,7 +129,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Enter passphrase</source> - <translation type="unfinished">Ingresa la frase de contraseña</translation> + <translation type="unfinished">Ingresar la frase de contraseña</translation> </message> <message> <source>New passphrase</source> @@ -137,7 +137,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Repeat new passphrase</source> - <translation type="unfinished">Repite la nueva frase de contraseña</translation> + <translation type="unfinished">Repetir la nueva frase de contraseña</translation> </message> <message> <source>Show passphrase</source> @@ -184,6 +184,14 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> <translation type="unfinished">Introduce la frase de contraseña antigua y la nueva para el monedero.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continuar</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Atrás</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 monedero no garantiza la protección total de tus bitcoins contra robos si el equipo está infectado con malware.</translation> </message> @@ -406,7 +414,11 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> <numerusform>%n años</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">monedero predeterminado</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -484,7 +496,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Cambiar la frase de contraseña utilizada para el cifrado del monedero</translation> + <translation type="unfinished">Cambiar la contraseña utilizada para el cifrado del monedero</translation> </message> <message> <source>&Send</source> @@ -500,35 +512,23 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">&Cifrar monedero…</translation> - </message> - <message> - <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">Cifrar las claves privadas de tu monedero</translation> + <translation type="unfinished">&Cifrar monedero</translation> </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&Respaldar monedero…</translation> + <translation type="unfinished">&Copia de seguridad del monedero</translation> </message> <message> <source>&Change Passphrase…</source> - <translation type="unfinished">&Cambiar frase de contraseña…</translation> + <translation type="unfinished">&Cambiar 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 tus direcciones Bitcoin para probar la propiedad</translation> + <translation type="unfinished">Firmar &mensaje...</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 comprobar que fueron firmados con la dirección Bitcoin indicada</translation> + <translation type="unfinished">&Verificar mensaje...</translation> </message> <message> <source>&Load PSBT from file…</source> @@ -551,24 +551,12 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> <translation type="unfinished">Cerrar todos los monederos...</translation> </message> <message> - <source>&File</source> - <translation type="unfinished">&Archivo</translation> - </message> - <message> - <source>&Settings</source> - <translation type="unfinished">&Parámetros</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> - <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Sincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Sincronizando cabeceras (1%1%)</translation> </message> <message> <source>Synchronizing with network…</source> @@ -576,27 +564,27 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Indexing blocks on disk…</source> - <translation type="unfinished">Indexando bloques en disco…</translation> + <translation type="unfinished">Indexando bloques en disco...</translation> </message> <message> <source>Processing blocks on disk…</source> - <translation type="unfinished">Procesando bloques en disco…</translation> + <translation type="unfinished">Procesando bloques en disco...</translation> </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">Conectando con pares…</translation> + <translation type="unfinished">Conectando con pares...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Solicitar pagos (genera códigos QR y URI de tipo "bitcoin:")</translation> + <translation type="unfinished">Solicitar pagos (genera código QR y URI's de Bitcoin)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Muestra el listado de direcciones de envío y etiquetas utilizadas</translation> + <translation type="unfinished">Editar la lista de las direcciones y etiquetas almacenadas</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Muestra el listado de direcciones de recepción y etiquetas utilizadas</translation> + <translation type="unfinished">Mostrar la lista de direcciones de envío y etiquetas</translation> </message> <message> <source>&Command-line options</source> @@ -605,8 +593,8 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>Se ha procesado %n bloque del historial de transacciones.</numerusform> - <numerusform>Se han procesado %n bloques del historial de transacciones.</numerusform> + <numerusform>Procesado %n bloque del historial de transacciones.</numerusform> + <numerusform>Procesado %n bloques del historial de transacciones.</numerusform> </translation> </message> <message> @@ -615,15 +603,15 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Catching up…</source> - <translation type="unfinished">Poniéndose al día…</translation> + <translation type="unfinished">Poniéndose al día...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">El último bloque recibido fue generado hace %1.</translation> + <translation type="unfinished">El último bloque recibido fue generado hace %1 horas.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Las transacciones posteriores aún no estarán visibles.</translation> + <translation type="unfinished">Las transacciones posteriores aún no son visibles.</translation> </message> <message> <source>Warning</source> @@ -635,7 +623,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Up to date</source> - <translation type="unfinished">Al día</translation> + <translation type="unfinished">Actualizado al día </translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> @@ -647,27 +635,23 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el portapapeles</translation> + <translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el Portapapeles</translation> </message> <message> <source>Node window</source> - <translation type="unfinished">Ventana de nodo</translation> - </message> - <message> - <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Abrir la consola de depuración y diagnóstico de nodos</translation> + <translation type="unfinished">Ventana del nodo</translation> </message> <message> <source>&Sending addresses</source> - <translation type="unfinished">&Direcciones de envío</translation> + <translation type="unfinished">Direcciones de &envío</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">Direcciones de &recepción</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Abrir un URI de tipo "bitcoin:"</translation> + <translation type="unfinished">Abrir un bitcoin: URI</translation> </message> <message> <source>Open Wallet</source> @@ -716,10 +700,6 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> <translation type="unfinished">Ocultar los valores de la ventana de previsualización</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Monedero predeterminado</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">No hay monederos disponibles</translation> </message> @@ -757,7 +737,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>%1 client</source> - <translation type="unfinished">%1 cliente</translation> + <translation type="unfinished">Cliente %1 </translation> </message> <message> <source>&Hide</source> @@ -771,8 +751,8 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>%n conexión activa 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 conexiónes activas con la red de Bitcoin.</numerusform> </translation> </message> <message> @@ -788,16 +768,16 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> <message> <source>Disable network activity</source> <extracomment>A context menu item.</extracomment> - <translation type="unfinished">Desactivar la actividad de la red</translation> + <translation type="unfinished">Deshabilitar actividad de red</translation> </message> <message> <source>Enable network activity</source> <extracomment>A context menu item. The network activity was disabled previously.</extracomment> - <translation type="unfinished">Habilitar la actividad de la red</translation> + <translation type="unfinished">Habilitar actividad de red</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Presincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Presincronizando cabeceras (%1%)...</translation> </message> <message> <source>Error creating wallet</source> @@ -907,7 +887,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished">Tras la comisión:</translation> + <translation type="unfinished">Después de la comisión:</translation> </message> <message> <source>Change:</source> @@ -915,7 +895,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>(un)select all</source> - <translation type="unfinished">(de)seleccionar todo</translation> + <translation type="unfinished">(de)selecionar todo</translation> </message> <message> <source>Tree mode</source> @@ -931,11 +911,11 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Received with label</source> - <translation type="unfinished">Recibido con etiqueta</translation> + <translation type="unfinished">Recibido con dirección</translation> </message> <message> <source>Received with address</source> - <translation type="unfinished">Recibido con dirección</translation> + <translation type="unfinished">Recibido con etiqueta</translation> </message> <message> <source>Date</source> @@ -971,11 +951,11 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>L&ock unspent</source> - <translation type="unfinished">&Bloquear importe no gastado</translation> + <translation type="unfinished">B&loquear no gastado</translation> </message> <message> <source>&Unlock unspent</source> - <translation type="unfinished">&Desbloquear importe no gastado</translation> + <translation type="unfinished">&Desbloquear lo no gastado</translation> </message> <message> <source>Copy quantity</source> @@ -987,7 +967,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar tras comisión</translation> + <translation type="unfinished">Copiar después de la comisión</translation> </message> <message> <source>Copy bytes</source> @@ -1011,7 +991,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>change from %1 (%2)</source> - <translation type="unfinished">cambio de %1 (%2)</translation> + <translation type="unfinished">cambia desde %1 (%2)</translation> </message> <message> <source>(change)</source> @@ -1032,7 +1012,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Create wallet failed</source> - <translation type="unfinished">Error al crear monedero</translation> + <translation type="unfinished">Fallo al crear monedero</translation> </message> <message> <source>Create wallet warning</source> @@ -1076,11 +1056,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">La migración del monedero lo convertirá en uno o más monederos basados en descriptores. Será necesario realizar una nueva copia de seguridad del monedero. + <translation type="unfinished">La migración del monedero lo convertirá en uno o más monederos basados en descriptores. Será necesario realizar una nuevo respaldo del monedero. Si este monedero contiene scripts solo de observación, se creará un nuevo monedero que los contenga. Si este monedero contiene scripts solucionables pero no de observación, se creará un nuevo monedero diferente que los contenga. -El proceso de migración creará una copia de seguridad del monedero antes de migrar. Este archivo de copia de seguridad se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de este monedero. En el caso de una migración incorrecta, la copia de seguridad puede restaurarse con la funcionalidad "Restaurar monedero".</translation> +El proceso de migración creará un respaldo del monedero antes de migrar. Este archivo de respaldo se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de este monedero. En el caso de una migración incorrecta, el respaldo puede restaurarse con la funcionalidad "Restaurar monedero".</translation> </message> <message> <source>Migrate Wallet</source> @@ -1092,7 +1072,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </message> <message> <source>The wallet '%1' was migrated successfully.</source> - <translation type="unfinished">La migración del monedero "%1" se realizó correctamente.</translation> + <translation type="unfinished">La migración del monedero "%1" se ha realizado correctamente.</translation> </message> <message> <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> @@ -1122,10 +1102,6 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi <translation type="unfinished">Advertencia al abrir monedero</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">monedero predeterminado</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Abrir monedero</translation> @@ -1252,7 +1228,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> @@ -1303,7 +1279,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </message> <message> <source>Could not unlock wallet.</source> - <translation type="unfinished">No se pudo desbloquear el monedero.</translation> + <translation type="unfinished">No se ha podido desbloquear el monedero.</translation> </message> <message> <source>New key generation failed.</source> @@ -1362,11 +1338,11 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </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 datos en este directorio, que aumentará con el tiempo.</translation> + <translation type="unfinished">Se almacenarán al menos %1 GB de datos en este directorio, que aumentarán con el tiempo.</translation> </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">Se almacenará aproximadamente %1 GB de datos en este directorio.</translation> + <translation type="unfinished">Se almacenarán aproximadamente %1 GB de datos en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1562,7 +1538,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 +1546,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 +1587,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 +1641,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 +1750,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 +1779,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> @@ -1853,7 +1829,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </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">El archivo de configuración no se ha podido abrir.</translation> </message> <message> <source>This change would require a client restart.</source> @@ -1903,7 +1879,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 +1926,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 +2039,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 +2090,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> @@ -2230,10 +2206,6 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Para especificar una localización personalizada del directorio de datos, usa la opción "%1".</translation> </message> <message> - <source>Blocksdir</source> - <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> </message> @@ -2254,6 +2226,14 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Número de conexiones</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Direcciones locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Direcciones de red que tu nodo Bitcoin usa actualmente para comunicarse con otros nodos.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Cadena de bloques</translation> </message> @@ -2302,6 +2282,10 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Selecciona un par para ver la información detallada.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalles de pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versión de la capa de transporte: %1</translation> </message> @@ -2310,10 +2294,6 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Transporte</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <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> @@ -2389,7 +2369,7 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI </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> @@ -2420,6 +2400,10 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Sentido/Tipo</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">La cadena del identificador de sesión BIP324 en formato hexadecimal.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">El protocolo de red de este par está conectado a través de: IPv4, IPv6, Onion, I2P o CJDNS.</translation> </message> @@ -2450,7 +2434,7 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un 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">Tiempo transcurrido desde que se recibió de este par una nueva transacción aceptada en la mempool.</translation> + <translation type="unfinished">Tiempo transcurrido desde que se recibió de este par una nueva transacción aceptada en el mempool.</translation> </message> <message> <source>Last Send</source> @@ -2612,6 +2596,10 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Actividad de red desactivada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ninguno</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Ejecutar comando sin monedero</translation> </message> @@ -2694,7 +2682,7 @@ Para obtener más información sobre cómo usar esta consola, escribe %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">Mensaje opcional para agregar a la solicitud de pago, el cual será mostrado cuando la solicitud esté abierta. Nota: el mensaje no se enviará con el pago a través de la red de Bitcoin.</translation> + <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> @@ -2702,11 +2690,11 @@ Para obtener más información sobre cómo usar esta consola, escribe %6. </message> <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation type="unfinished">Usa este formulario para solicitar un pago. Todos los campos son <b>opcional</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> @@ -2714,7 +2702,7 @@ Para obtener más información sobre cómo usar esta consola, escribe %6. </message> <message> <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> - <translation type="unfinished">Mensaje opcional asociado a la solicitud de pago que podría ser presentado al remitente </translation> + <translation type="unfinished">Un mensaje opcional que se adjunta a la solicitud de pago y que puede mostrarse al remitente.</translation> </message> <message> <source>&Create new receiving address</source> @@ -2786,7 +2774,7 @@ Para obtener más información sobre cómo usar esta consola, escribe %6. </message> <message> <source>Could not unlock wallet.</source> - <translation type="unfinished">No se pudo desbloquear el monedero.</translation> + <translation type="unfinished">No se ha podido desbloquear el monedero.</translation> </message> <message> <source>Could not generate new %1 address</source> @@ -2891,7 +2879,7 @@ Para obtener más información sobre cómo usar esta consola, escribe %6. </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> @@ -2999,7 +2987,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Confirmation time target:</source> - <translation type="unfinished">Objetivo de tiempo de confirmación</translation> + <translation type="unfinished">Objetivo de tiempo de confirmación:</translation> </message> <message> <source>Enable Replace-By-Fee</source> @@ -3039,7 +3027,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 tras comisión</translation> + <translation type="unfinished">Copiar después de la comisión</translation> </message> <message> <source>Copy bytes</source> @@ -3203,7 +3191,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Se ha encontrado una dirección duplicada: las direcciones solo se deben usar una vez.</translation> </message> <message> <source>Transaction creation failed!</source> @@ -3273,7 +3261,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <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> @@ -3293,7 +3281,7 @@ 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">Ingresar una etiqueta para esta dirección a fin de agregarla 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> @@ -3322,8 +3310,8 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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 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> + <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">Puedes firmar mensajes o acuerdos con tus direcciones tipo legacy (P2PKH) 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> @@ -3410,8 +3398,8 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <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">La dirección ingresada no se refiere a una clave tipo legacy (P2PKH). La firma de mensajes para direcciones SegWit y de otros tipos que no sean P2PKH no es compatible con esta versión de %1. Comprueba la dirección e inténtalo de nuevo.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3423,7 +3411,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> @@ -3435,7 +3423,7 @@ 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">La firma no pudo decodificarse.</translation> + <translation type="unfinished">La firma no ha podido decodificarse.</translation> </message> <message> <source>Please check the signature and try again.</source> @@ -3458,7 +3446,7 @@ 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">(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> @@ -3470,7 +3458,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <message> <source>conflicted with a transaction with %1 confirmations</source> <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment> - <translation type="unfinished">Hay un conflicto con una transacción de %1 confirmaciones.</translation> + <translation type="unfinished">Hay un conflicto con una transacción con %1 confirmaciones</translation> </message> <message> <source>0/unconfirmed, in memory pool</source> @@ -3637,7 +3625,7 @@ 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">Este panel muestra una descripción detallada de la transacción</translation> </message> <message> <source>Details for %1</source> @@ -3688,19 +3676,19 @@ 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> - <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> @@ -3767,15 +3755,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> @@ -3807,7 +3795,7 @@ 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> @@ -3849,7 +3837,7 @@ 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> @@ -3872,12 +3860,16 @@ 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">Error al exportar</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> - <translation type="unfinished">Ocurrió un error al intentar guardar el historial de transacciones en %1.</translation> + <translation type="unfinished">Ha ocurrido un error al intentar guardar el historial de transacciones en %1.</translation> </message> <message> <source>Exporting Successful</source> @@ -3924,7 +3916,7 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </message> <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> + <translation type="unfinished">El archivo de la TBPF debe ser inferior a 100 MiB</translation> </message> <message> <source>Unable to decode PSBT</source> @@ -3939,11 +3931,11 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </message> <message> <source>Fee bump error</source> - <translation type="unfinished">Error de incremento de la comisión</translation> + <translation type="unfinished">Error de incremento de comisión</translation> </message> <message> <source>Increasing transaction fee failed</source> - <translation type="unfinished">Ha fallado el incremento de la comisión de transacción.</translation> + <translation type="unfinished">Fallo al incrementar la comisión de transacción</translation> </message> <message> <source>Do you want to increase the fee?</source> @@ -3972,32 +3964,31 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiada al portapapeles</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">TBPF con incremento de comisión copiada en el portapapeles</translation> </message> <message> <source>Can't sign transaction.</source> - <translation type="unfinished">No puede firmar la transacción.</translation> + <translation type="unfinished">No se puede firmar la transacción.</translation> </message> <message> <source>Could not commit transaction</source> - <translation type="unfinished">No se pudo confirmar la transacción</translation> + <translation type="unfinished">No se ha podido confirmar la transacción</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">No puede mostrar la dirección</translation> + <source>Signer error</source> + <translation type="unfinished">Error de firmante</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">monedero predeterminado</translation> + <source>Can't display address</source> + <translation type="unfinished">No se puede mostrar la dirección</translation> </message> </context> <context> @@ -4048,11 +4039,11 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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 de Bitcoin para rescatar o restaurar una copia de seguridad.</translation> + <translation type="unfinished">%s corrupto. Intenta utilizar la herramienta del monedero de Bitcoin para rescatar o restaurar un respaldo.</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 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> + <translation type="unfinished">%s no ha podido 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 ha permitido 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 ha dejado el estado de cadena de la instantánea inválida en el disco por si resulta útil para diagnosticar el problema que ha causado 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> @@ -4096,15 +4087,15 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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 del monedero 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 volcado no es compatible. Esta versión del monedero de Bitcoin solo admite archivos de volcado de la versión 1. Se ha obtenido 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: los monederos heredados solo admiten los tipos de dirección "legacy", "p2sh-segwit" y "bech32".</translation> + <translation type="unfinished">Error: Los monederos de tipo "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> - <translation type="unfinished">Error: No se pueden producir descriptores para este monedero tipo "legacy". Asegúrate de proporcionar la frase de contraseña del monedero si está encriptada.</translation> + <translation type="unfinished">Error: No se pueden producir descriptores para este monedero de tipo "legacy". Asegúrate de proporcionar la frase de contraseña del monedero si está 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> @@ -4112,7 +4103,7 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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">Archivo "peers.dat" inválido o corrupto (%s). Si crees que se trata de un error, infórmalo a %s. Como alternativa, puedes quitar el archivo %s (renombrarlo, moverlo o eliminarlo) para que se cree uno nuevo en el siguiente inicio.</translation> </message> <message> <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> @@ -4120,7 +4111,7 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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 ha proporcionado ningún 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> @@ -4131,10 +4122,6 @@ Ve a "Archivo > Abrir monedero" para cargar uno. <translation type="unfinished">No se ha proporcionado el formato de archivo del monedero. 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> - <translation type="unfinished">Verifica que la fecha y hora del equipo sean correctas. Si el reloj está mal configurado, %s no funcionará correctamente.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Contribuye si te parece que %s es útil. Visita %s para obtener más información sobre el software.</translation> </message> @@ -4168,7 +4155,7 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </message> <message> <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> - <translation type="unfinished">Este error podría ocurrir si el monedero no se cerró correctamente y se cargó por última vez usando una compilación con una versión más reciente de Berkeley DB. Si es así, usa el software que cargó por última vez este monedero.</translation> + <translation type="unfinished">Este error podría ocurrir si el monedero no se ha cerrado correctamente y se ha cargado por última vez usando una compilación con una versión más reciente de Berkeley DB. Si es así, usa el software que ha cargado por última vez este monedero.</translation> </message> <message> <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> @@ -4188,7 +4175,7 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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). Reduce 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> @@ -4196,11 +4183,11 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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 monedero desconocido "%s". Proporciona uno entre "bdb" o "sqlite".</translation> + <translation type="unfinished">Se ha proporcionado un formato de monedero 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">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> + <translation type="unfinished">El nivel de registro específico de la categoría 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> @@ -4243,10 +4230,6 @@ Ve a "Archivo > Abrir monedero" para cargar uno. <translation type="unfinished">-maxmempool debe ser por lo menos de %d MB.</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ocurrió un error interno grave. Consulta debug.log para obtener más información.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">No se puede resolver la dirección de -%s: "%s"</translation> </message> @@ -4260,11 +4243,11 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">No se puede escribir en el directorio de datos "%s"; comprueba los permisos.</translation> + <translation type="unfinished">No se puede escribir en el directorio de datos '%s'; verificar permisos.</translation> </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 de %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> @@ -4276,7 +4259,7 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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 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> + <translation type="unfinished">Error al leer %s. Todas las claves se han leído 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> @@ -4292,17 +4275,31 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </message> <message> <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> - <translation type="unfinished">No se pudo calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> + <translation type="unfinished">No se ha podido calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> + </message> + <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">No se ha podido eliminar la instantánea chainstate dir (%s). Elimínala manualmente antes de reiniciar. +</translation> </message> <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> - <translation type="unfinished">No se pudo cambiar el nombre del archivo peers.dat inválido. Muévelo o elimínalo, e intenta de nuevo.</translation> + <translation type="unfinished">No se ha podido cambiar el nombre del archivo "peers.dat" inválido. Muévelo o elimínalo, e intenta de nuevo.</translation> </message> <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> <translation type="unfinished">Error al calcular la comisión. La opción "fallbackfee" está desactivada. Espera algunos bloques o activa %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el vaciado del archivo de bloques al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el vaciado del archivo para deshacer al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Opciones incompatibles: -dnsseed=1 se especificó explícitamente, pero -onlynet prohíbe conexiones a IPv4/IPv6.</translation> </message> @@ -4311,22 +4308,38 @@ Ve a "Archivo > Abrir monedero" para cargar uno. <translation type="unfinished">Importe inválido para %s=<amount>: "%s" (debe ser al menos la comisión mínima de retransmisión de %s para evitar transacciones atascadas)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">El peso máximo de la transacción es menor que el peso de la transacción sin entradas.</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">El peso máximo de la transacción es demasiado bajo, por lo que no puede incluir la salida de cambio.</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Las conexiones salientes están restringidas a CJDNS (-onlynet=cjdns), pero no se proporciona -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">Las conexiones salientes están restringidas a Tor (-onlynet=onion), pero el proxy para conectarse con la red Tor está explícitamente prohibido: -onion=0.</translation> + <translation type="unfinished">Las conexiones salientes están restringidas a Tor (-onlynet=onion), pero el proxy para conectar con la red Tor está explícitamente prohibido: -onion=0.</translation> </message> <message> <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source> - <translation type="unfinished">Las conexiones salientes están restringidas a Tor (-onlynet=onion), pero no se proporciona el proxy para conectarse con la red Tor: no se indican -proxy, -onion ni -listenonion.</translation> + <translation type="unfinished">Las conexiones salientes están restringidas a Tor (-onlynet=onion), pero no se proporciona el proxy para conectar con la red Tor: no se indican -proxy, -onion ni -listenonion.</translation> </message> <message> <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source> <translation type="unfinished">Las conexiones salientes están restringidas a i2p (-onlynet=i2p), pero no se proporciona -i2psam.</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Ha fallado el cambio de nombre de ''%s" a ''%s". No se puede limpiar el directorio leveldb del estado de la cadena de fondo.</translation> + </message> + <message> + <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">La combinación de las entradas preseleccionadas y la selección automática de entradas del monedero supera el peso máximo de la transacción. Intenta enviar un importe menor o consolidar manualmente las UTXO del monedero.</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">El tamaño de las entradas supera el peso máximo. Intenta enviar un importe menor o consolidar manualmente las UTXO del monedero.</translation> </message> @@ -4340,18 +4353,18 @@ Ve a "Archivo > Abrir monedero" para cargar uno. </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 ha validado la instantánea de la UTXO. Reinicia para reanudar la descarga normal del bloque inicial 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á la mempool.</translation> + <translation type="unfinished">Las UTXO sin confirmar están disponibles, pero si se gastan, se crea una cadena de transacciones que rechazará el 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 inesperada tipo "legacy" en el monedero basado en descriptores. Cargando monedero %s + <translation type="unfinished">Se ha encontrado una entrada inesperada tipo "legacy" en el monedero basado en descriptores. Cargando monedero %s Es posible que el monedero haya sido manipulado o creado con malas intenciones. </translation> @@ -4362,13 +4375,17 @@ Es posible que el monedero haya sido manipulado o creado con malas intenciones. The wallet might had been created on a newer version. Please try running the latest software version. </source> - <translation type="unfinished">Se encontró un descriptor desconocido. Cargando monedero %s. + <translation type="unfinished">Se ha encontrado un descriptor desconocido. Cargando monedero %s. El monedero se podría haber creado con una versión más reciente. Intenta ejecutar la última versión del software. </translation> </message> <message> + <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">La fecha y la hora del ordenador parecen estar más de %d minutos desincronizadas con la red, lo que puede producir un fallo de consenso. Después de confirmar el reloj del ordenador, este mensaje debería dejar de aparecer cuando reinicies el nodo. Sin reiniciar, debería dejar de mostrarse automáticamente después de que te hayas conectado a un número suficiente de nuevos pares salientes, lo que puede llevar cierto tiempo. Puedes inspeccionar el campo "timeoffset" de los métodos RPC "getpeerinfo" y "getnetworkinfo" para obtener más información.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4378,11 +4395,23 @@ No se puede limpiar la migración fallida</translation> <source> Unable to restore backup of wallet.</source> <translation type="unfinished"> -No se puede restaurar la copia de seguridad del monedero.</translation> +No se puede restaurar el respaldo del monedero.</translation> + </message> + <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind solo puede utilizarse para conexiones entrantes (se ha pasado "out")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para obtener más información:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">No se han encontrado datos assumeutxo para el blockhash indicado "%s".</translation> </message> <message> <source>Block verification was interrupted</source> - <translation type="unfinished">Se interrumpió la verificación de bloques</translation> + <translation type="unfinished">Se ha interrumpido la verificación de bloques</translation> </message> <message> <source>Config setting for %s only applied on %s network when in [%s] section.</source> @@ -4393,20 +4422,24 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">Derechos de autor (C) %i-%i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Se ha encontrado un bloque corrupto que indica un posible fallo del hardware.</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> + <translation type="unfinished">Se ha detectado 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> + <translation type="unfinished">No se ha podido encontrar el archivo asmap %s</translation> </message> <message> <source>Could not parse asmap file %s</source> - <translation type="unfinished">No se pudo analizar el archivo asmap %s</translation> + <translation type="unfinished">No se ha podido analizar el archivo asmap %s</translation> </message> <message> <source>Disk space is too low!</source> - <translation type="unfinished">¡El espacio en el disco es demasiado pequeño!</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> @@ -4421,6 +4454,10 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">El archivo de volcado %s no existe.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fallo en la prueba de cordura de la criptografía de curva elíptica. %s se apagará.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Error al confirmar transacción de la base de datos para eliminar transacciones del monedero</translation> </message> @@ -4434,7 +4471,7 @@ No se puede restaurar la copia de seguridad del monedero.</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 del monedero %s</translation> </message> <message> <source>Error loading %s</source> @@ -4482,7 +4519,7 @@ No se puede restaurar la copia de seguridad del monedero.</translation> </message> <message> <source>Error: Couldn't create cursor into database</source> - <translation type="unfinished">Error: No se pudo crear el cursor en la base de datos</translation> + <translation type="unfinished">Error: No se ha podido crear el cursor en la base de datos</translation> </message> <message> <source>Error: Disk space is low for %s</source> @@ -4494,19 +4531,19 @@ No se puede restaurar la copia de seguridad del monedero.</translation> </message> <message> <source>Error: Failed to create new watchonly wallet</source> - <translation type="unfinished">Error: No se puede crear un monedero solo de observación</translation> + <translation type="unfinished">Error: No se ha podido crear un monedero solo de observación</translation> </message> <message> <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">Error: Se recibió una clave que no es hexadecimal (%s)</translation> + <translation type="unfinished">Error: Se ha recibido 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 hexadecimal (%s)</translation> + <translation type="unfinished">Error: Se ha recibido un valor que no es hexadecimal (%s)</translation> </message> <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> - <translation type="unfinished">Error: El pool de claves se agotó. Invoca keypoolrefill primero.</translation> + <translation type="unfinished">Error: El pool de claves se ha agotado. Invoca keypoolrefill primero.</translation> </message> <message> <source>Error: Missing checksum</source> @@ -4514,7 +4551,7 @@ No se puede restaurar la copia de seguridad del monedero.</translation> </message> <message> <source>Error: No %s addresses available.</source> - <translation type="unfinished">Error: No hay direcciones %s disponibles .</translation> + <translation type="unfinished">Error: No hay direcciones %s disponibles.</translation> </message> <message> <source>Error: This wallet already uses SQLite</source> @@ -4569,10 +4606,22 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">Error: la transacción de la base de datos no se puede ejecutar para el monedero %s</translation> </message> <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">No se ha podido conectar el mejor bloque (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">No se ha podido desconectar el bloque.</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 read block.</source> + <translation type="unfinished">No se ha podido leer el bloque.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Error al rescanear el monedero durante la inicialización</translation> </message> @@ -4585,6 +4634,22 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">Fallo al verificar la base de datos</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">No se ha podido escribir el bloque.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Error al escribir en la base de datos del índice de bloques.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Error al escribir en la base de datos de monedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Error al escribir datos para deshacer.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">Error al eliminar la transacción: %s</translation> </message> @@ -4602,7 +4667,7 @@ No se puede restaurar la copia de seguridad del monedero.</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished">El bloque génesis es incorrecto o no se encontró. ¿El directorio de datos es incorrecto para la red?</translation> + <translation type="unfinished">El bloque génesis es incorrecto o no se ha encontrado. ¿El directorio de datos es incorrecto para la red?</translation> </message> <message> <source>Initialization sanity check failed. %s is shutting down.</source> @@ -4610,7 +4675,7 @@ No se puede restaurar la copia de seguridad del monedero.</translation> </message> <message> <source>Input not found or already spent</source> - <translation type="unfinished">Entrada no encontrada o ya gastada</translation> + <translation type="unfinished">La entrada no se ha encontrado o ya se ha gastado</translation> </message> <message> <source>Insufficient dbcache for block verification</source> @@ -4662,7 +4727,7 @@ No se puede restaurar la copia de seguridad del monedero.</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 en la escucha para conexiones entrantes (la escucha ha devuelto el error %s)</translation> </message> <message> <source>Loading P2P addresses…</source> @@ -4681,6 +4746,10 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">Cargando monedero...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">El peso máximo de la transacción debe estar entre %d y %d.</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Falta el importe</translation> </message> @@ -4702,13 +4771,17 @@ No se puede restaurar la copia de seguridad del monedero.</translation> </message> <message> <source>Not found pre-selected input %s</source> - <translation type="unfinished">La entrada preseleccionada no se encontró %s</translation> + <translation type="unfinished">La entrada preseleccionada no se ha encontrado %s</translation> </message> <message> <source>Not solvable pre-selected input %s</source> <translation type="unfinished">La entrada preseleccionada no se puede solucionar %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Solo se ha establecido la dirección, sin permisos: "%s"</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">La poda no se puede configurar con un valor negativo.</translation> </message> @@ -4753,6 +4826,18 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">La sección [%s] no se reconoce.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">El firmante no se ha hecho eco de la dirección.</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">El firmante se ha hecho eco de una dirección inesperada: %s.</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">El firmante ha devuelto un error: %s.</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Fallo al firmar la transacción</translation> </message> @@ -4781,6 +4866,18 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">Iniciando subprocesos de red...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Error del sistema durante el vaciado:%s.</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Error del sistema al cargar un archivo de bloque externo: %s.</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Error del sistema al guardar el bloque en el disco: %s.</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">El código fuente está disponible en %s.</translation> </message> @@ -4790,13 +4887,17 @@ No se puede restaurar la copia de seguridad del monedero.</translation> </message> <message> <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">El importe de la transacción es muy pequeño para pagar la comisión</translation> + <translation type="unfinished">El importe de la transacción es demasiado pequeño para pagar la comisión</translation> </message> <message> <source>The wallet will avoid paying less than the minimum relay fee.</source> <translation type="unfinished">El monedero evitará pagar menos que la comisión mínima de retransmisión. </translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">No hay ningún ScriptPubKeyManager para esta dirección.</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Este es un software experimental.</translation> </message> @@ -4837,12 +4938,8 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">Transacción demasiado grande</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">No se puede asignar memoria para -maxsigcachesize: "%s" MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> - <translation type="unfinished">No se puede establecer un enlace a %s en este equipo (bind devolvió el error %s)</translation> + <translation type="unfinished">No se puede establecer un enlace a %s en este equipo (bind ha devuelto el error %s)</translation> </message> <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> @@ -4901,6 +4998,10 @@ No se puede restaurar la copia de seguridad del monedero.</translation> <translation type="unfinished">Se desconocen las nuevas reglas activadas (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opción no reconocida "%s" proporcionada en -test=<option>.</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished">El nivel de registro global %s=%s no es compatible. Valores válidos: %s.</translation> </message> @@ -4942,11 +5043,11 @@ No se puede restaurar la copia de seguridad del monedero.</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 pudo leerse</translation> </message> <message> <source>Settings file could not be written</source> - <translation type="unfinished">El archivo de configuración no puede escribirse</translation> + <translation type="unfinished">El archivo de configuración no ha podido escribirse</translation> </message> </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index 0f4dda3755..419d9a0437 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -11,7 +11,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Copiar la dirección actualmente seleccionada al sistema de portapapeles</translation> + <translation type="unfinished">Copiar la dirección seleccionada actualmente al portapapeles del sistema</translation> </message> <message> <source>&Copy</source> @@ -177,6 +177,14 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <translation type="unfinished">Introducir la vieja contraseña y la nueva contraseña para la billetera.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continuar</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Atrás</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 codificando tu billetera no garantiza mantener a salvo tus bitcoins en caso de tener virus en el computador.</translation> </message> @@ -264,7 +272,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">Se ha producido un error interno. 1%1 Se intentará continuar de manera segura. Este es un error inesperado que se puede reportar como se describe a continuación.</translation> + <translation type="unfinished">Se ha producido un error interno. %1 Se 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 +289,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>%1 didn't yet exit safely…</source> - <translation type="unfinished">%1 aún no salió de forma segura...</translation> + <translation type="unfinished">%1 todavía no ha terminado de forma segura...</translation> </message> <message> <source>unknown</source> @@ -390,7 +398,11 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <numerusform>%n años</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">billetera predeterminada</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -487,20 +499,32 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <translation type="unfinished">Encripta las claves privadas que pertenecen a tu billetera</translation> </message> <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Copia de seguridad del monedero</translation> + </message> + <message> <source>&Change Passphrase…</source> - <translation type="unfinished">&Cambiar frase de contraseña...</translation> + <translation type="unfinished">&Cambiar 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">Firme mensajes con sus direcciones de Bitcoin para demostrar que los posee</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">Verifique los mensajes para asegurarse de que fueron firmados con las direcciones de Bitcoin especificadas</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar PSBT desde archivo...</translation> + <translation type="unfinished">&Cargar PSBT desde el archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -516,7 +540,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Close All Wallets…</source> - <translation type="unfinished">Cerrar todos los monederos...</translation> + <translation type="unfinished">Cerrar Todos los Monederos...</translation> </message> <message> <source>&File</source> @@ -536,7 +560,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Sincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Sincronizando cabeceras (1%1%)</translation> </message> <message> <source>Synchronizing with network…</source> @@ -552,7 +576,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">Conectando a pares...</translation> + <translation type="unfinished">Conectando con pares...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> @@ -614,28 +638,24 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <translation type="unfinished">Cargar PSBT desde el &portapapeles...</translation> </message> <message> - <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el portapapeles</translation> - </message> - <message> <source>Node window</source> - <translation type="unfinished">Ventana 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> - <translation type="unfinished">&Direcciones de envío</translation> + <translation type="unfinished">Direcciones de &envío</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">Direcciones de &recepción</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Bitcoin: abrir URI</translation> + <translation type="unfinished">Abrir un bitcoin: URI</translation> </message> <message> <source>Open Wallet</source> @@ -661,7 +681,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </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> @@ -676,30 +696,18 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <translation type="unfinished">Muestre el mensaje de ayuda %1 para obtener una lista con 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> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">billetera predeterminada</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Monederos no disponibles</translation> </message> <message> <source>Wallet Data</source> <extracomment>Name of the wallet data file format.</extracomment> - <translation type="unfinished">Datos de la billetera</translation> + <translation type="unfinished">Datos del monedero </translation> </message> <message> <source>Load Wallet Backup</source> <extracomment>The title for Restore Wallet File Windows</extracomment> - <translation type="unfinished">Cargar copia de seguridad de billetera</translation> + <translation type="unfinished">Cargar copia de seguridad del monedero</translation> </message> <message> <source>Restore Wallet</source> @@ -709,7 +717,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <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> @@ -729,20 +737,20 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </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 conexiónes activas con la red de Bitcoin.</numerusform> </translation> </message> <message> <source>Click for more actions.</source> <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> - <translation type="unfinished">Hacer clic para ver más acciones.</translation> + <translation type="unfinished">Haz clic para ver más acciones.</translation> </message> <message> <source>Show Peers tab</source> @@ -752,7 +760,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <message> <source>Disable network activity</source> <extracomment>A context menu item.</extracomment> - <translation type="unfinished">Deshabilitar actividad de red</translation> + <translation type="unfinished">Desactivar la actividad de la red</translation> </message> <message> <source>Enable network activity</source> @@ -761,7 +769,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Presincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Presincronizando cabeceras (%1%)...</translation> </message> <message> <source>Error creating wallet</source> @@ -821,11 +829,11 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>HD key generation is <b>enabled</b></source> - <translation type="unfinished">La generación de la clave HD está <b> activada </ b></translation> + <translation type="unfinished">La generación de la clave HD está <b> activada </b></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 la clave HD está <b> desactivada </b></translation> </message> <message> <source>Private key <b>disabled</b></source> @@ -833,11 +841,11 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </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> desbloqueada </b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">La billetera está <b> encriptada </ b> y actualmente está <b> bloqueada </ b></translation> + <translation type="unfinished">La billetera está <b> encriptada </b> y actualmente está <b> bloqueada </b></translation> </message> <message> <source>Original message:</source> @@ -935,7 +943,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>L&ock unspent</source> - <translation type="unfinished">B&loquear importe no gastado</translation> + <translation type="unfinished">B&loquear no gastado</translation> </message> <message> <source>&Unlock unspent</source> @@ -1032,7 +1040,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </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">Estas seguro de wue 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. @@ -1082,10 +1090,6 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Advertencia sobre crear monedero</translation> </message> <message> - <source>default wallet</source> - <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 billetera</translation> @@ -2158,6 +2162,14 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Número de conexiones</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Direcciones locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Direcciones de red que tu nodo Bitcoin usa actualmente para comunicarse con otros nodos.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Cadena de bloques</translation> </message> @@ -2175,7 +2187,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Wallet: </source> - <translation type="unfinished">Monedero:</translation> + <translation type="unfinished">Monedero: </translation> </message> <message> <source>&Reset</source> @@ -2202,6 +2214,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Seleccione un par para ver información detallada.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalles de pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versión de la capa de transporte: %1</translation> </message> @@ -2210,10 +2226,6 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Transporte</translation> </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> - </message> - <message> <source>Session ID</source> <translation type="unfinished">Identificador de sesión</translation> </message> @@ -2289,7 +2301,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> @@ -2316,6 +2328,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Dirección/Tipo</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">La cadena del identificador de sesión BIP324 en formato hexadecimal.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">El protocolo de red mediante el cual está conectado este par: IPv4, IPv6, Onion, I2P o CJDNS.</translation> </message> @@ -2504,6 +2520,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Actividad de red deshabilitada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ninguno</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Ejecutar comando sin monedero</translation> </message> @@ -2589,7 +2609,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaci </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">Use 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> @@ -2850,7 +2870,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaci </message> <message> <source>Inputs…</source> - <translation type="unfinished">Entradas...</translation> + <translation type="unfinished">Entradas…</translation> </message> <message> <source>Choose…</source> @@ -3180,8 +3200,8 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <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">Puedes firmar mensajes o acuerdos con tus direcciones tipo legacy (P2PKH) 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> @@ -3264,8 +3284,8 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <translation type="unfinished">Por favor, revisa la dirección e intenta nuevamente.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">La dirección ingresada no corresponde a una llave válida.</translation> + <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">La dirección ingresada no se refiere a una clave tipo legacy (P2PKH). La firma de mensajes para direcciones SegWit y de otros tipos que no sean P2PKH no es compatible con esta versión de %1. Comprueba la dirección e inténtalo de nuevo.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3825,9 +3845,8 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">PSBT copiada</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiada al portapapeles</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">TBPF con incremento de comisión copiada en el portapapeles</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3838,12 +3857,12 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se pudo confirmar la transacción</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">No se puede mostrar la dirección</translation> + <source>Signer error</source> + <translation type="unfinished">Error de firmante</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera predeterminada</translation> + <source>Can't display address</source> + <translation type="unfinished">No se puede mostrar la dirección</translation> </message> </context> <context> @@ -3863,7 +3882,7 @@ Ir a Archivo > Abrir billetera para cargar una. <message> <source>Wallet Data</source> <extracomment>Name of the wallet data file format.</extracomment> - <translation type="unfinished">Datos de la billetera</translation> + <translation type="unfinished">Datos del monedero </translation> </message> <message> <source>Backup Failed</source> @@ -3977,10 +3996,6 @@ Ir a Archivo > Abrir billetera para cargar una. <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> - <translation type="unfinished">Verifica que la fecha y hora de la computadora sean correctas. Si el reloj está mal configurado, %s no funcionará correctamente.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Contribuye si te parece que %s es útil. Visita %s para obtener más información sobre el software.</translation> </message> @@ -4089,10 +4104,6 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">-maxmempool debe ser por lo menos de %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ocurrió un error interno grave. Consulta debug.log para obtener más información.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">No se puede resolver -%s direccion: '%s'</translation> </message> @@ -4105,10 +4116,6 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se puede establecer -peerblockfilters sin -blockfilterindex.</translation> </message> <message> - <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">No se puede escribir en el directorio de datos "%s"; comprueba los permisos.</translation> - </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> </message> @@ -4141,6 +4148,12 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se pudo calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">No se ha podido eliminar la instantánea chainstate dir (%s). Elimínala manualmente antes de reiniciar. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">No se pudo cambiar el nombre del archivo peers.dat inválido. Muévelo o elimínalo, e intenta de nuevo.</translation> </message> @@ -4149,6 +4162,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Error al calcular la comisión. La opción "fallbackfee" está desactivada. Espera algunos bloques o activa %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el volcado del archivo de bloques al disco. Es probable que se deba a un error de E/O.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el volcado del archivo para deshacer al disco. Es probable que se deba a un error de E/O.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Opciones incompatibles: -dnsseed=1 se especificó explícitamente, pero -onlynet prohíbe conexiones a IPv4/IPv6.</translation> </message> @@ -4157,6 +4178,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Importe inválido para %s=<amount>: "%s" (debe ser al menos la comisión mínima de retransmisión de %s para evitar transacciones atascadas)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">El peso máximo de la transacción es menor que el peso de la transacción sin entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">El peso máximo de la transacción es demasiado bajo, por lo que no puede incluir la salida de cambio.</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Las conexiones salientes están restringidas a CJDNS (-onlynet=cjdns), pero no se proporciona -cjdnsreachable</translation> </message> @@ -4173,6 +4202,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Las conexiones salientes están restringidas a i2p (-onlynet=i2p), pero no se proporciona -i2psam</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Ha fallado el cambio de nombre de ''%s" a ''%s". No se puede limpiar el directorio leveldb del estado de la cadena de fondo.</translation> + </message> + <message> + <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">La combinación de las entradas preseleccionadas y la selección automática de entradas del monedero supera el peso máximo de la transacción. Intenta enviar un importe menor o consolidar manualmente las UTXO del monedero.</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">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> </message> @@ -4215,6 +4252,10 @@ Intenta ejecutar la última versión del software. </translation> </message> <message> + <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">La fecha y la hora del ordenador parecen estar más de %d minutos desincronizadas con la red, lo que puede producir un fallo de consenso. Después de confirmar el reloj del ordenador, este mensaje debería dejar de aparecer cuando reinicies el nodo. Sin reiniciar, debería dejar de mostrarse automáticamente después de que te hayas conectado a un número suficiente de nuevos pares salientes, lo que puede llevar cierto tiempo. Puedes inspeccionar el campo "timeoffset" de los métodos RPC "getpeerinfo" y "getnetworkinfo" para obtener más información.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4227,10 +4268,26 @@ Unable to restore backup of wallet.</source> No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind solo puede utilizarse para conexiones entrantes (se ha pasado "out")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para obtener más información:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">No se han encontrado datos assumeutxo para el blockhash indicado "%s".</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">Se interrumpió la verificación de bloques</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Se ha encontrado un bloque corrupto que indica un posible fallo del hardware.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Corrupción de base de datos de bloques detectada.</translation> </message> @@ -4259,6 +4316,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">El archivo de volcado %s no existe.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fallo en la prueba de cordura de la criptografía de curva elíptica. %s se apagará.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Error al confirmar db txn para eliminar transacciones de billetera</translation> </message> @@ -4408,10 +4469,22 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <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 connect best block (%s).</source> + <translation type="unfinished">No se ha podido conectar el mejor bloque (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">No se ha podido desconectar el bloque.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Ha fallado la escucha en todos los puertos. Usa -listen=0 si desea esto.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">No se ha podido leer el bloque.</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> @@ -4424,6 +4497,22 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Fallo al verificar la base de datos</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">No se ha podido escribir el bloque.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Error al escribir en la base de datos del índice de bloques.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Error al escribir en la base de datos de monedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Error al escribir datos para deshacer.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">Error al eliminar la transacción: 1%s</translation> </message> @@ -4520,6 +4609,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Cargando billetera...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">El peso máximo de la transacción debe estar entre %d y %d.</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Falta la cantidad</translation> </message> @@ -4548,6 +4641,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Entrada preseleccionada no solucionable %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Solo se ha establecido la dirección, sin permisos: "%s"</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">La poda no se puede configurar con un valor negativo.</translation> </message> @@ -4592,6 +4689,18 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La sección [%s] no se reconoce.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">El firmante no se hizo eco de la dirección</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">El firmante se hizo eco de una dirección inesperada %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">El firmante ha devuelto un error: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Firma de transacción fallida</translation> </message> @@ -4620,6 +4729,18 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Iniciando subprocesos de red...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Error del sistema durante el vaciado:%s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Error del sistema al cargar un archivo de bloque externo: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Error del sistema al guardar el bloque en el disco: %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">El código fuente esta disponible desde %s.</translation> </message> @@ -4636,6 +4757,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La billetera no permitirá pagar menos que la fee de transmisión mínima (relay fee).</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">No hay ningún ScriptPubKeyManager para esta dirección.</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Este es un software experimental.</translation> </message> @@ -4676,10 +4801,6 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Transacción muy grande</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">No se puede asignar memoria para -maxsigcachesize: "%s" MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">No es posible conectar con %s en este sistema (bind ha devuelto el error %s)</translation> </message> @@ -4740,6 +4861,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Se desconocen las nuevas reglas activadas (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opción no reconocida "%s" proporcionada en -test=<option>.</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> </message> diff --git a/src/qt/locale/bitcoin_es_CO.ts b/src/qt/locale/bitcoin_es_CO.ts index 1451f88104..14fbc9d056 100644 --- a/src/qt/locale/bitcoin_es_CO.ts +++ b/src/qt/locale/bitcoin_es_CO.ts @@ -51,7 +51,7 @@ </message> <message> <source>Choose the address to receive coins with</source> - <translation type="unfinished">Elige la dirección con la que se recibirán monedas</translation> + <translation type="unfinished">Elige la dirección en la que se recibirán monedas</translation> </message> <message> <source>C&hoose</source> @@ -65,7 +65,7 @@ <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. 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> +Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>&Copy Address</source> @@ -184,6 +184,14 @@ Solo es posible firmar con direcciones de tipo legacy.</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>Continue</source> + <translation type="unfinished">Continuar</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Atrás</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 encriptar tu billetera no garantiza la protección total contra el robo de tus bitcoins si la computadora está infectada con malware.</translation> </message> @@ -225,7 +233,7 @@ Solo es posible firmar con direcciones de tipo legacy.</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">La frase de contraseña ingresada para el descifrado de 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 . Si esto tiene éxito, establece una nueva frase de contraseña para evitar este problema en el futuro.</translation> + <translation type="unfinished">La frase de contraseña ingresada para el descifrado de 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 . Si esto es correcto, establece una nueva frase de contraseña para evitar este problema en el futuro.</translation> </message> <message> <source>Wallet passphrase was successfully changed.</source> @@ -259,7 +267,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> <name>BitcoinApplication</name> <message> <source>Settings file %1 might be corrupt or invalid.</source> - <translation type="unfinished">El archivo de configuración %1 puede estar corrupto o no ser válido.</translation> + <translation type="unfinished">El archivo de configuración %1 puede estar dañado o no ser válido.</translation> </message> <message> <source>Runaway exception</source> @@ -292,13 +300,17 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>%1 didn't yet exit safely…</source> - <translation type="unfinished">%1 aún no salió de forma segura...</translation> + <translation type="unfinished">%1 aún no se cerró 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> <translation type="unfinished">Fuente predeterminada del sistema "%1"</translation> </message> @@ -397,7 +409,11 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> <numerusform>%n años</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">billetera predeterminada</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -430,7 +446,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Show information about %1</source> - <translation type="unfinished">Mostrar Información sobre %1</translation> + <translation type="unfinished">Mostrar información sobre %1</translation> </message> <message> <source>About &Qt</source> @@ -487,7 +503,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>&Options…</source> - <translation type="unfinished">&Opciones…</translation> + <translation type="unfinished">&Opciones...</translation> </message> <message> <source>&Encrypt Wallet…</source> @@ -495,15 +511,15 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">Encriptar las claves privadas que pertenecen a la billetera</translation> + <translation type="unfinished">Encriptar las llaves privadas que pertenecen a tu billetera</translation> </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&Realizar copia de seguridad de la billetera...</translation> + <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> + <translation type="unfinished">&Cambiar contraseña...</translation> </message> <message> <source>Sign &message…</source> @@ -511,7 +527,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 de Bitcoin para demostrar que te pertenecen</translation> + <translation type="unfinished">Firmar un mensaje para provar que usted es dueño de esta dirección</translation> </message> <message> <source>&Verify message…</source> @@ -519,11 +535,11 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished">Verificar mensajes para asegurarte de que estén firmados con direcciones de Bitcoin concretas</translation> + <translation type="unfinished">Verificar mensajes comprobando que están firmados con direcciones Bitcoin concretas</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar TBPF desde archivo...</translation> + <translation type="unfinished">&Cargar TBPF desde el archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -531,11 +547,11 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">Cerrar billetera...</translation> + <translation type="unfinished">Cerrar Billetera...</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Crear billetera...</translation> + <translation type="unfinished">Crear Billetera...</translation> </message> <message> <source>Close All Wallets…</source> @@ -559,7 +575,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Sincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Sincronizando cabeceras (1%1%)</translation> </message> <message> <source>Synchronizing with network…</source> @@ -575,7 +591,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">Conectando a pares...</translation> + <translation type="unfinished">Conectando con pares...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> @@ -583,11 +599,11 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de envío usadas</translation> + <translation type="unfinished">Mostrar la lista de direcciones de envío y etiquetas</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de recepción usadas</translation> + <translation type="unfinished">Mostrar la lista de direcciones de recepción y etiquetas</translation> </message> <message> <source>&Command-line options</source> @@ -614,7 +630,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Las transacciones posteriores aún no están visibles.</translation> + <translation type="unfinished">Las transacciones posteriores aún no estarán visibles.</translation> </message> <message> <source>Warning</source> @@ -654,7 +670,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de destino</translation> + <translation type="unfinished">&Direcciones de recepción</translation> </message> <message> <source>Open a bitcoin: URI</source> @@ -707,10 +723,6 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> <translation type="unfinished">Ocultar los valores en la pestaña de vista general</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera predeterminada</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">No hay billeteras disponibles</translation> </message> @@ -732,7 +744,7 @@ Solo es posible firmar con direcciones de tipo legacy.</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 de la billetera</translation> + <translation type="unfinished">Nombre de la billetera </translation> </message> <message> <source>&Window</source> @@ -748,7 +760,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>%1 client</source> - <translation type="unfinished">%1 cliente</translation> + <translation type="unfinished">Cliente %1 </translation> </message> <message> <source>&Hide</source> @@ -938,7 +950,7 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>Confirmed</source> - <translation type="unfinished">Confirmada</translation> + <translation type="unfinished">Confirmado</translation> </message> <message> <source>Copy amount</source> @@ -1087,11 +1099,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> @@ -1113,10 +1125,6 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Advertencia al abrir billetera</translation> </message> <message> - <source>default wallet</source> - <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 billetera</translation> @@ -1353,11 +1361,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Se almacenarán al menos %1 GB de datos en este directorio, que aumentarán con el tiempo.</translation> </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">Se almacenará aproximadamente %1 GB de información en este directorio.</translation> + <translation type="unfinished">Se almacenarán aproximadamente %1 GB de datos en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1565,7 +1573,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> @@ -2217,10 +2225,6 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <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">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, usa la opción "%1".</translation> </message> @@ -2241,6 +2245,14 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Número de conexiones</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Direcciones locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Direcciones de red que tu nodo Bitcoin usa actualmente para comunicarse con otros nodos.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Cadena de bloques</translation> </message> @@ -2289,6 +2301,10 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Selecciona un par para ver la información detallada.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalles de pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versión de la capa de transporte: %1</translation> </message> @@ -2297,10 +2313,6 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Transporte</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <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> @@ -2407,6 +2419,10 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Dirección/Tipo</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">La cadena del identificador de sesión BIP324 en formato hexadecimal.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">El protocolo de red mediante el cual está conectado este par: IPv4, IPv6, Onion, I2P o CJDNS.</translation> </message> @@ -2599,6 +2615,10 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI <translation type="unfinished">Actividad de red desactivada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ninguno</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Ejecutar comando sin ninguna billetera</translation> </message> @@ -2646,7 +2666,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> @@ -3064,7 +3084,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>%1 to '%2'</source> - <translation type="unfinished">%1 a '%2'</translation> + <translation type="unfinished">%1 a "%2"</translation> </message> <message> <source>%1 to %2</source> @@ -3121,7 +3141,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 +3214,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> @@ -3284,7 +3304,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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">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> + <translation type="unfinished">Un mensaje adjunto al URI de tipo "bitcoin:" 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> @@ -3309,8 +3329,8 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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 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> + <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">Puedes firmar mensajes o acuerdos con tus direcciones tipo legacy (P2PKH) 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> @@ -3397,8 +3417,8 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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 ingresada no corresponde a una clave.</translation> + <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">La dirección ingresada no se refiere a una clave tipo legacy (P2PKH). La firma de mensajes para direcciones SegWit y de otros tipos que no sean P2PKH no es compatible con esta versión de %1. Comprueba la dirección e inténtalo de nuevo.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3494,7 +3514,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Source</source> - <translation type="unfinished">Fuente</translation> + <translation type="unfinished">Origen</translation> </message> <message> <source>Generated</source> @@ -3510,7 +3530,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> @@ -3915,7 +3935,7 @@ Ir a "Archivo > Abrir billetera" para cargar una. </message> <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> + <translation type="unfinished">El archivo de la TBPF debe ser más pequeño de 100 MiB</translation> </message> <message> <source>Unable to decode PSBT</source> @@ -3970,9 +3990,8 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">TBPF copiada</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiada al portapapeles</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">TBPF con incremento de comisión copiada en el portapapeles</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3983,12 +4002,12 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">No se pudo confirmar la transacción</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">No se puede mostrar la dirección</translation> + <source>Signer error</source> + <translation type="unfinished">Error de firmante</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera predeterminada</translation> + <source>Can't display address</source> + <translation type="unfinished">No se puede mostrar la dirección</translation> </message> </context> <context> @@ -4122,10 +4141,6 @@ Ir a "Archivo > Abrir billetera" para cargar una. <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> - <translation type="unfinished">Verifica que la fecha y hora de la computadora sean correctas. Si el reloj está mal configurado, %s no funcionará correctamente.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Contribuye si te parece que %s es útil. Visita %s para obtener más información sobre el software.</translation> </message> @@ -4234,10 +4249,6 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">-maxmempool debe ser por lo menos de %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ocurrió un error interno grave. Consulta debug.log para obtener más información.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">No se puede resolver la dirección de -%s: "%s"</translation> </message> @@ -4250,10 +4261,6 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">No se puede establecer -peerblockfilters sin -blockfilterindex.</translation> </message> <message> - <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">No se puede escribir en el directorio de datos "%s"; comprueba los permisos.</translation> - </message> - <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> <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> @@ -4286,6 +4293,12 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">No se pudo calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">No se pudo eliminar la instantánea chainstate dir (%s). Elimínala manualmente antes de reiniciar. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">No se pudo cambiar el nombre del archivo peers.dat inválido. Muévelo o elimínalo, e intenta de nuevo.</translation> </message> @@ -4294,6 +4307,14 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">Error al calcular la comisión. La opción "fallbackfee" está desactivada. Espera algunos bloques o activa %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falló el volcado del archivo de bloques al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falló el volcado del archivo para deshacer al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Opciones incompatibles: -dnsseed=1 se especificó explícitamente, pero -onlynet prohíbe conexiones a IPv4/IPv6.</translation> </message> @@ -4302,6 +4323,14 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">Importe inválido para %s=<amount>: "%s" (debe ser al menos la comisión mínima de retransmisión de %s para evitar transacciones atascadas)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">El peso máximo de la transacción es menor que el peso de la transacción sin entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">El peso máximo de la transacción es demasiado bajo, por lo que no puede incluir la salida de cambio.</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Las conexiones salientes están restringidas a CJDNS (-onlynet=cjdns), pero no se proporciona -cjdnsreachable</translation> </message> @@ -4318,6 +4347,14 @@ Ir a "Archivo > Abrir billetera" para cargar una. <translation type="unfinished">Las conexiones salientes están restringidas a i2p (-onlynet=i2p), pero no se proporciona -i2psam</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Falló el cambio de nombre de ''%s" a ''%s". No se puede limpiar el directorio leveldb del estado de la cadena de fondo.</translation> + </message> + <message> + <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">La combinación de las entradas preseleccionadas y la selección automática de entradas de la billetera supera el peso máximo de la transacción. Intenta enviar un importe menor o consolidar manualmente las UTXO de la billetera.</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">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> @@ -4342,7 +4379,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> @@ -4360,6 +4397,10 @@ Intenta ejecutar la última versión del software. </translation> </message> <message> + <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">La fecha y la hora de la computadora parecen estar más de %d minutos desincronizadas con la red, lo que puede producir un fallo de consenso. Después de confirmar el reloj de la computadora, este mensaje debería dejar de aparecer cuando reinicies el nodo. Sin reiniciar, debería dejar de mostrarse automáticamente después de que te hayas conectado a un número suficiente de nuevos pares salientes, lo que puede llevar cierto tiempo. Puedes inspeccionar el campo "timeoffset" de los métodos RPC "getpeerinfo" y "getnetworkinfo" para obtener más información.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4372,6 +4413,18 @@ Unable to restore backup of wallet.</source> No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind solo puede utilizarse para conexiones entrantes (se ha pasado "out")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para obtener más información:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">No se encontraron datos assumeutxo para el blockhash indicado "%s".</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">Se interrumpió la verificación de bloques</translation> </message> @@ -4384,6 +4437,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Derechos de autor (C) %i-%i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Se encontró un bloque corrupto que indica un posible fallo del hardware.</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> @@ -4412,6 +4469,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">El archivo de volcado %s no existe.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fallo en la prueba de cordura de la criptografía de curva elíptica. %s se apagará.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Error al confirmar db txn para eliminar transacciones de billetera</translation> </message> @@ -4533,7 +4594,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,26 +4606,37 @@ 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 connect best block (%s).</source> + <translation type="unfinished">No se pudo conectar el mejor bloque (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">No se pudo desconectar el bloque.</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 read block.</source> + <translation type="unfinished">No se pudo leer el bloque.</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> @@ -4577,8 +4649,24 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Fallo al verificar la base de datos</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">No se pudo escribir el bloque.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Error al escribir en la base de datos del índice de bloques.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Error al escribir en la base de datos de monedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Error al escribir datos para deshacer.</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> @@ -4673,6 +4761,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Cargando billetera...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">El peso máximo de la transacción debe estar entre %d y %d.</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Falta el importe</translation> </message> @@ -4701,6 +4793,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La entrada preseleccionada no se puede solucionar %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Solo se ha establecido la dirección, sin permisos: "%s"</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">La poda no se puede configurar con un valor negativo.</translation> </message> @@ -4745,6 +4841,18 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La sección [%s] no se reconoce.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">El firmante no se hizo eco de la dirección</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">El firmante se hizo eco de una dirección inesperada %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">El firmante ha devuelto un error: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Fallo al firmar la transacción</translation> </message> @@ -4773,6 +4881,18 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Iniciando subprocesos de red...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Error del sistema durante el vaciado:%s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Error del sistema al cargar un archivo de bloque externo: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Error del sistema al guardar el bloque en el disco: %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">El código fuente está disponible en %s.</translation> </message> @@ -4789,6 +4909,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La billetera evitará pagar menos que la comisión mínima de retransmisión.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">No hay ningún ScriptPubKeyManager para esta dirección.</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Este es un software experimental.</translation> </message> @@ -4829,10 +4953,6 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Transacción demasiado grande</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">No se puede asignar memoria para -maxsigcachesize: "%s" MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">No se puede establecer un enlace a %s en esta computadora (bind devolvió el error %s)</translation> </message> @@ -4893,12 +5013,16 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Se desconocen las nuevas reglas activadas (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opción no reconocida "%s" proporcionada en -test=<option>.</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <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> @@ -4910,11 +5034,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 puede agregar la transacción solo de observació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..47008084b8 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 en 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,100 +137,107 @@ 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>Continue</source> + <translation type="unfinished">Continuar</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Atrás</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> - <translation type="unfinished">La frase de contraseña ingresada para el descifrado de 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 . Si esto tiene éxito, establece una nueva frase de contraseña para evitar este problema en el futuro.</translation> + <translation type="unfinished">La frase de contraseña ingresada para el descifrado de 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 . Si esto es correcto, establece una nueva frase de contraseña para evitar este problema en el futuro.</translation> </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 +249,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> @@ -256,11 +267,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> <name>BitcoinApplication</name> <message> <source>Settings file %1 might be corrupt or invalid.</source> - <translation type="unfinished">El archivo de configuración %1 puede estar corrupto o no ser válido.</translation> + <translation type="unfinished">El archivo de configuración %1 puede estar dañado 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 +283,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,17 +296,21 @@ 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> - <translation type="unfinished">%1 aún no salió de forma segura...</translation> + <translation type="unfinished">%1 aún no se cerró 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> <translation type="unfinished">Fuente predeterminada del sistema "%1"</translation> </message> @@ -301,11 +320,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 +338,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 +348,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> @@ -390,7 +409,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n años</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">billetera por defecto</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -399,7 +422,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 +430,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 +454,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> @@ -455,27 +503,39 @@ Signing is only possible with addresses of the type 'legacy'.</source> </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> </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> + <translation type="unfinished">&Cambiar 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> </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> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar PSBT desde archivo...</translation> + <translation type="unfinished">&Cargar TBPF desde el archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -483,15 +543,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> @@ -511,7 +571,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Sincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Sincronizando cabeceras (1%1%)</translation> </message> <message> <source>Synchronizing with network…</source> @@ -527,7 +587,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">Conectando a pares...</translation> + <translation type="unfinished">Conectando con pares...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> @@ -586,35 +646,39 @@ 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> - </message> - <message> - <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el portapapeles</translation> + <translation type="unfinished">Cargar TBPF desde el &portapapeles...</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> - <translation type="unfinished">&Direcciones de envío</translation> + <translation type="unfinished">Direcciones de &envío</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">Direcciones de &recepción</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Bitcoin: abrir URI</translation> + <translation type="unfinished">Abrir un bitcoin: URI</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 cartera</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Cerrar cartera</translation> </message> <message> <source>Restore Wallet…</source> @@ -628,7 +692,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 +703,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Migrar una billetera</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> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</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,15 +724,19 @@ 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>Main Window</source> + <translation type="unfinished">Ventana principal</translation> + </message> + <message> <source>%1 client</source> - <translation type="unfinished">%1 cliente</translation> + <translation type="unfinished">Cliente %1 </translation> </message> <message> <source>&Hide</source> @@ -688,20 +744,20 @@ 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 conexiónes activas con la red de Bitcoin.</numerusform> </translation> </message> <message> <source>Click for more actions.</source> <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> - <translation type="unfinished">Hacer clic para ver más acciones.</translation> + <translation type="unfinished">Haz clic para ver más acciones.</translation> </message> <message> <source>Show Peers tab</source> @@ -720,7 +776,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Presincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Presincronizando cabeceras (%1%)...</translation> </message> <message> <source>Error creating wallet</source> @@ -728,7 +784,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 +817,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 +840,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 +848,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 +863,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 +878,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> @@ -894,7 +950,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">B&loquear no gastado</translation> </message> <message> <source>&Unlock unspent</source> @@ -944,6 +1000,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> @@ -970,12 +1031,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 +1047,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 +1056,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 +1075,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 +1093,22 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <context> <name>OpenWalletActivity</name> <message> - <source>Open wallet warning</source> - <translation type="unfinished">Advertencia sobre crear monedero</translation> + <source>Open wallet failed</source> + <translation type="unfinished">Fallo al abrir billetera</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <source>Open wallet warning</source> + <translation type="unfinished">Advertencia al abrir billetera</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 +1142,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 +1186,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 +1206,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 +1227,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 +1242,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 +1266,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 +1297,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 +1320,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 +1336,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án al menos %1 GB de datos en este directorio, que aumentarán 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án aproximadamente %1 GB de datos en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1260,27 +1357,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 +1393,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 +1420,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 +1498,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 +1508,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 +1537,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 +1565,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 +1591,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 +1600,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 +1609,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 +1626,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 +1640,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 +1657,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 +1672,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 +1697,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 +1717,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 +1757,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 +1787,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 +1802,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 +1812,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 +1824,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 +1846,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 +1862,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 +1870,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 +1886,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 +1902,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 +1957,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 +1981,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 +1994,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 +2014,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 +2026,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 +2048,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 +2069,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 +2077,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 +2103,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 +2123,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 +2143,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 +2154,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 +2190,23 @@ 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>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> + <source>Datadir</source> + <translation type="unfinished">Directorio de datos</translation> </message> <message> - <source>Blocksdir</source> - <translation type="unfinished">Bloques dir</translation> + <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, usa la opción "%1".</translation> </message> <message> <source>To specify a non-default location of the blocks directory use the '%1' option.</source> - <translation type="unfinished">Para especificar una 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> @@ -2040,24 +2221,40 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Número de conexiones</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Direcciones locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Direcciones de red que tu nodo Bitcoin usa actualmente para comunicarse con otros nodos.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Cadena de bloques</translation> </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 +2262,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> @@ -2080,6 +2277,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Selecciona un par para ver la información detallada.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalles de pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versión de la capa de transporte: %1</translation> </message> @@ -2088,14 +2289,14 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Transporte</translation> </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> - </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 +2306,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 +2336,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 +2356,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 +2364,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 +2372,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> @@ -2186,6 +2395,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Dirección/Tipo</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">La cadena del identificador de sesión BIP324 en formato hexadecimal.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">El protocolo de red mediante el cual está conectado este par: IPv4, IPv6, Onion, I2P o CJDNS.</translation> </message> @@ -2195,13 +2408,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 +2437,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 +2473,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 +2533,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 +2550,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,35 +2558,55 @@ 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> <translation type="unfinished">Actividad de red desactivada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ninguno</translation> + </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 +2615,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 +2638,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 +2650,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 +2665,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 +2673,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 +2701,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 +2725,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 +2769,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 +2783,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 +2816,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 +2824,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 +2839,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 +2851,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 +2870,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 +2886,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 +2894,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 +2902,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 +2914,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 +2938,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 +2974,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> @@ -2759,22 +3033,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 +3072,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 +3096,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 +3108,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 +3127,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 +3140,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 +3154,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 +3174,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 +3190,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 +3228,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 +3240,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 +3276,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 adjunto al URI de tipo "bitcoin:" 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,31 +3298,31 @@ 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> </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> + <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">Puedes firmar mensajes o acuerdos con tus direcciones tipo legacy (P2PKH) 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 +3334,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 +3342,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 +3366,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 +3378,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> + <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">La dirección ingresada no se refiere a una clave tipo legacy (P2PKH). La firma de mensajes para direcciones SegWit y de otros tipos que no sean P2PKH no es compatible con esta versión de %1. Comprueba la dirección e inténtalo de nuevo.</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 +3418,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 +3441,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 +3473,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> @@ -3182,7 +3490,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Source</source> - <translation type="unfinished">Fuente</translation> + <translation type="unfinished">Origen</translation> </message> <message> <source>Generated</source> @@ -3198,13 +3506,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 +3541,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 +3553,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 +3565,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 +3577,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 +3585,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,7 +3601,7 @@ 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> @@ -3304,9 +3620,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> + <message> + <source>Details for %1</source> + <translation type="unfinished">Detalles para %1</translation> </message> - </context> +</context> <context> <name>TransactionTableModel</name> <message> @@ -3319,43 +3639,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 +3699,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 +3711,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 +3719,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 +3750,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 +3766,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 +3790,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 +3832,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 +3848,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 +3864,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 +3880,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 +3890,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 +3926,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,28 +3963,27 @@ 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> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiada al portapapeles</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">TBPF con incremento de comisión copiada en el portapapeles</translation> </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> <translation type="unfinished">No se pudo confirmar la transacción</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">No se puede mostrar la dirección</translation> + <source>Signer error</source> + <translation type="unfinished">Error de firmante</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <source>Can't display address</source> + <translation type="unfinished">No se puede mostrar la dirección</translation> </message> </context> <context> @@ -3635,11 +3994,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 +4007,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 +4034,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 +4061,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 +4098,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> @@ -3754,16 +4117,16 @@ Ir a Archivo > Abrir billetera para cargar una. <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> - <translation type="unfinished">Verifica que la fecha y hora de la computadora sean correctas. Si el reloj está mal configurado, %s no funcionará correctamente.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <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 +4134,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 +4146,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 +4154,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 +4162,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 +4182,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 +4194,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 +4206,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,19 +4218,15 @@ 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> <translation type="unfinished">-maxmempool debe ser por lo menos de %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ocurrió un error interno grave. Consulta debug.log para obtener más información.</translation> - </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> @@ -3878,12 +4237,8 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se puede establecer -peerblockfilters sin -blockfilterindex.</translation> </message> <message> - <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">No se puede escribir en el directorio de datos "%s"; comprueba los permisos.</translation> - </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 +4250,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> @@ -3914,6 +4269,12 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se pudo calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">No se pudo eliminar la instantánea chainstate dir (%s). Elimínala manualmente antes de reiniciar. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">No se pudo cambiar el nombre del archivo peers.dat inválido. Muévelo o elimínalo, e intenta de nuevo.</translation> </message> @@ -3922,6 +4283,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Error al calcular la comisión. La opción "fallbackfee" está desactivada. Espera algunos bloques o activa %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el volcado del archivo de bloques al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el volcado del archivo para deshacer al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Opciones incompatibles: -dnsseed=1 se especificó explícitamente, pero -onlynet prohíbe conexiones a IPv4/IPv6.</translation> </message> @@ -3930,6 +4299,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Importe inválido para %s=<amount>: "%s" (debe ser al menos la comisión mínima de retransmisión de %s para evitar transacciones atascadas)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">El peso máximo de la transacción es menor que el peso de la transacción sin entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">El peso máximo de la transacción es demasiado bajo, por lo que no puede incluir la salida de cambio.</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Las conexiones salientes están restringidas a CJDNS (-onlynet=cjdns), pero no se proporciona -cjdnsreachable</translation> </message> @@ -3946,12 +4323,20 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Las conexiones salientes están restringidas a i2p (-onlynet=i2p), pero no se proporciona -i2psam</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Ha fallado el cambio de nombre de ''%s" a ''%s". No se puede limpiar el directorio leveldb del estado de la cadena de fondo.</translation> + </message> + <message> + <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">La combinación de las entradas preseleccionadas y la selección automática de entradas de la billetera supera el peso máximo de la transacción. Intenta enviar un importe menor o consolidar manualmente las UTXO de la billetera.</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">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 +4348,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> @@ -3988,6 +4373,10 @@ Intenta ejecutar la última versión del software. </translation> </message> <message> + <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">La fecha y la hora de la computadora parecen estar más de %d minutos desincronizadas con la red, lo que puede producir un fallo de consenso. Después de confirmar el reloj de la computadora, este mensaje debería dejar de aparecer cuando reinicies el nodo. Sin reiniciar, debería dejar de mostrarse automáticamente después de que te hayas conectado a un número suficiente de nuevos pares salientes, lo que puede llevar cierto tiempo. Puedes inspeccionar el campo "timeoffset" de los métodos RPC "getpeerinfo" y "getnetworkinfo" para obtener más información.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4000,12 +4389,36 @@ Unable to restore backup of wallet.</source> No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind solo puede utilizarse para conexiones entrantes (se ha pasado "out")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para obtener más información:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">No se encontraron datos assumeutxo para el blockhash indicado "%s".</translation> + </message> + <message> <source>Block verification was interrupted</source> <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>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Se encontró un bloque corrupto que indica un posible fallo del hardware.</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,13 +4438,17 @@ 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> <translation type="unfinished">El archivo de volcado %s no existe.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fallo en la prueba de cordura de la criptografía de curva elíptica. %s se apagará.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Error al confirmar db txn para eliminar transacciones de billetera</translation> </message> @@ -4045,7 +4462,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 +4474,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 +4506,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 +4526,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 +4550,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 +4570,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,24 +4582,35 @@ 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 connect best block (%s).</source> + <translation type="unfinished">No se pudo conectar el mejor bloque (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">No se pudo desconectar el bloque.</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 read block.</source> + <translation type="unfinished">No se pudo leer el bloque.</translation> </message> <message> <source>Failed to rescan the wallet during initialization</source> @@ -4186,15 +4618,31 @@ 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> <translation type="unfinished">Fallo al verificar la base de datos</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">No se pudo escribir el bloque.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Error al escribir en la base de datos del índice de bloques.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Error al escribir en la base de datos de monedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Error al escribir datos para deshacer.</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 +4658,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 +4678,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 +4701,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 +4726,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> @@ -4277,28 +4737,40 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Cargando billetera...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">El peso máximo de la transacción debe estar entre %d y %d.</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>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Solo se ha establecido la dirección, sin permisos: "%s"</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> @@ -4310,7 +4782,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> @@ -4341,8 +4817,20 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La sección [%s] no se reconoce.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">El firmante no se hizo eco de la dirección</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">El firmante se hizo eco de una dirección inesperada %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">El firmante devolvió un error: %s</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> @@ -4369,8 +4857,20 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Iniciando subprocesos de red...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Error del sistema durante el vaciado:%s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Error del sistema al cargar un archivo de bloque externo: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Error del sistema al guardar el bloque en el disco: %s</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 +4878,27 @@ 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>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">No hay ningún ScriptPubKeyManager para esta direcció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 +4906,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 +4918,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,11 +4926,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> - </message> - <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">No se puede asignar memoria para -maxsigcachesize: "%s" MiB</translation> + <translation type="unfinished">Transacción demasiado grande</translation> </message> <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> @@ -4453,6 +4961,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,23 +4982,27 @@ 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> <translation type="unfinished">Se desconocen las nuevas reglas activadas (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opción no reconocida "%s" proporcionada en -test=<option>.</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 +5010,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 puede agregar la transacción solo de observació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_MX.ts b/src/qt/locale/bitcoin_es_MX.ts index ee6865bbd7..c487b7b32f 100644 --- a/src/qt/locale/bitcoin_es_MX.ts +++ b/src/qt/locale/bitcoin_es_MX.ts @@ -3,11 +3,12 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">0xB006A7c1B9639BE87461Ee9 0xB006A7c1B9639BE87461Ee9</translation> + <translation type="unfinished">Right-click to edit address or label +Click-derecho para editar direccion o nivel</translation> </message> <message> <source>Create a new address</source> - <translation type="unfinished">0xB006A7c1B9639BE87461Ee9 0xB006A7c1B9639BE87461Ee9</translation> + <translation type="unfinished">Crea una nueva dirección </translation> </message> <message> <source>&New</source> @@ -15,7 +16,75 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Copiar la dirección actualmente seleccionada al portapapeles del sistema</translation> + <translation type="unfinished">Copie la direccion seleccionada actualmente en el portapapeles del sistema</translation> + </message> + <message> + <source>&Copy</source> + <translation type="unfinished">&copia</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation type="unfinished">Borre la direccion seleccionada actualmente de la lista</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation type="unfinished">introduzca la 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 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">&Borrar</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation type="unfinished">Escoja la direccion a la que va enviar monedas tambien</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation type="unfinished">Eliga la direccion para recibir monedas con</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">Esta es tu direccion para enviar pagos con Bitcoin. Siempre revisa la cantidad y la direccion correcta de monedas antes de enviar.</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">Esta es la direccion de Bitcoin para recibir pagos. Usa el botton ‘Crea nueva direccion de pagos’ en la pestaña crear nueva direccion. +la entrada solo es posible con las direcciones del tipo ‘legacy’</translation> + </message> + <message> + <source>&Copy Address</source> + <translation type="unfinished">&Copiar dirección </translation> + </message> + <message> + <source>Copy &Label</source> + <translation type="unfinished">Copiar &Etiqueta</translation> + </message> + <message> + <source>&Edit</source> + <translation type="unfinished">&Editar </translation> + </message> + <message> + <source>Export Address List</source> + <translation type="unfinished">Exportar la lista de direccion</translation> + </message> + <message> + <source>Comma separated file</source> + <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment> + <translation type="unfinished">Archivo separado de 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">Se ha producido un error al intentar guardar la lista de direcciones en %1. Por favor, inténtelo de nuevo.</translation> </message> <message> <source>Sending addresses - %1</source> @@ -23,25 +92,100 @@ </message> <message> <source>Receiving addresses - %1</source> - <translation type="unfinished">Recepción de direcciones - %1</translation> + <translation type="unfinished">Recibiendo direcciones - %1</translation> </message> - </context> + <message> + <source>Exporting Failed</source> + <translation type="unfinished">Error en la transportación.</translation> + </message> +</context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation type="unfinished">Etiqueta.</translation> + </message> + <message> + <source>Address</source> + <translation type="unfinished">Dirección </translation> + </message> + <message> + <source>(no label)</source> + <translation type="unfinished">(Sin etiqueta)</translation> + </message> +</context> <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">Introduzca la frase de contraseña</translation> + </message> + <message> + <source>New passphrase</source> + <translation type="unfinished">Nueva frase de contraseña</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation type="unfinished">Repetir nueva frase de contraseña</translation> + </message> + <message> + <source>Show passphrase</source> + <translation type="unfinished">Mostrar frase de contraseña</translation> + </message> + <message> <source>Encrypt wallet</source> - <translation type="unfinished">Encrypt wallet jesus daniel</translation> + <translation type="unfinished">cartera encriptada</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation type="unfinished">Esta operación necesita la frase de contraseña de su billetera para desbloquear la billetera.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation type="unfinished">Cartera desbloqueda</translation> + </message> + <message> + <source>Change passphrase</source> + <translation type="unfinished">Cambiar frase de contraseña</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation type="unfinished">Confirmar el cifrado de la cartera</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">Advertencia: Si cifras tu billetera y pierdes tu frase de contraseña,podrias 1 PERDER TODS TUS BITCOINS 1 !</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation type="unfinished">¿Estás seguro de que quieres cifrar tu cartera?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation type="unfinished">Cartera encriptada</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation type="unfinished">Introduzca la frase de contraseña antigua y la nueva frase de contraseña para la cartera.</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Atrás</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">Recuerde que el cifrado de su billetera no puede proteger completamente sus bitcoins de ser robados por el malware que infecta su ordenador.</translation> </message> </context> <context> <name>QObject</name> <message> - <source>Default system font "%1"</source> - <translation type="unfinished">Fuente predeterminada del sistema "%1"</translation> - </message> - <message> - <source>Custom…</source> - <translation type="unfinished">Personalizada...</translation> + <source>%1 didn't yet exit safely…</source> + <translation type="unfinished">%1 todavía no ha terminado de forma segura...</translation> </message> <message numerus="yes"> <source>%n second(s)</source> @@ -85,33 +229,160 @@ <numerusform>%n year(s)</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">billetera por defecto</translation> + </message> +</context> <context> <name>BitcoinGUI</name> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation type="unfinished">Cambiar la contraseña usada para la encriptación de la cartera</translation> + </message> + <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&Encriptar billetera…</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation type="unfinished">Cifre las claves privadas que pertenecen a su 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 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">Firme mensajes con sus direcciones de Bitcoin para demostrar que los posee</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">Verifique los mensajes para asegurarse de que se firmaron con direcciones de Bitcoin especificadas.</translation> + </message> + <message> + <source>&Load PSBT from file…</source> + <translation type="unfinished">&Cargar PSBT desde el archivo...</translation> + </message> + <message> + <source>Open &URI…</source> + <translation type="unfinished">Abrir &URI…</translation> + </message> + <message> + <source>Close Wallet…</source> + <translation type="unfinished">Cerrar Billetera</translation> + </message> + <message> + <source>Create Wallet…</source> + <translation type="unfinished">Crear Billetera</translation> + </message> + <message> + <source>Close All Wallets…</source> + <translation type="unfinished">Cerrar todas las carteras</translation> + </message> + <message> + <source>&File</source> + <translation type="unfinished">&Archivo</translation> + </message> + <message> + <source>&Settings</source> + <translation type="unfinished">&Configuraciones</translation> + </message> + <message> + <source>&Help</source> + <translation type="unfinished">&Ayuda</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation type="unfinished">Pestañas</translation> + </message> + <message> + <source>Syncing Headers (%1%)…</source> + <translation type="unfinished">Sincronizando cabeceras (%1%) ...</translation> + </message> + <message> + <source>Synchronizing with network…</source> + <translation type="unfinished">Sincronizando con la red...</translation> + </message> + <message> + <source>Indexing blocks on disk…</source> + <translation type="unfinished">Indexando bloques en disco...</translation> + </message> + <message> + <source>Processing blocks on disk…</source> + <translation type="unfinished">Procesando bloques en disco...</translation> + </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>Processed %n block(s) of transaction history.</numerusform> - <numerusform>Processed %n block(s) of transaction history.</numerusform> + <numerusform>%n bloque procesado del historial de transacciones.</numerusform> + <numerusform>%n bloques procesados del historial de transacciones.</numerusform> </translation> </message> <message> - <source>Migrate Wallet</source> - <translation type="unfinished">Migrar billetera</translation> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Cargar PSBT desde el &portapapeles...</translation> + </message> + <message> + <source>Open Wallet</source> + <translation type="unfinished">Abrir Cartera</translation> + </message> + <message> + <source>Open a wallet</source> + <translation type="unfinished">Abrir una cartera</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Cerrar cartera</translation> </message> <message> - <source>Migrate a wallet</source> - <translation type="unfinished">Migrar una billetera</translation> + <source>Restore Wallet…</source> + <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> + <translation type="unfinished">Restaurar billetera…</translation> + </message> + <message> + <source>Restore a wallet from a backup file</source> + <extracomment>Status tip for Restore Wallet menu item</extracomment> + <translation type="unfinished">Restaurar una billetera desde un archivo de copia de seguridad</translation> + </message> + <message> + <source>No wallets available</source> + <translation type="unfinished">Monederos no disponibles</translation> + </message> + <message> + <source>Wallet Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Datos del monedero </translation> </message> <message> <source>Load Wallet Backup</source> <extracomment>The title for Restore Wallet File Windows</extracomment> - <translation type="unfinished">Cargar copia de seguridad de billetera</translation> + <translation type="unfinished">Cargar copia de seguridad del monedero</translation> + </message> + <message> + <source>Wallet Name</source> + <extracomment>Label of the input field where the name of the wallet is entered.</extracomment> + <translation type="unfinished">Nombre de la billetera </translation> </message> <message> - <source>Restore Wallet</source> - <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment> - <translation type="unfinished">Restaurar billetera</translation> + <source>&Window</source> + <translation type="unfinished">&Ventana</translation> + </message> + <message> + <source>Main Window</source> + <translation type="unfinished">Ventana principal</translation> </message> <message> <source>&Hide</source> @@ -119,7 +390,7 @@ </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> @@ -130,157 +401,127 @@ </translation> </message> <message> - <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Presincronizando encabezados (%1%)...</translation> + <source>Click for more actions.</source> + <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> + <translation type="unfinished">Haz clic para ver más acciones.</translation> </message> <message> - <source>Error creating wallet</source> - <translation type="unfinished">Error al crear billetera</translation> + <source>Show Peers tab</source> + <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment> + <translation type="unfinished">Mostrar pestaña de pares</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> + <source>Disable network activity</source> + <extracomment>A context menu item.</extracomment> + <translation type="unfinished">Desactivar la actividad de la red</translation> </message> <message> - <source>Warning: %1</source> - <translation type="unfinished">Advertencia: %1</translation> + <source>Enable network activity</source> + <extracomment>A context menu item. The network activity was disabled previously.</extracomment> + <translation type="unfinished">Habilitar actividad de red</translation> </message> <message> - <source>Date: %1 -</source> - <translation type="unfinished">Fecha: %1 -</translation> + <source>Pre-syncing Headers (%1%)…</source> + <translation type="unfinished">Presincronizando cabeceras (%1%)...</translation> </message> <message> - <source>Amount: %1 -</source> - <translation type="unfinished">Importe: %1 -</translation> + <source>Private key <b>disabled</b></source> + <translation type="unfinished">Clave privada <b>deshabilitada</b></translation> </message> + </context> +<context> + <name>CoinControlDialog</name> <message> - <source>Wallet: %1 -</source> - <translation type="unfinished">Billetera: %1 -</translation> + <source>After Fee:</source> + <translation type="unfinished">Después de la comisión:</translation> </message> <message> - <source>Type: %1 -</source> - <translation type="unfinished">Tipo: %1 -</translation> + <source>Change:</source> + <translation type="unfinished">Cambio:</translation> </message> <message> - <source>Label: %1 -</source> - <translation type="unfinished">Etiqueta: %1 -</translation> + <source>(un)select all</source> + <translation type="unfinished">(des)marcar todos</translation> </message> <message> - <source>Address: %1 -</source> - <translation type="unfinished">Dirección: %1 -</translation> + <source>Tree mode</source> + <translation type="unfinished">Modo arbol</translation> </message> <message> - <source>Sent transaction</source> - <translation type="unfinished">Transacción enviada</translation> + <source>List mode</source> + <translation type="unfinished">Modo de lista</translation> </message> <message> - <source>Incoming transaction</source> - <translation type="unfinished">Transacción recibida</translation> + <source>Amount</source> + <translation type="unfinished">Importe</translation> </message> <message> - <source>Private key <b>disabled</b></source> - <translation type="unfinished">Clave privada <b>deshabilitada</b></translation> + <source>Received with label</source> + <translation type="unfinished">Recibido con etiqueta</translation> </message> <message> - <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">La billetera está <b>cifrada</b> y actualmente <b>desbloqueda</b></translation> + <source>Received with address</source> + <translation type="unfinished">Recibido con etiqueta</translation> </message> <message> - <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">La billetera está <b>cifrada</b> y actualmente <b>bloqueda</b></translation> - </message> - </context> -<context> - <name>CoinControlDialog</name> - <message> - <source>Coin Selection</source> - <translation type="unfinished">Selección de monedas</translation> - </message> - <message> - <source>Quantity:</source> - <translation type="unfinished">Cantidad:</translation> + <source>Date</source> + <translation type="unfinished">Fecha</translation> </message> <message> - <source>Amount:</source> - <translation type="unfinished">Importe:</translation> + <source>Confirmations</source> + <translation type="unfinished">Confirmaciones</translation> </message> <message> - <source>Fee:</source> - <translation type="unfinished">Comisión:</translation> + <source>Confirmed</source> + <translation type="unfinished">Confirmada</translation> </message> - </context> -<context> - <name>MigrateWalletActivity</name> <message> - <source>Migrate wallet</source> - <translation type="unfinished">Migrar billetera</translation> + <source>Copy amount</source> + <translation type="unfinished">Copiar importe</translation> </message> <message> - <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> - <translation type="unfinished">Are you sure you wish to close the wallet <i>%1</i>?</translation> + <source>&Copy address</source> + <translation type="unfinished">&Copiar dirección</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">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. - -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> + <source>Copy &label</source> + <translation type="unfinished">Copiar &etiqueta</translation> </message> <message> - <source>Migrate Wallet</source> - <translation type="unfinished">Migrar billetera</translation> + <source>Copy &amount</source> + <translation type="unfinished">Copiar &importe</translation> </message> <message> - <source>Migrating Wallet <b>%1</b>…</source> - <translation type="unfinished">Migrando billetera <b>%1</b>…</translation> + <source>Copy transaction &ID and output index</source> + <translation type="unfinished">Copiar &identificador de transacción e índice de salidas</translation> </message> <message> - <source>The wallet '%1' was migrated successfully.</source> - <translation type="unfinished">La migración de la billetera "%1" se realizó correctamente.</translation> + <source>L&ock unspent</source> + <translation type="unfinished">&Bloquear importe no gastado</translation> </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> + <source>&Unlock unspent</source> + <translation type="unfinished">&Desbloquear importe no gastado</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> + <source>Copy quantity</source> + <translation type="unfinished">Copiar cantidad</translation> </message> <message> - <source>Migration failed</source> - <translation type="unfinished">Migración errónea</translation> + <source>Copy fee</source> + <translation type="unfinished">Tarifa de copia</translation> </message> <message> - <source>Migration Successful</source> - <translation type="unfinished">Migración correcta</translation> + <source>Copy after fee</source> + <translation type="unfinished">Copiar después de la tarifa</translation> </message> -</context> -<context> - <name>CreateWalletDialog</name> <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> + <source>Copy bytes</source> + <translation type="unfinished">Copiar bytes</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> + <source>Copy change</source> + <translation type="unfinished">Copiar cambio</translation> </message> </context> <context> @@ -316,66 +557,48 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> </context> <context> - <name>OptionsDialog</name> - <message> - <source>Font in the Overview tab: </source> - <translation type="unfinished">Fuente en la pestaña Resumen:</translation> - </message> - </context> -<context> - <name>PSBTOperationsDialog</name> - <message> - <source>Sends %1 to %2</source> - <translation type="unfinished">Envía %1 a %2</translation> - </message> - </context> -<context> <name>RPCConsole</name> <message> - <source>The transport layer version: %1</source> - <translation type="unfinished">Versión de la capa de transporte: %1</translation> - </message> - <message> - <source>Transport</source> - <translation type="unfinished">Transporte</translation> + <source>Local Addresses</source> + <translation type="unfinished">Direcciones locales</translation> </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> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Direcciones de red que tu nodo Bitcoin usa actualmente para comunicarse con otros nodos.</translation> </message> <message> - <source>Session ID</source> - <translation type="unfinished">Identificador de sesión</translation> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalles de pares</translation> </message> <message> - <source>detecting: peer could be v1 or v2</source> - <extracomment>Explanatory text for "detecting" transport type.</extracomment> - <translation type="unfinished">Detectando: el par puede ser v1 o v2</translation> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">La cadena del identificador de sesión BIP324 en formato hexadecimal.</translation> </message> + </context> +<context> + <name>RecentRequestsTableModel</name> <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> + <source>Label</source> + <translation type="unfinished">Etiqueta.</translation> </message> + </context> +<context> + <name>SendCoinsDialog</name> <message> - <source>v2: BIP324 encrypted transport protocol</source> - <extracomment>Explanatory text for v2 transport type.</extracomment> - <translation type="unfinished">v2: protocolo de transporte encriptado BIP324</translation> + <source>Copy quantity</source> + <translation type="unfinished">Copiar cantidad</translation> </message> <message> - <source>Node window - [%1]</source> - <translation type="unfinished">Ventana de nodo - [%1]</translation> + <source>Copy amount</source> + <translation type="unfinished">Copiar importe</translation> </message> - </context> -<context> - <name>SendCoinsDialog</name> <message> - <source>Quantity:</source> - <translation type="unfinished">Cantidad:</translation> + <source>Copy after fee</source> + <translation type="unfinished">Copiar después de la tarifa</translation> </message> <message> - <source>%1 from wallet '%2'</source> - <translation type="unfinished">%1 desde monedero '%2'</translation> + <source>Copy change</source> + <translation type="unfinished">Copiar cambio</translation> </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> @@ -386,6 +609,17 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> </context> <context> + <name>SignVerifyMessageDialog</name> + <message> + <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">Puedes firmar mensajes o acuerdos con tus direcciones tipo legacy (P2PKH) 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 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">La dirección ingresada no se refiere a una clave tipo legacy (P2PKH). La firma de mensajes para direcciones SegWit y de otros tipos que no sean P2PKH no es compatible con esta versión de %1. Comprueba la dirección e inténtalo de nuevo.</translation> + </message> + </context> +<context> <name>TransactionDesc</name> <message numerus="yes"> <source>matures in %n more block(s)</source> @@ -395,64 +629,187 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </translation> </message> <message> - <source>%1 (Certificate was not verified)</source> - <translation type="unfinished">%1 (El certificado no fue verificado)</translation> + <source>Amount</source> + <translation type="unfinished">Importe</translation> + </message> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Label</source> + <translation type="unfinished">Etiqueta.</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Comma separated file</source> + <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment> + <translation type="unfinished">Archivo separado de comas</translation> + </message> + <message> + <source>Label</source> + <translation type="unfinished">Etiqueta.</translation> + </message> + <message> + <source>Address</source> + <translation type="unfinished">Dirección </translation> + </message> + <message> + <source>Exporting Failed</source> + <translation type="unfinished">Error en la transportación.</translation> + </message> + </context> +<context> + <name>WalletModel</name> + <message> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">TBPF con incremento de comisión copiada en el portapapeles</translation> + </message> + <message> + <source>Signer error</source> + <translation type="unfinished">Error de firmante</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 los datos de la pestaña actual a un archivo</translation> + </message> + <message> + <source>Wallet Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Datos del monedero </translation> </message> </context> <context> <name>bitcoin-core</name> <message> - <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> - <translation type="unfinished">No se pudo calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">No se ha podido eliminar la instantánea chainstate dir (%s). Elimínala manualmente antes de reiniciar. +</translation> + </message> + <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el volcado del archivo de bloques al disco. Es probable que se deba a un error de E/O.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Ha fallado el volcado del archivo para deshacer al disco. Es probable que se deba a un error de E/O.</translation> + </message> + <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">El peso máximo de la transacción es menor que el peso de la transacción sin entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">El peso máximo de la transacción es demasiado bajo, por lo que no puede incluir la salida de cambio.</translation> + </message> + <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Ha fallado el cambio de nombre de ''%s" a ''%s". No se puede limpiar el directorio leveldb del estado de la cadena de fondo.</translation> + </message> + <message> + <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">La combinación de las entradas preseleccionadas y la selección automática de entradas del monedero supera el peso máximo de la transacción. Intenta enviar un importe menor o consolidar manualmente las UTXO del monedero.</translation> + </message> + <message> + <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">La fecha y la hora del ordenador parecen estar más de %d minutos desincronizadas con la red, lo que puede producir un fallo de consenso. Después de confirmar el reloj del ordenador, este mensaje debería dejar de aparecer cuando reinicies el nodo. Sin reiniciar, debería dejar de mostrarse automáticamente después de que te hayas conectado a un número suficiente de nuevos pares salientes, lo que puede llevar cierto tiempo. Puedes inspeccionar el campo "timeoffset" de los métodos RPC "getpeerinfo" y "getnetworkinfo" para obtener más información.</translation> + </message> + <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind solo puede utilizarse para conexiones entrantes (se ha pasado "out")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para obtener más información:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">No se han encontrado datos assumeutxo para el blockhash indicado "%s".</translation> + </message> + <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Se ha encontrado un bloque corrupto que indica un posible fallo del hardware.</translation> + </message> + <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fallo en la prueba de cordura de la criptografía de curva elíptica. %s se apagará.</translation> + </message> + <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">No se ha podido conectar el mejor bloque (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">No se ha podido desconectar el bloque.</translation> + </message> + <message> + <source>Failed to read block.</source> + <translation type="unfinished">No se ha podido leer el bloque.</translation> + </message> + <message> + <source>Failed to write block.</source> + <translation type="unfinished">No se ha podido escribir el bloque.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Error al escribir en la base de datos del índice de bloques.</translation> </message> <message> - <source>Error committing db txn for wallet transactions removal</source> - <translation type="unfinished">Error al confirmar db txn para eliminar transacciones de billetera</translation> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Error al escribir en la base de datos de monedas.</translation> </message> <message> - <source>Error starting db txn for wallet transactions removal</source> - <translation type="unfinished">Error al iniciar db txn para eliminar transacciones de billetera</translation> + <source>Failed to write undo data.</source> + <translation type="unfinished">Error al escribir datos para deshacer.</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> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">El peso máximo de la transacción debe estar entre %d y %d.</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> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Solo se ha establecido la dirección, sin permisos: "%s"</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> + <source>Signer did not echo address</source> + <translation type="unfinished">El firmante no se hizo eco de la direcció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> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">El firmante se hizo eco de una dirección inesperada %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> + <source>Signer returned error: %s</source> + <translation type="unfinished">El firmante ha devuelto un error: %s</translation> </message> <message> - <source>Failure removing transaction: %s</source> - <translation type="unfinished">Error al eliminar la transacción: 1%s</translation> + <source>System error while flushing: %s</source> + <translation type="unfinished">Error del sistema durante el vaciado:%s</translation> </message> <message> - <source>Transaction %s does not belong to this wallet</source> - <translation type="unfinished">La transacción %s no pertenece a esta billetera</translation> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Error del sistema al cargar un archivo de bloque externo: %s</translation> </message> <message> - <source>Wallet file creation failed: %s</source> - <translation type="unfinished">Creación errónea del fichero monedero: %s</translation> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Error del sistema al guardar el bloque en el disco: %s</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> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">No hay ningún ScriptPubKeyManager para esta direcció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> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opción no reconocida "%s" proporcionada en -test=<option>.</translation> </message> </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_es_SV.ts b/src/qt/locale/bitcoin_es_SV.ts index 2edd75a5da..75fe65e2b2 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 en 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,63 +169,75 @@ 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>Continue</source> + <translation type="unfinished">Continuar</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Atrás</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> - <translation type="unfinished">La frase de contraseña ingresada para el descifrado de 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 . Si esto tiene éxito, establece una nueva frase de contraseña para evitar este problema en el futuro.</translation> + <translation type="unfinished">La frase de contraseña ingresada para el descifrado de 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 . Si esto es correcto, establece una nueva frase de contraseña para evitar este problema en el futuro.</translation> </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,23 +247,35 @@ 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> <name>BitcoinApplication</name> <message> <source>Settings file %1 might be corrupt or invalid.</source> - <translation type="unfinished">El archivo de configuración %1 puede estar corrupto o no ser válido.</translation> + <translation type="unfinished">El archivo de configuración %1 puede estar dañado 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 +283,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 +296,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 se cerró 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 +320,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 +338,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 +348,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 +356,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,28 +405,93 @@ 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> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">billetera por defecto</translation> + </message> +</context> <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> @@ -395,27 +503,35 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </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 llaves privadas que pertenecen a tu 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> + <translation type="unfinished">&Cambiar 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 un mensaje para provar que usted es dueño de esta dirección</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> + <source>&Verify message…</source> + <translation type="unfinished">&Verificar mensaje...</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar PSBT desde archivo...</translation> + <translation type="unfinished">&Cargar TBPF desde el archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -423,31 +539,23 @@ 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> - </message> - <message> - <source>&File</source> - <translation type="unfinished">&Archivo</translation> - </message> - <message> - <source>&Settings</source> - <translation type="unfinished">&Configuración</translation> + <translation type="unfinished">Cerrar todas las billeteras...</translation> </message> <message> - <source>Tabs toolbar</source> - <translation type="unfinished">Barra de pestañas</translation> + <source>&Help</source> + <translation type="unfinished">A&yuda</translation> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Sincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Sincronizando cabeceras (1%1%)</translation> </message> <message> <source>Synchronizing with network…</source> @@ -463,31 +571,29 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">Conectando a pares...</translation> + <translation type="unfinished">Conectando con pares...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished"> -Solicitar pagos (genera códigos QR y bitcoin: URI) - </translation> + <translation type="unfinished">Solicitar pagos (genera código QR y URI's de Bitcoin)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Mostrar la lista de direcciones y etiquetas de envío usadas</translation> + <translation type="unfinished">Editar la lista de las direcciones y etiquetas almacenadas</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Mostrar la lista de direcciones y etiquetas de recepción usadas</translation> + <translation type="unfinished">Muestra la lista de direcciones de recepción y etiquetas</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>%n bloque procesado del historial de transacciones.</numerusform> + <numerusform>%n bloques procesados del historial de transacciones.</numerusform> </translation> </message> <message> @@ -495,20 +601,20 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation type="unfinished">Poniéndose al día...</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> + <source>Last received block was generated %1 ago.</source> + <translation type="unfinished">El último bloque recibido fue generado hace %1</translation> </message> <message> - <source>Warning</source> - <translation type="unfinished">Aviso</translation> + <source>Transactions after this will not yet be visible.</source> + <translation type="unfinished">Las transacciones posteriores aún no son visibles.</translation> </message> <message> - <source>Information</source> - <translation type="unfinished">Información </translation> + <source>Warning</source> + <translation type="unfinished">Advertencia</translation> </message> <message> <source>Up to date</source> - <translation type="unfinished">Actualizado al dia </translation> + <translation type="unfinished">Actualizado al día </translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> @@ -516,35 +622,39 @@ 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> - </message> - <message> - <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el portapapeles</translation> + <translation type="unfinished">Cargar TBPF desde el &portapapeles...</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> - <translation type="unfinished">&Direcciones de envío</translation> + <translation type="unfinished">Direcciones de &envío</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">Direcciones de &recepción</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Bitcoin: abrir URI</translation> + <translation type="unfinished">Abrir un bitcoin: URI</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 cartera</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Cerrar cartera</translation> </message> <message> <source>Restore Wallet…</source> @@ -558,7 +668,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 +679,8 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation type="unfinished">Migrar una billetera</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> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</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,15 +700,19 @@ 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>Main Window</source> + <translation type="unfinished">Ventana principal</translation> + </message> + <message> <source>%1 client</source> - <translation type="unfinished">%1 cliente</translation> + <translation type="unfinished">Cliente %1 </translation> </message> <message> <source>&Hide</source> @@ -618,20 +720,20 @@ 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 conexiónes activas con la red de Bitcoin.</numerusform> </translation> </message> <message> <source>Click for more actions.</source> <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> - <translation type="unfinished">Hacer clic para ver más acciones.</translation> + <translation type="unfinished">Haz clic para ver más acciones.</translation> </message> <message> <source>Show Peers tab</source> @@ -650,7 +752,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Presincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Presincronizando cabeceras (%1%)...</translation> </message> <message> <source>Error creating wallet</source> @@ -658,7 +760,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 +793,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 +808,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 +816,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 +824,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 +839,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,14 +865,42 @@ 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 arbol</translation> + </message> + <message> + <source>List mode</source> + <translation type="unfinished">Modo de lista</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Monto</translation> </message> <message> + <source>Received with label</source> + <translation type="unfinished">Recibido con etiqueta</translation> + </message> + <message> <source>Received with address</source> <translation type="unfinished">Recibido con etiqueta</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> @@ -815,6 +945,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation type="unfinished">Copiar después de la tarifa</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> <translation type="unfinished">(%1 bloqueado)</translation> </message> @@ -830,10 +968,19 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <source>change from %1 (%2)</source> <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> @@ -860,12 +1007,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 +1023,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 +1032,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 +1051,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 +1069,22 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <context> <name>OpenWalletActivity</name> <message> - <source>Open wallet warning</source> - <translation type="unfinished">Advertencia sobre crear monedero</translation> + <source>Open wallet failed</source> + <translation type="unfinished">Fallo al abrir billetera</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <source>Open wallet warning</source> + <translation type="unfinished">Advertencia al abrir billetera</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 +1092,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 +1118,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 +1182,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 +1203,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 +1269,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 +1296,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 +1312,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án al menos %1 GB de datos en este directorio, que aumentarán 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án aproximadamente %1 GB de datos en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1130,23 +1333,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 +1369,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 +1396,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 +1414,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 +1488,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 +1513,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 +1548,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 +1567,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 +1576,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 +1590,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 +1598,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 +1616,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 +1633,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 +1648,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 +1689,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 +1713,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 +1729,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 +1745,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 +1763,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 +1773,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 +1788,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 +1800,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 +1826,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 +1838,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 +1846,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 +1862,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 +1878,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 +1921,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 +1932,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 +1970,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 +1978,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 +1998,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 +2036,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 +2079,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 +2119,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 +2129,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 +2161,28 @@ 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>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> + <source>Datadir</source> + <translation type="unfinished">Directorio de datos</translation> </message> <message> - <source>Blocksdir</source> - <translation type="unfinished">Bloques dir</translation> + <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, usa la opción "%1".</translation> </message> <message> <source>To specify a non-default location of the blocks directory use the '%1' option.</source> - <translation type="unfinished">Para especificar una localización personalizada del directorio de bloques, usa la opción «%1». </translation> + <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> @@ -1814,24 +2197,40 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Número de conexiones</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Direcciones locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Direcciones de red que tu nodo Bitcoin usa actualmente para comunicarse con otros nodos.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Cadena de bloques</translation> </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 +2238,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> @@ -1854,6 +2253,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Selecciona un par para ver la información detallada.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalles de pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versión de la capa de transporte: %1</translation> </message> @@ -1862,14 +2265,14 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Transporte</translation> </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> - </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 +2282,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 +2312,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 +2332,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 +2340,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 +2348,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> @@ -1956,8 +2371,12 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Dirección/Tipo</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">La cadena del identificador de sesión BIP324 en formato hexadecimal.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> - <translation type="unfinished">El protocolo de red 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 +2384,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 +2413,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 +2449,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 +2457,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 +2469,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 +2494,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 +2509,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 +2526,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,35 +2534,55 @@ 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> <translation type="unfinished">Actividad de red desactivada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ninguno</translation> + </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 +2591,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 +2614,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 +2626,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 +2644,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 +2677,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 +2744,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 +2759,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 +2792,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 +2831,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 +2846,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 +2873,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 +2914,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 +2946,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 +2978,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,33 +2990,53 @@ 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> </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> <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> @@ -2492,17 +3048,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 +3072,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 +3084,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 +3103,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 +3150,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 +3158,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 +3204,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 +3220,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 +3235,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 adjunto al URI de tipo "bitcoin:" 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 +3274,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> + <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">Puedes firmar mensajes o acuerdos con tus direcciones tipo legacy (P2PKH) 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 +3297,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 +3310,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 +3342,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 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">La dirección ingresada no se refiere a una clave tipo legacy (P2PKH). La firma de mensajes para direcciones SegWit y de otros tipos que no sean P2PKH no es compatible con esta versión de %1. Comprueba la dirección e inténtalo 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> + <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 +3398,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 +3454,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> + <translation type="unfinished">Origen</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 +3512,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 +3545,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 +3553,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 +3561,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> @@ -2921,35 +3587,59 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <message> + <source>Details for %1</source> + <translation type="unfinished">Detalles para %1</translation> </message> - </context> +</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 +3647,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 +3659,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 +3701,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 +3718,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 +3734,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 +3742,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 +3766,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 +3811,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 +3866,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 +3902,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,43 +3935,46 @@ 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> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiada al portapapeles</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">TBPF con incremento de comisión copiada en el portapapeles</translation> </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> <translation type="unfinished">No se pudo confirmar la transacción</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">No se puede mostrar la dirección</translation> + <source>Signer error</source> + <translation type="unfinished">Error de firmante</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <source>Can't display address</source> + <translation type="unfinished">No se puede mostrar la dirección</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 +3987,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 +4010,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 +4025,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 +4037,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 +4074,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,25 +4082,25 @@ 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> - </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">Verifica que la fecha y hora de la computadora sean correctas. Si el reloj está mal configurado, %s no funcionará correctamente.</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 contribute if you find %s useful. Visit %s for further information about the software.</source> <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 +4110,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 +4122,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 +4138,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 +4170,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 +4182,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,19 +4194,15 @@ 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> <translation type="unfinished">-maxmempool debe ser por lo menos de %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ocurrió un error interno grave. Consulta debug.log para obtener más información.</translation> - </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> @@ -3444,10 +4213,6 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se puede establecer -peerblockfilters sin -blockfilterindex.</translation> </message> <message> - <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">No se puede escribir en el directorio de datos "%s"; comprueba los permisos.</translation> - </message> - <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> <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> @@ -3461,7 +4226,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> @@ -3480,6 +4245,12 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se pudo calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">No se pudo eliminar la instantánea chainstate dir (%s). Elimínala manualmente antes de reiniciar. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">No se pudo cambiar el nombre del archivo peers.dat inválido. Muévelo o elimínalo, e intenta de nuevo.</translation> </message> @@ -3488,6 +4259,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Error al calcular la comisión. La opción "fallbackfee" está desactivada. Espera algunos bloques o activa %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falló el volcado del archivo de bloques al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falló el volcado del archivo para deshacer al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Opciones incompatibles: -dnsseed=1 se especificó explícitamente, pero -onlynet prohíbe conexiones a IPv4/IPv6.</translation> </message> @@ -3496,6 +4275,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Importe inválido para %s=<amount>: "%s" (debe ser al menos la comisión mínima de retransmisión de %s para evitar transacciones atascadas)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">El peso máximo de la transacción es menor que el peso de la transacción sin entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">El peso máximo de la transacción es demasiado bajo, por lo que no puede incluir la salida de cambio.</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Las conexiones salientes están restringidas a CJDNS (-onlynet=cjdns), pero no se proporciona -cjdnsreachable</translation> </message> @@ -3512,12 +4299,20 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Las conexiones salientes están restringidas a i2p (-onlynet=i2p), pero no se proporciona -i2psam</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Falló el cambio de nombre de ''%s" a ''%s". No se puede limpiar el directorio leveldb del estado de la cadena de fondo.</translation> + </message> + <message> + <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">La combinación de las entradas preseleccionadas y la selección automática de entradas de la billetera supera el peso máximo de la transacción. Intenta enviar un importe menor o consolidar manualmente las UTXO de la billetera.</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">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 +4324,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> @@ -3554,6 +4349,10 @@ Intenta ejecutar la última versión del software. </translation> </message> <message> + <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">La fecha y la hora de la computadora parecen estar más de %d minutos desincronizadas con la red, lo que puede producir un fallo de consenso. Después de confirmar el reloj de la computadora, este mensaje debería dejar de aparecer cuando reinicies el nodo. Sin reiniciar, debería dejar de mostrarse automáticamente después de que te hayas conectado a un número suficiente de nuevos pares salientes, lo que puede llevar cierto tiempo. Puedes inspeccionar el campo "timeoffset" de los métodos RPC "getpeerinfo" y "getnetworkinfo" para obtener más información.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -3566,10 +4365,38 @@ Unable to restore backup of wallet.</source> No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind solo puede utilizarse para conexiones entrantes (se ha pasado "out")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para obtener más información:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">No se encontraron datos assumeutxo para el blockhash indicado "%s".</translation> + </message> + <message> <source>Block verification was interrupted</source> <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>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Se encontró un bloque corrupto que indica un posible fallo del hardware.</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,10 +4409,22 @@ 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> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fallo en la prueba de cordura de la criptografía de curva elíptica. %s se apagará.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Error al confirmar db txn para eliminar transacciones de billetera</translation> </message> @@ -3594,16 +4433,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 +4482,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 +4502,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 +4526,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 +4546,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,36 +4558,67 @@ 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 connect best block (%s).</source> + <translation type="unfinished">No se pudo conectar el mejor bloque (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">No se pudo desconectar el bloque.</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 read block.</source> + <translation type="unfinished">No se pudo leer el bloque.</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> <translation type="unfinished">Fallo al verificar la base de datos</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">No se pudo escribir el bloque.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Error al escribir en la base de datos del índice de bloques.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Error al escribir en la base de datos de monedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Error al escribir datos para deshacer.</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 +4634,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 +4677,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 +4702,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> @@ -3807,24 +4713,40 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Cargando billetera...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">El peso máximo de la transacción debe estar entre %d y %d.</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>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Solo se ha establecido la dirección, sin permisos: "%s"</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> @@ -3836,7 +4758,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> @@ -3867,8 +4793,20 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La sección [%s] no se reconoce.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">El firmante no se hizo eco de la dirección</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">El firmante se hizo eco de una dirección inesperada %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">El firmante devolvió un error: %s</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> @@ -3895,8 +4833,20 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Iniciando subprocesos de red...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Error del sistema durante el vaciado:%s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Error del sistema al cargar un archivo de bloque externo: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Error del sistema al guardar el bloque en el disco: %s</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 +4854,27 @@ 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>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">No hay ningún ScriptPubKeyManager para esta direcció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 +4886,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 +4894,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> @@ -3943,10 +4905,6 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Transacción demasiado grande</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">No se puede asignar memoria para -maxsigcachesize: "%s" MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">No se puede establecer un enlace a %s en esta computadora (bind devolvió el error %s)</translation> </message> @@ -3979,6 +4937,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,23 +4958,27 @@ 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> <translation type="unfinished">Se desconocen las nuevas reglas activadas (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opción no reconocida "%s" proporcionada en -test=<option>.</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 +4986,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 puede agregar la transacción solo de observació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 +5010,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..5ffa866afd 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 en 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,55 +181,63 @@ 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>Continue</source> + <translation type="unfinished">Continuar</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Atrás</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> - <translation type="unfinished">La frase de contraseña ingresada para el descifrado de 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 . Si esto tiene éxito, establece una nueva frase de contraseña para evitar este problema en el futuro.</translation> + <translation type="unfinished">La frase de contraseña ingresada para el descifrado de 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 . Si esto es correcto, establece una nueva frase de contraseña para evitar este problema en el futuro.</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,25 +249,33 @@ 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> <name>BitcoinApplication</name> <message> <source>Settings file %1 might be corrupt or invalid.</source> - <translation type="unfinished">El archivo de configuración %1 puede estar corrupto o no ser válido.</translation> + <translation type="unfinished">El archivo de configuración %1 puede estar dañado 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 +283,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,17 +296,21 @@ 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> - <translation type="unfinished">%1 aún no salió de forma segura...</translation> + <translation type="unfinished">%1 aún no se cerró 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> <translation type="unfinished">Fuente predeterminada del sistema "%1"</translation> </message> @@ -300,11 +320,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 +338,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 +348,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> @@ -389,7 +409,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <numerusform>%n años</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">billetera por defecto</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -398,7 +422,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 +430,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 +438,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 +454,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 +469,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> @@ -459,27 +503,39 @@ 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>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 llaves privadas que pertenecen a tu 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> + <translation type="unfinished">&Cambiar 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> </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> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar PSBT desde archivo...</translation> + <translation type="unfinished">&Cargar TBPF desde el archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -487,15 +543,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> @@ -515,7 +571,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Sincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Sincronizando cabeceras (1%1%)</translation> </message> <message> <source>Synchronizing with network…</source> @@ -531,7 +587,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">Conectando a pares...</translation> + <translation type="unfinished">Conectando con pares...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> @@ -590,39 +646,39 @@ 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> - </message> - <message> - <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el portapapeles</translation> + <translation type="unfinished">Cargar TBPF desde el &portapapeles...</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> - <translation type="unfinished">&Direcciones de envío</translation> + <translation type="unfinished">Direcciones de &envío</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">Direcciones de &recepción</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Bitcoin: abrir URI</translation> + <translation type="unfinished">Abrir un bitcoin: URI</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 cartera</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 +692,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 +703,8 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <translation type="unfinished">Migrar una billetera</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> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</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,15 +724,19 @@ 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>Main Window</source> + <translation type="unfinished">Ventana principal</translation> + </message> + <message> <source>%1 client</source> - <translation type="unfinished">%1 cliente</translation> + <translation type="unfinished">Cliente %1 </translation> </message> <message> <source>&Hide</source> @@ -696,20 +744,20 @@ 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 conexiónes activas con la red de Bitcoin.</numerusform> </translation> </message> <message> <source>Click for more actions.</source> <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> - <translation type="unfinished">Hacer clic para ver más acciones.</translation> + <translation type="unfinished">Haz clic para ver más acciones.</translation> </message> <message> <source>Show Peers tab</source> @@ -728,7 +776,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">Presincronizando encabezados (%1%)...</translation> + <translation type="unfinished">Presincronizando cabeceras (%1%)...</translation> </message> <message> <source>Error creating wallet</source> @@ -736,7 +784,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 +817,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 +840,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 +848,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 +863,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,11 +878,11 @@ 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> @@ -902,7 +950,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">B&loquear no gastado</translation> </message> <message> <source>&Unlock unspent</source> @@ -952,6 +1000,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> @@ -978,12 +1031,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 +1056,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 +1075,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 +1093,22 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <context> <name>OpenWalletActivity</name> <message> - <source>Open wallet warning</source> - <translation type="unfinished">Advertencia sobre crear monedero</translation> + <source>Open wallet failed</source> + <translation type="unfinished">Fallo al abrir billetera</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <source>Open wallet warning</source> + <translation type="unfinished">Advertencia al abrir billetera</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 +1143,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 +1206,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 +1227,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 +1242,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 +1258,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 +1266,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 +1282,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 +1297,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 +1320,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 +1336,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án al menos %1 GB de datos en este directorio, que aumentarán 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án aproximadamente %1 GB de datos en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1272,27 +1357,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 +1393,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 +1416,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 +1498,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 +1512,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 +1537,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 +1565,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 +1591,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 +1600,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 +1609,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 +1626,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 +1640,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 +1657,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 +1672,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 +1697,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 +1717,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 +1757,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 +1787,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 +1802,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 +1812,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 +1824,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 +1846,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 +1862,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 +1870,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 +1886,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 +1902,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 +1957,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 +1981,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 +1994,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 +2002,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 +2014,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 +2026,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 +2048,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 +2060,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 +2077,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 +2103,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 +2143,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 +2153,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 +2190,23 @@ 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>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> + <source>Datadir</source> + <translation type="unfinished">Directorio de datos</translation> </message> <message> - <source>Blocksdir</source> - <translation type="unfinished">Bloques dir</translation> + <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, usa la opción "%1".</translation> </message> <message> <source>To specify a non-default location of the blocks directory use the '%1' option.</source> - <translation type="unfinished">Para especificar una 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> @@ -2040,24 +2221,40 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Número de conexiones</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Direcciones locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Direcciones de red que tu nodo Bitcoin usa actualmente para comunicarse con otros nodos.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Cadena de bloques</translation> </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 +2262,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> @@ -2080,6 +2277,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Selecciona un par para ver la información detallada.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalles de pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versión de la capa de transporte: %1</translation> </message> @@ -2088,14 +2289,14 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Transporte</translation> </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> - </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 +2306,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 +2336,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 +2356,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 +2364,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 +2372,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> @@ -2186,6 +2395,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">Dirección/Tipo</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">La cadena del identificador de sesión BIP324 en formato hexadecimal.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">El protocolo de red mediante el cual está conectado este par: IPv4, IPv6, Onion, I2P o CJDNS.</translation> </message> @@ -2195,13 +2408,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 +2437,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 +2473,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 +2489,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 +2533,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 +2550,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,35 +2558,55 @@ 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> <translation type="unfinished">Actividad de red desactivada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ninguno</translation> + </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 +2615,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 +2638,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 +2650,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 +2665,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 +2673,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 +2701,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 +2725,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 +2773,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 +2783,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 +2816,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 +2842,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 +2855,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 +2870,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 +2886,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 +2902,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 +2914,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 +2938,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 +2974,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> @@ -2747,22 +3033,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 +3072,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 +3096,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 +3108,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 +3127,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 +3140,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 +3174,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 +3182,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 +3228,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 +3240,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 +3276,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 adjunto al URI de tipo "bitcoin:" 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,31 +3298,31 @@ 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> </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> + <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">Puedes firmar mensajes o acuerdos con tus direcciones tipo legacy (P2PKH) 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 +3334,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 +3342,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 +3366,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 +3378,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> + <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">La dirección ingresada no se refiere a una clave tipo legacy (P2PKH). La firma de mensajes para direcciones SegWit y de otros tipos que no sean P2PKH no es compatible con esta versión de %1. Comprueba la dirección e inténtalo de nuevo.</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 +3422,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> + <message> + <source>Message verification failed.</source> + <translation type="unfinished">Falló la verificación del mensaje.</translation> </message> - </context> + <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 +3478,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> @@ -3146,7 +3490,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Source</source> - <translation type="unfinished">Fuente</translation> + <translation type="unfinished">Origen</translation> + </message> + <message> + <source>Generated</source> + <translation type="unfinished">Generado</translation> </message> <message> <source>From</source> @@ -3158,11 +3506,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 +3536,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 +3553,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 +3569,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 +3577,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 +3585,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> @@ -3231,14 +3611,22 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <message> + <source>Details for %1</source> + <translation type="unfinished">Detalles para %1</translation> </message> - </context> +</context> <context> <name>TransactionTableModel</name> <message> @@ -3254,16 +3642,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 +3671,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 +3683,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 +3725,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 +3742,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 +3758,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 +3766,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 +3790,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 +3832,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 +3855,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 +3868,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 +3890,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 +3899,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 +3926,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,28 +3963,27 @@ 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> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiada al portapapeles</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">TBPF con incremento de comisión copiada en el portapapeles</translation> </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> <translation type="unfinished">No se pudo confirmar la transacción</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">No se puede mostrar la dirección</translation> + <source>Signer error</source> + <translation type="unfinished">Error de firmante</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <source>Can't display address</source> + <translation type="unfinished">No se puede mostrar la dirección</translation> </message> </context> <context> @@ -3543,11 +3994,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 +4011,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 +4034,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 +4061,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 +4098,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> @@ -3662,16 +4117,16 @@ Ir a Archivo > Abrir billetera para cargar una. <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> - <translation type="unfinished">Verifica que la fecha y hora de la computadora sean correctas. Si el reloj está mal configurado, %s no funcionará correctamente.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <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 +4134,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 +4146,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 +4154,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 +4162,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 +4182,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 +4194,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 +4206,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,19 +4218,15 @@ 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> <translation type="unfinished">-maxmempool debe ser por lo menos de %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Ocurrió un error interno grave. Consulta debug.log para obtener más información.</translation> - </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> @@ -3786,12 +4237,8 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se puede establecer -peerblockfilters sin -blockfilterindex.</translation> </message> <message> - <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">No se puede escribir en el directorio de datos "%s"; comprueba los permisos.</translation> - </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 +4250,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> @@ -3822,6 +4269,12 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">No se pudo calcular la comisión de incremento porque las UTXO sin confirmar dependen de un grupo enorme de transacciones no confirmadas.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">No se pudo eliminar la instantánea chainstate dir (%s). Elimínala manualmente antes de reiniciar. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">No se pudo cambiar el nombre del archivo peers.dat inválido. Muévelo o elimínalo, e intenta de nuevo.</translation> </message> @@ -3830,6 +4283,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Error al calcular la comisión. La opción "fallbackfee" está desactivada. Espera algunos bloques o activa %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falló el volcado del archivo de bloques al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falló el volcado del archivo para deshacer al disco. Es probable que se deba a un error de E/S.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Opciones incompatibles: -dnsseed=1 se especificó explícitamente, pero -onlynet prohíbe conexiones a IPv4/IPv6.</translation> </message> @@ -3838,6 +4299,14 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Importe inválido para %s=<amount>: "%s" (debe ser al menos la comisión mínima de retransmisión de %s para evitar transacciones atascadas)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">El peso máximo de la transacción es menor que el peso de la transacción sin entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">El peso máximo de la transacción es demasiado bajo, por lo que no puede incluir la salida de cambio.</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Las conexiones salientes están restringidas a CJDNS (-onlynet=cjdns), pero no se proporciona -cjdnsreachable</translation> </message> @@ -3854,12 +4323,20 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Las conexiones salientes están restringidas a i2p (-onlynet=i2p), pero no se proporciona -i2psam</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Falló el cambio de nombre de ''%s" a ''%s". No se puede limpiar el directorio leveldb del estado de la cadena de fondo.</translation> + </message> + <message> + <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">La combinación de las entradas preseleccionadas y la selección automática de entradas de la billetera supera el peso máximo de la transacción. Intenta enviar un importe menor o consolidar manualmente las UTXO de la billetera.</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">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 +4344,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> @@ -3896,6 +4373,10 @@ Intenta ejecutar la última versión del software. </translation> </message> <message> + <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">La fecha y la hora de la computadora parecen estar más de %d minutos desincronizadas con la red, lo que puede producir un fallo de consenso. Después de confirmar el reloj de la computadora, este mensaje debería dejar de aparecer cuando reinicies el nodo. Sin reiniciar, debería dejar de mostrarse automáticamente después de que te hayas conectado a un número suficiente de nuevos pares salientes, lo que puede llevar cierto tiempo. Puedes inspeccionar el campo "timeoffset" de los métodos RPC "getpeerinfo" y "getnetworkinfo" para obtener más información.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -3908,12 +4389,36 @@ Unable to restore backup of wallet.</source> No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind solo puede utilizarse para conexiones entrantes (se ha pasado "out")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para obtener más información:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">No se encontraron datos assumeutxo para el blockhash indicado "%s".</translation> + </message> + <message> <source>Block verification was interrupted</source> <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>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Se encontró un bloque corrupto que indica un posible fallo del hardware.</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,13 +4438,17 @@ 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> <translation type="unfinished">El archivo de volcado %s no existe.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Fallo en la prueba de cordura de la criptografía de curva elíptica. %s se apagará.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Error al confirmar db txn para eliminar transacciones de billetera</translation> </message> @@ -3953,7 +4462,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 +4474,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 +4506,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 +4526,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 +4550,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 +4570,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,24 +4582,35 @@ 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 connect best block (%s).</source> + <translation type="unfinished">No se pudo conectar el mejor bloque (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">No se pudo desconectar el bloque.</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 read block.</source> + <translation type="unfinished">No se pudo leer el bloque.</translation> </message> <message> <source>Failed to rescan the wallet during initialization</source> @@ -4094,15 +4618,31 @@ 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> <translation type="unfinished">Fallo al verificar la base de datos</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">No se pudo escribir el bloque.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Error al escribir en la base de datos del índice de bloques.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Error al escribir en la base de datos de monedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Error al escribir datos para deshacer.</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 +4658,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 +4678,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 +4701,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 +4726,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> @@ -4185,14 +4737,22 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Cargando billetera...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">El peso máximo de la transacción debe estar entre %d y %d.</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 +4762,15 @@ 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>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Solo se ha establecido la dirección, sin permisos: "%s"</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> @@ -4218,7 +4782,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> @@ -4249,8 +4817,20 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">La sección [%s] no se reconoce.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">El firmante no se hizo eco de la dirección</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">El firmante se hizo eco de una dirección inesperada %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">El firmante devolvió un error: %s</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> @@ -4277,8 +4857,20 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Iniciando subprocesos de red...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Error del sistema durante el vaciado:%s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Error del sistema al cargar un archivo de bloque externo: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Error del sistema al guardar el bloque en el disco: %s</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 +4878,27 @@ 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>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">No hay ningún ScriptPubKeyManager para esta direcció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 +4906,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 +4918,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> @@ -4325,10 +4929,6 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Transacción demasiado grande</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">No se puede asignar memoria para -maxsigcachesize: "%s" MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">No se puede establecer un enlace a %s en esta computadora (bind devolvió el error %s)</translation> </message> @@ -4361,6 +4961,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,23 +4982,27 @@ 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> <translation type="unfinished">Se desconocen las nuevas reglas activadas (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opción no reconocida "%s" proporcionada en -test=<option>.</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 +5010,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 puede agregar la transacción solo de observació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_et.ts b/src/qt/locale/bitcoin_et.ts index 8ffd068e5c..a23c1ffdd9 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -1468,10 +1468,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Palun kontrolli aadressi ja proovi uuesti.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Sisestatud aadress ei viita võtmele.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Rahakoti lahtilukustamine on katkestatud.</translation> </message> diff --git a/src/qt/locale/bitcoin_eu.ts b/src/qt/locale/bitcoin_eu.ts index 78cac641f0..d3ed81efdd 100644 --- a/src/qt/locale/bitcoin_eu.ts +++ b/src/qt/locale/bitcoin_eu.ts @@ -310,7 +310,11 @@ Sinatzea 'legacy' motako helbideekin soilik da posible</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">Diruzorro lehenetsia</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -582,10 +586,6 @@ Sinatzea 'legacy' motako helbideekin soilik da posible</translation> <translation type="unfinished">Diruzorro guztiak itxi</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Diruzorro lehenetsia</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Ez dago diru-zorrorik eskura</translation> </message> @@ -860,10 +860,6 @@ Sinatzea 'legacy' motako helbideekin soilik da posible</translation> <translation type="unfinished">Diruzorroa irekitzen abisua</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Diruzorro lehenetsia</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Diruzorroa zabaldu</translation> @@ -2157,11 +2153,7 @@ Sinatzea 'legacy' motako helbideekin soilik da posible</translation> <source>PSBT copied</source> <translation type="unfinished">PSBT kopiatua</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Diruzorro lehenetsia</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 5da96344e5..43b82049e1 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -2,106 +2,44 @@ <context> <name>AddressBookPage</name> <message> - <source>Create a new address</source> - <translation type="unfinished">یک آدرس جدید ایجاد کنید</translation> - </message> - <message> - <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">کپی آدرسی که اکنون انتخاب کردید در کلیپ بورد سیستم</translation> - </message> - </context> -<context> - <name>AskPassphraseDialog</name> - <message> - <source>Your wallet is about to be encrypted. </source> - <translation type="unfinished">کیف پول شما در حال رمزگذاری ست.</translation> - </message> - <message> - <source>Your wallet is now encrypted. </source> - <translation type="unfinished">کیف پول شما اکنون رمزگذاری شد.</translation> - </message> - <message> - <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> - <translation type="unfinished">مهم: پشتیبان گیری قبلی که از پرونده کیف پول خود انجام داده اید باید با پرونده کیف پول رمزگذاری شده تازه ایجاد شده جایگزین شود. به دلایل امنیتی ، به محض شروع استفاده از کیف پول رمزگذاری شده جدید ، پشتیبان گیری قبلی از پرونده کیف پول رمزگذاری نشده فایده ای نخواهد داشت. - </translation> - </message> - <message> - <source>Wallet encryption failed</source> - <translation type="unfinished">رمزگذاری کیف پول انجام نشد - </translation> - </message> - <message> - <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">رمزگذاری کیف پول به دلیل خطای داخلی انجام نشد. کیف پول شما رمزگذاری نشده است. - </translation> - </message> - <message> - <source>The supplied passphrases do not match.</source> - <translation type="unfinished">رمزهای واردشده تطابق ندارند.</translation> + <source>Right-click to edit address or label</source> + <translation type="unfinished">برای ویرایش آدرس یا لیبل کلیک راست کنید</translation> </message> <message> - <source>Wallet unlock failed</source> - <translation type="unfinished">باز کردن قفل کیف پول انجام نشد - </translation> + <source>Create a new address</source> + <translation type="unfinished">آدرس جدید بسازید</translation> </message> <message> - <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">عبارت عبور وارد شده برای رمزگشایی کیف پول نادرست است. - </translation> + <source>&New</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> + <source>Copy the currently selected address to the system clipboard</source> + <translation type="unfinished">آدرس انتخاب شده را در حافظه سیستم ذخیره کنید</translation> </message> <message> - <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished">هشدار: کلید کلاه قفل روشن است! - </translation> + <source>&Copy</source> + <translation type="unfinished">هم افزایی</translation> </message> -</context> -<context> - <name>BanTableModel</name> <message> - <source>IP/Netmask</source> - <translation type="unfinished">آی پی/نت ماسک</translation> + <source>C&lose</source> + <translation type="unfinished">بستن</translation> </message> <message> - <source>Banned Until</source> - <translation type="unfinished">مسدودشده تا</translation> + <source>Delete the currently selected address from the list</source> + <translation type="unfinished">آدرس انتخاب شده را از لیست پاک کنید</translation> </message> -</context> + </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>Internal error</source> - <translation type="unfinished">مشکل داخلی</translation> - </message> + <name>AskPassphraseDialog</name> <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> + <source>Back</source> + <translation type="unfinished">بازگشت</translation> </message> -</context> + </context> <context> <name>QObject</name> <message> - <source>Do you want to reset settings to default values, or to abort without making changes?</source> - <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment> - <translation type="unfinished">آیا می خواهید تنظیمات را به مقادیر پیش فرض بازنشانی کنید یا بدون ایجاد تغییرات لغو کنید؟</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> @@ -110,8 +48,12 @@ <translation type="unfinished">%1 هنوز به صورت ایمن بیرون نرفته است...</translation> </message> <message> - <source>unknown</source> - <translation type="unfinished">ناشناس</translation> + <source>Embedded "%1"</source> + <translation type="unfinished">تعبیه شده%1</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">سفارشی...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> @@ -236,6 +178,11 @@ <source>%1 GB</source> <translation type="unfinished">%1 گیگابایت</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">کیف پول پیش فرض + </translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -300,7 +247,7 @@ </message> <message> <source>Proxy is <b>enabled</b>: %1</source> - <translation type="unfinished">پراکسی <br>فعال شده است: %1</br></translation> + <translation type="unfinished">پراکسی <b>فعال</b> شده است: %1</translation> </message> <message> <source>Send coins to a Bitcoin address</source> @@ -324,10 +271,6 @@ <translation type="unfinished">دریافت</translation> </message> <message> - <source>&Options…</source> - <translation type="unfinished">گزینه ها...</translation> - </message> - <message> <source>&Encrypt Wallet…</source> <translation type="unfinished">رمزنگاری کیف پول</translation> </message> @@ -409,14 +352,6 @@ <translation type="unfinished">در حال پردازش بلوکها روی دیسک..</translation> </message> <message> - <source>Connecting to peers…</source> - <translation type="unfinished">در حال اتصال به همتاهای شبکه(پیِر ها)...</translation> - </message> - <message> - <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">درخواست پرداخت (ساخت کد QR و بیتکوین: URIs)</translation> - </message> - <message> <source>Show the list of used sending addresses and labels</source> <translation type="unfinished">نمایش لیست آدرسها و لیبلهای ارسالی استفاده شده</translation> </message> @@ -431,7 +366,7 @@ <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>سابقه تراکنش بلوک(های) %n پردازش شد.</numerusform> + <numerusform>Processed %n block(s) of transaction history.</numerusform> </translation> </message> <message> @@ -510,20 +445,10 @@ <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>default wallet</source> - <translation type="unfinished">کیف پول پیش فرض - </translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">هیچ کیف پولی در دسترس نمی باشد</translation> </message> @@ -538,11 +463,6 @@ <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> @@ -571,7 +491,7 @@ <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>%n active connection(s) to Bitcoin network.</numerusform> + <numerusform>%n اتصال(های) فعال به شبکه بیت کوین.</numerusform> </translation> </message> <message> @@ -603,114 +523,59 @@ <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> + </context> +<context> + <name>CoinControlDialog</name> <message> - <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">کیف پول است <b> رمزگذاری شده </b> و در حال حاضر <b> تفسیر شده است </b> - </translation> + <source>After Fee:</source> + <translation type="unfinished">بعد از احتساب کارمزد</translation> </message> <message> - <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">کیف پول است <b> رمزگذاری شده </b> و در حال حاضر <b> تفسیر شده </b> - </translation> + <source>Change:</source> + <translation type="unfinished">تغییر</translation> </message> <message> - <source>Original message:</source> - <translation type="unfinished">پیام اصلی:</translation> + <source>(un)select all</source> + <translation type="unfinished">(عدم)انتخاب همه</translation> </message> -</context> -<context> - <name>CoinControlDialog</name> <message> - <source>Coin Selection</source> - <translation type="unfinished">انتخاب سکه - </translation> + <source>Tree mode</source> + <translation type="unfinished">حالت درختی</translation> + </message> + <message> + <source>List mode</source> + <translation type="unfinished">حالت لیستی</translation> </message> <message> - <source>Quantity:</source> - <translation type="unfinished">مقدار</translation> + <source>Amount</source> + <translation type="unfinished">میزان وجه:</translation> </message> <message> - <source>Bytes:</source> - <translation type="unfinished">بایت ها:</translation> + <source>Received with label</source> + <translation type="unfinished">دریافت شده با برچسب</translation> </message> <message> - <source>Amount:</source> - <translation type="unfinished">میزان وجه:</translation> + <source>Received with address</source> + <translation type="unfinished">دریافت شده با آدرس</translation> </message> <message> - <source>Fee:</source> - <translation type="unfinished">هزینه</translation> + <source>Date</source> + <translation type="unfinished">تاریخ</translation> </message> <message> - <source>After Fee:</source> - <translation type="unfinished">بعد از احتساب کارمزد</translation> + <source>Confirmations</source> + <translation type="unfinished">تاییدیه</translation> </message> <message> - <source>Change:</source> - <translation type="unfinished">تغییر</translation> + <source>Confirmed</source> + <translation type="unfinished">تایید شده</translation> </message> <message> - <source>List mode</source> - <translation type="unfinished">حالت لیستی</translation> + <source>Copy amount</source> + <translation type="unfinished">کپی مقدار</translation> </message> <message> <source>&Copy address</source> @@ -761,6 +626,10 @@ <translation type="unfinished">(قفل شده است %1)</translation> </message> <message> + <source>(no label)</source> + <translation type="unfinished">(بدون لیبل)</translation> + </message> + <message> <source>change from %1 (%2)</source> <translation type="unfinished">تغییر از %1 (%2)</translation> </message> @@ -815,420 +684,45 @@ </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> + <name>MigrateWalletActivity</name> <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>Close all wallets</source> - <translation type="unfinished">همهی کیف پولها را ببند</translation> + <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">اسکریپت های Watchonly با موفقیت به کیف پول '%1' منتقل گردیدند.</translation> </message> </context> <context> - <name>CreateWalletDialog</name> - <message> - <source>Create Wallet</source> - <translation type="unfinished">ایجاد کیف پول - </translation> - </message> - <message> - <source>Wallet Name</source> - <translation type="unfinished">نام کیف پول</translation> - </message> - <message> - <source>Wallet</source> - <translation type="unfinished">کیف پول</translation> - </message> - <message> - <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation type="unfinished">کیف پول را رمز نگاری نمائید. کیف پول با کلمات رمز دلخواه شما رمز نگاری خواهد شد</translation> - </message> - <message> - <source>Encrypt Wallet</source> - <translation type="unfinished">رمز نگاری کیف پول</translation> - </message> - <message> - <source>Advanced Options</source> - <translation type="unfinished">گزینههای پیشرفته</translation> - </message> - <message> - <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> - <translation type="unfinished">غیر فعال کردن کلیدهای خصوصی برای این کیف پول. کیف پول هایی با کلید های خصوصی غیر فعال هیچ کلید خصوصی نداشته و نمیتوانند HD داشته باشند و یا کلید های خصوصی دارد شدنی داشته باشند. این کیف پول ها صرفاً برای رصد مناسب هستند.</translation> - </message> - <message> - <source>Disable Private Keys</source> - <translation type="unfinished">غیر فعال کردن کلیدهای خصوصی</translation> - </message> - <message> - <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> - <translation type="unfinished">یک کیف پول خالی درست کنید. کیف پول های خالی در ابتدا کلید یا اسکریپت خصوصی ندارند. کلیدها و آدرسهای خصوصی می توانند وارد شوند یا بذر HD را می توان بعداً تنظیم نمود.</translation> - </message> - <message> - <source>Make Blank Wallet</source> - <translation type="unfinished">ساخت کیف پول خالی</translation> - </message> - <message> - <source>Use 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>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>Path already exists, and is not a directory.</source> - <translation type="unfinished">مسیر داده شده موجود است و به یک پوشه اشاره نمیکند.</translation> - </message> - <message> - <source>Cannot create data directory here.</source> - <translation type="unfinished">نمی توانید فهرست داده را در اینجا ایجاد کنید. - </translation> - </message> -</context> -<context> <name>Intro</name> - <message> - <source>Bitcoin</source> - <translation type="unfinished">بیت کوین</translation> - </message> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform>%n گیگابایت فضای موجود</numerusform> + <numerusform>%n GB of space available</numerusform> </translation> </message> <message numerus="yes"> <source>(of %n GB needed)</source> <translation type="unfinished"> - <numerusform>(از %n گیگابایت مورد نیاز)</numerusform> + <numerusform>(of %n GB needed)</numerusform> </translation> </message> <message numerus="yes"> <source>(%n GB needed for full chain)</source> <translation type="unfinished"> - <numerusform>(%n گیگابایت برای زنجیره کامل مورد نیاز است)</numerusform> + <numerusform>(%n GB needed for full chain)</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 گیگابایت اطلاعات در این شاخه ذخیره خواهد شد، که به مرور زمان افزایش خواهد یافت.</translation> - </message> - <message> - <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">تقریبا %1 گیگابایت داده در این شاخه ذخیره خواهد شد.</translation> - </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> <extracomment>Explanatory text on the capability of the current prune target.</extracomment> <translation type="unfinished"> - <numerusform>(برای بازیابی نسخههای پشتیبان %n روز (های) قدیمی کافی است)</numerusform> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> </translation> </message> - <message> - <source>The wallet will also be stored in this directory.</source> - <translation type="unfinished">کیف پول هم در همین دایرکتوری ذخیره میشود.</translation> - </message> - <message> - <source>Error: Specified data directory "%1" cannot be created.</source> - <translation type="unfinished">خطا: نمیتوان پوشهای برای دادهها در «%1» ایجاد کرد.</translation> - </message> - <message> - <source>Error</source> - <translation type="unfinished">خطا</translation> - </message> - <message> - <source>Welcome</source> - <translation type="unfinished">خوش آمدید</translation> - </message> - <message> - <source>Welcome to %1.</source> - <translation type="unfinished">به %1 خوش آمدید.</translation> - </message> - <message> - <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> - <translation type="unfinished">از آنجا که اولین مرتبه این برنامه اجرا میشود، شما میتوانید محل ذخیره دادههای %1 را انتخاب نمایید.</translation> - </message> - <message> - <source>Limit block chain storage to</source> - <translation type="unfinished">محدود کن حافظه زنجیره بلوک را به</translation> - </message> - <message> - <source> GB</source> - <translation type="unfinished">گیگابایت</translation> - </message> - <message> - <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source> - <translation type="unfinished">وقتی تأیید را کلیک میکنید، %1 شروع به دانلود و پردازش زنجیره بلاک %4 کامل (%2 گیگابایت) میکند که با اولین تراکنشها در %3 شروع میشود که %4 در ابتدا راهاندازی می شود.</translation> - </message> - <message> - <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> - <translation type="unfinished">اگر تصمیم بگیرید که فضای ذخیره سازی زنجیره بلوک (هرس) را محدود کنید ، داده های تاریخی باید بارگیری و پردازش شود ، اما اگر آن را حذف کنید ، اگر شما دیسک کم استفاده کنید. - </translation> - </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>Number of blocks left</source> - <translation type="unfinished">تعداد بلوکهای باقیمانده</translation> - </message> - <message> - <source>Unknown…</source> - <translation type="unfinished">ناشناخته</translation> - </message> - <message> - <source>calculating…</source> - <translation type="unfinished">در حال رایانش</translation> - </message> - <message> - <source>Last block time</source> - <translation type="unfinished">زمان آخرین بلوک</translation> - </message> - <message> - <source>Progress</source> - <translation type="unfinished">پیشرفت</translation> - </message> - <message> - <source>Progress increase per hour</source> - <translation type="unfinished">سرعت افزایش پیشرفت بر ساعت</translation> - </message> - <message> - <source>Estimated time left until synced</source> - <translation type="unfinished">زمان تقریبی باقیمانده تا همگام شدن</translation> - </message> - <message> - <source>Hide</source> - <translation type="unfinished">پنهان کردن</translation> - </message> - <message> - <source>Esc</source> - <translation type="unfinished">خروج</translation> - </message> - <message> - <source>Unknown. Syncing Headers (%1, %2%)…</source> - <translation type="unfinished">ناشناخته. هماهنگسازی سربرگها (%1، %2%) </translation> - </message> - <message> - <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> - <translation type="unfinished">ناشناس. پیشهمگامسازی سرصفحهها (%1، %2% )…</translation> - </message> -</context> -<context> - <name>OpenURIDialog</name> - <message> - <source>URI:</source> - <translation type="unfinished">آدرس:</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> <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>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>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> + <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> @@ -1721,921 +1215,46 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> </context> <context> - <name>QRImageWidget</name> - <message> - <source>&Save Image…</source> - <translation type="unfinished">&ذخیره کردن تصویر...</translation> - </message> - <message> - <source>&Copy Image</source> - <translation type="unfinished">&کپی کردن image</translation> - </message> - <message> - <source>Resulting URI too long, try to reduce the text for label / message.</source> - <translation type="unfinished">URL ایجاد شده خیلی طولانی است. سعی کنید طول برچسب و یا پیام را کمتر کنید.</translation> - </message> - <message> - <source>Error encoding URI into QR Code.</source> - <translation type="unfinished">خطا در تبدیل نشانی اینترنتی به صورت کد QR.</translation> - </message> - <message> - <source>QR code support not available.</source> - <translation type="unfinished">پستیبانی از QR کد در دسترس نیست.</translation> - </message> - <message> - <source>Save QR Code</source> - <translation type="unfinished">ذحیره کردن Qr Code</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">ویرایش کنسول RPC</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">پوشه داده Datadir</translation> - </message> - <message> - <source>Blocksdir</source> - <translation type="unfinished">فولدر بلاکها</translation> - </message> - <message> - <source>Startup time</source> - <translation type="unfinished">زمان آغاز به کار</translation> - </message> - <message> - <source>Network</source> - <translation type="unfinished">شبکه</translation> - </message> - <message> - <source>Name</source> - <translation type="unfinished">نام</translation> - </message> - <message> - <source>Number of connections</source> - <translation type="unfinished">تعداد اتصال</translation> - </message> - <message> - <source>Block chain</source> - <translation type="unfinished">زنجیره مجموعه تراکنش ها</translation> - </message> - <message> - <source>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> <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>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 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>Whether we relay addresses to this peer.</source> - <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment> - <translation type="unfinished"> ما آدرسها را به این همتا ارسال میکنیم.</translation> - </message> - <message> - <source>Address Relay</source> - <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment> - <translation type="unfinished">رله آدرس</translation> - </message> - <message> - <source>Addresses Processed</source> - <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment> - <translation type="unfinished">آدرس ها پردازش شد</translation> - </message> - <message> - <source>Addresses Rate-Limited</source> - <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment> - <translation type="unfinished">آدرس ها با نرخ محدود</translation> - </message> - <message> - <source>User Agent</source> - <translation type="unfinished">نماینده کاربر</translation> - </message> - <message> <source>Node window</source> <translation type="unfinished">پنجره گره</translation> </message> - <message> - <source>Current block height</source> - <translation type="unfinished">ارتفاع فعلی بلوک</translation> - </message> - <message> - <source>Decrease font size</source> - <translation type="unfinished">کاهش دادن اندازه فونت</translation> - </message> - <message> - <source>Increase font size</source> - <translation type="unfinished">افزایش دادن اندازه فونت</translation> - </message> - <message> - <source>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, or 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>Ping Wait</source> - <translation type="unfinished">انتظار پینگ</translation> - </message> - <message> - <source>Min Ping</source> - <translation type="unfinished">حداقل پینگ</translation> - </message> - <message> - <source>Last block time</source> - <translation type="unfinished">زمان آخرین بلوک</translation> - </message> - <message> - <source>&Open</source> - <translation type="unfinished">&بازکردن</translation> - </message> - <message> - <source>&Console</source> - <translation type="unfinished">&کنسول</translation> - </message> - <message> - <source>&Network Traffic</source> - <translation type="unfinished">&شلوغی شبکه</translation> - </message> - <message> - <source>Totals</source> - <translation type="unfinished">جمع کل ها</translation> - </message> - <message> - <source>Debug log file</source> - <translation type="unfinished">فایلِ لاگِ اشکال زدایی</translation> - </message> - <message> - <source>Clear console</source> - <translation type="unfinished">پاک کردن کنسول</translation> - </message> - <message> - <source>In:</source> - <translation type="unfinished">به یا داخل:</translation> - </message> - <message> - <source>Out:</source> - <translation type="unfinished">خارج شده:</translation> - </message> - <message> - <source>Inbound: initiated by peer</source> - <extracomment>Explanatory text for an inbound peer connection.</extracomment> - <translation type="unfinished">ورودی: توسط همتا آغاز شد</translation> - </message> - <message> - <source>Outbound Full Relay: default</source> - <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment> - <translation type="unfinished">خروجی کامل رله : پیش فرض</translation> - </message> - <message> - <source>Outbound Block Relay: does not relay transactions or addresses</source> - <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment> - <translation type="unfinished">رله بلوک خروجی: تراکنش ها یا آدرس ها را انتقال نمی دهد</translation> - </message> - <message> - <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> - <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment> - <translation type="unfinished">راهنمای خروجی: با استفاده از گزینه های پیکربندی RPC %1 یا %2/%3 اضافه شده است</translation> - </message> - <message> - <source>Outbound Feeler: short-lived, for testing addresses</source> - <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment> - <translation type="unfinished">حسگر خروجی: کوتاه مدت، برای آزمایش آدرس ها</translation> - </message> - <message> - <source>Outbound Address Fetch: short-lived, for soliciting addresses</source> - <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment> - <translation type="unfinished">واکشی آدرس خروجی: کوتاه مدت، برای درخواست آدرس</translation> - </message> - <message> - <source>we selected the peer for high bandwidth relay</source> - <translation type="unfinished">ما همتا را برای رله با پهنای باند بالا انتخاب کردیم</translation> - </message> - <message> - <source>the peer selected us for high bandwidth relay</source> - <translation type="unfinished">همتا ما را برای رله با پهنای باند بالا انتخاب کرد</translation> - </message> - <message> - <source>no high bandwidth relay selected</source> - <translation type="unfinished">رله با پهنای باند بالا انتخاب نشده است</translation> - </message> - <message> - <source>Ctrl++</source> - <extracomment>Main shortcut to increase the RPC console font size.</extracomment> - <translation type="unfinished">Ctrl + +</translation> - </message> - <message> - <source>Ctrl+=</source> - <extracomment>Secondary shortcut to increase the RPC console font size.</extracomment> - <translation type="unfinished">Ctrl + =</translation> - </message> - <message> - <source>Ctrl+-</source> - <extracomment>Main shortcut to decrease the RPC console font size.</extracomment> - <translation type="unfinished">Ctrl + -</translation> - </message> - <message> - <source>Ctrl+_</source> - <extracomment>Secondary shortcut to decrease the RPC console font size.</extracomment> - <translation type="unfinished">Ctrl + _</translation> - </message> - <message> - <source>&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>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>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">یک پیام اختیاری برای پیوست به درخواست پرداخت ، که با باز شدن درخواست نمایش داده می شود. توجه: پیام با پرداخت از طریق شبکه بیت کوین ارسال نمی شود. - </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">کپی کردن &آدرس URL</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>Generates a native segwit address (BIP-173). Some old wallets don't support it.</source> - <translation type="unfinished">یک آدرس سگویت بومی (BIP-173) ایجاد کنید. -برخی از کیف پول های قدیمی از آن پشتیبانی نمی کنند.</translation> - </message> - <message> - <source>Bech32m (Taproot)</source> - <translation type="unfinished">Bech32m (تپروت)</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> </context> <context> - <name>ReceiveRequestDialog</name> - <message> - <source>Request payment to …</source> - <translation type="unfinished">درخواست پرداخت به </translation> - </message> - <message> - <source>Address:</source> - <translation type="unfinished">آدرسها:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">میزان وجه:</translation> - </message> - <message> - <source>Label:</source> - <translation type="unfinished">برچسب:</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">پیام:</translation> - </message> - <message> - <source>Copy &URI</source> - <translation type="unfinished">کپی کردن &آدرس URL</translation> - </message> - <message> - <source>Copy &Address</source> - <translation type="unfinished">کپی آدرس</translation> - </message> - <message> - <source>&Verify</source> - <translation type="unfinished">&تایید کردن</translation> - </message> - <message> - <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">این آدرس را در صفحه کیف پول سخت افزاری تأیید کنید</translation> - </message> - <message> - <source>&Save Image…</source> - <translation type="unfinished">&ذخیره کردن تصویر...</translation> - </message> - <message> - <source>Payment information</source> - <translation type="unfinished">اطلاعات پرداخت</translation> - </message> - <message> - <source>Request payment to %1</source> - <translation type="unfinished">درخواست پرداخت به %1</translation> - </message> -</context> -<context> <name>RecentRequestsTableModel</name> <message> - <source>Message</source> - <translation type="unfinished">پیام</translation> + <source>(no label)</source> + <translation type="unfinished">(برچسبی ندارد)</translation> </message> - <message> - <source>(no message)</source> - <translation type="unfinished">(بدون پیام)</translation> - </message> - <message> - <source>(no amount requested)</source> - <translation type="unfinished">(هیچ درخواست پرداخت وجود ندارد)</translation> - </message> - <message> - <source>Requested</source> - <translation type="unfinished">درخواست شده</translation> - </message> -</context> + </context> <context> <name>SendCoinsDialog</name> <message> - <source>Send Coins</source> - <translation type="unfinished">سکه های ارسالی</translation> - </message> - <message> - <source>Coin Control Features</source> - <translation type="unfinished">ویژگی های کنترل سکه - </translation> - </message> - <message> - <source>automatically selected</source> - <translation type="unfinished">به صورت خودکار انتخاب شده</translation> - </message> - <message> - <source>Insufficient funds!</source> - <translation type="unfinished">وجوه ناکافی</translation> - </message> - <message> - <source>Quantity:</source> - <translation type="unfinished">مقدار</translation> - </message> - <message> - <source>Bytes:</source> - <translation type="unfinished">بایت ها:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">میزان وجه:</translation> - </message> - <message> - <source>Fee:</source> - <translation type="unfinished">هزینه</translation> - </message> - <message> - <source>After Fee:</source> - <translation type="unfinished">بعد از احتساب کارمزد</translation> - </message> - <message> - <source>Change:</source> - <translation type="unfinished">تغییر</translation> - </message> - <message> - <source>Custom change address</source> - <translation type="unfinished">تغییر آدرس مخصوص</translation> - </message> - <message> - <source>Transaction Fee:</source> - <translation type="unfinished">کارمزد تراکنش:</translation> - </message> - <message> - <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> - <translation type="unfinished">استفاده از Fallbackfee می تواند منجر به ارسال تراکنشی شود که تأیید آن چندین ساعت یا روز (یا هرگز) طول می کشد. هزینه خود را به صورت دستی انتخاب کنید یا صبر کنید تا زنجیره کامل را تأیید کنید.</translation> - </message> - <message> - <source>Warning: Fee estimation is currently not possible.</source> - <translation type="unfinished">هشدار:تخمین کارمزد در حال حاضر امکان پذیر نیست.</translation> - </message> - <message> - <source>per kilobyte</source> - <translation type="unfinished">به ازای هر کیلوبایت</translation> - </message> - <message> - <source>Hide</source> - <translation type="unfinished">پنهان کردن</translation> - </message> - <message> - <source>Recommended:</source> - <translation type="unfinished">پیشنهاد شده:</translation> - </message> - <message> - <source>Custom:</source> - <translation type="unfinished">سفارشی:</translation> - </message> - <message> - <source>Send to multiple recipients at once</source> - <translation type="unfinished">ارسال همزمان به گیرنده های متعدد</translation> - </message> - <message> - <source>Add &Recipient</source> - <translation type="unfinished">اضافه کردن &گیرنده</translation> - </message> - <message> - <source>Clear all fields of the form.</source> - <translation type="unfinished">پاک کردن تمامی گزینه های این فرم</translation> - </message> - <message> - <source>Inputs…</source> - <translation type="unfinished">ورودی ها</translation> - </message> - <message> - <source>Choose…</source> - <translation type="unfinished">انتخاب کنید...</translation> - </message> - <message> - <source>Hide transaction fee settings</source> - <translation type="unfinished">تنظیمات مخفی کردن کارمزد عملیات</translation> - </message> - <message> - <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. - -Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">مشخص کردن هزینه کارمزد مخصوص به ازای کیلوبایت(1,000 بایت) حجم مجازی تراکنش - -توجه: از آن جایی که کارمزد بر اساس هر بایت محاسبه می شود,هزینه کارمزد"100 ساتوشی بر کیلو بایت"برای تراکنش با حجم 500 بایت مجازی (نصف 1 کیلوبایت) کارمزد فقط اندازه 50 ساتوشی خواهد بود.</translation> - </message> - <message> - <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> - <translation type="unfinished">(مقداردهی کارمزد هوشمند هنوز شروع نشده است.این کارمزد معمولا به اندازه چند بلاک طول میکشد...)</translation> - </message> - <message> - <source>Confirmation time target:</source> - <translation type="unfinished">هدف زمانی تایید شدن:</translation> - </message> - <message> - <source>Enable Replace-By-Fee</source> - <translation type="unfinished">فعال کردن جایگذاری دوباره از کارمزد</translation> - </message> - <message> - <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> - <translation type="unfinished">با Replace-By-Fee (BIP-125) می توانید هزینه معامله را پس از ارسال آن افزایش دهید. بدون این ، ممکن است هزینه بیشتری برای جبران افزایش خطر تاخیر در معامله پیشنهاد شود. - </translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">پاک کردن همه</translation> - </message> - <message> - <source>Balance:</source> - <translation type="unfinished">مانده حساب:</translation> - </message> - <message> - <source>Confirm the send action</source> - <translation type="unfinished">تایید عملیات ارسال</translation> - </message> - <message> - <source>S&end</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 (%2 blocks)</source> - <translation type="unfinished">%1(%2 بلاک ها)</translation> - </message> - <message> - <source>Sign on device</source> - <extracomment>"device" usually means a hardware wallet.</extracomment> - <translation type="unfinished">امضا کردن در دستگاه</translation> - </message> - <message> - <source>Connect your hardware wallet first.</source> - <translation type="unfinished">اول کیف سخت افزاری خود را متصل کنید.</translation> - </message> - <message> - <source>Set external signer script path in Options -> Wallet</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">مسیر اسکریپت امضاکننده خارجی را در Options -> Wallet تنظیم کنید</translation> - </message> - <message> - <source>%1 to %2</source> - <translation type="unfinished">%1 به %2</translation> - </message> - <message> - <source>To review recipient list click "Show Details…"</source> - <translation type="unfinished">برای بررسی لیست گیرندگان، روی «نمایش جزئیات…» کلیک کنید.</translation> - </message> - <message> - <source>Sign failed</source> - <translation type="unfinished">امضا موفق نبود</translation> - </message> - <message> - <source>External signer not found</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">امضا کننده خارجی یافت نشد</translation> - </message> - <message> - <source>External signer failure</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">امضا کننده خارجی شکست خورد.</translation> - </message> - <message> - <source>Save Transaction Data</source> - <translation type="unfinished">ذخیره اطلاعات عملیات</translation> - </message> - <message> <source>Partially Signed Transaction (Binary)</source> <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment> <translation type="unfinished">تراکنش نسبتا امضا شده (باینری)</translation> </message> <message> - <source>External balance:</source> - <translation type="unfinished">تعادل خارجی </translation> - </message> - <message> <source>or</source> <translation type="unfinished">یا</translation> </message> - <message> - <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> - <translation type="unfinished">تو میتوانی بعدا هزینه کارمزد را افزایش بدی(signals Replace-By-Fee, BIP-125)</translation> - </message> - <message> - <source>Do you want to create this transaction?</source> - <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment> - <translation type="unfinished">آیا می خواهید این تراکنش را ایجاد کنید؟</translation> - </message> - <message> - <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment> - <translation type="unfinished">لطفا معامله خود را بررسی کنید می توانید این تراکنش را ایجاد و ارسال کنید یا یک تراکنش بیت کوین با امضای جزئی (PSBT) ایجاد کنید، که می توانید آن را ذخیره یا کپی کنید و سپس با آن امضا کنید، به عنوان مثال، یک کیف پول آفلاین %1، یا یک کیف پول سخت افزاری سازگار با PSBT.</translation> - </message> - <message> - <source>Please, review your transaction.</source> - <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment> - <translation type="unfinished">لطفا,تراکنش خود را بازبینی کنید.</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">کارمزد تراکنش</translation> - </message> - <message> - <source>Total Amount</source> - <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> - <message> - <source>The recipient address is not valid. Please recheck.</source> - <translation type="unfinished">آدرس گیرنده نامعتبر است.لطفا دوباره چک یا بررسی کنید.</translation> - </message> - <message> - <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">مبلغ پرداختی باید بیشتر از 0 باشد. - </translation> - </message> - <message> - <source>The amount exceeds your balance.</source> - <translation type="unfinished">این میزان پول بیشتر از موجودی شما است.</translation> - </message> - <message> - <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation type="unfinished">این میزان بیشتر از موجودی شما است وقتی که کارمزد تراکنش %1 باشد.</translation> - </message> - <message> - <source>Duplicate address found: addresses should only be used once each.</source> - <translation type="unfinished">آدرس تکراری یافت شد:آدرس ها باید فقط یک بار استفاده شوند.</translation> - </message> - <message> - <source>Transaction creation failed!</source> - <translation type="unfinished">ایجاد تراکنش با خطا مواجه شد!</translation> - </message> - <message> - <source>A fee higher than %1 is considered an absurdly high fee.</source> - <translation type="unfinished">کارمزد بیشتر از %1 است,این یعنی کارمزد خیلی زیادی در نظر گرفته شده است.</translation> - </message> - <message> - <source>%1/kvB</source> - <translation type="unfinished">%1 kvB</translation> - </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> @@ -2643,280 +1262,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </translation> </message> <message> - <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished">هشدار: آدرس بیت کوین نامعتبر</translation> - </message> - <message> - <source>Warning: Unknown change address</source> - <translation type="unfinished">هشدار:تغییر آدرس نامعلوم</translation> - </message> - <message> - <source>Confirm custom change address</source> - <translation type="unfinished">تایید کردن تغییر آدرس سفارشی</translation> - </message> - <message> - <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> - <translation type="unfinished">این آدرس که شما انتخاب کرده اید بخشی از کیف پول شما نیست.هر یا همه دارایی های شما در این کیف پول به این آدرس ارسال خواهد شد.آیا مطمئن هستید؟</translation> - </message> - </context> -<context> - <name>SendCoinsEntry</name> - <message> - <source>A&mount:</source> - <translation type="unfinished">میزان وجه</translation> - </message> - <message> - <source>Pay &To:</source> - <translation type="unfinished">پرداخت به: - </translation> - </message> - <message> - <source>&Label:</source> - <translation type="unfinished">برچسب:</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">آدرس استفاده شده قبلی را انتخاب کنید</translation> - </message> - <message> - <source>The Bitcoin address to send the payment to</source> - <translation type="unfinished">آدرس Bitcoin برای ارسال پرداخت به - </translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">استفاده از آدرس کلیپ بورد</translation> - </message> - <message> - <source>Remove this entry</source> - <translation type="unfinished">پاک کردن این ورودی</translation> - </message> - <message> - <source>Use available balance</source> - <translation type="unfinished">استفاده از موجودی حساب</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">پیام:</translation> - </message> - </context> -<context> - <name>SendConfirmationDialog</name> - <message> - <source>Send</source> - <translation type="unfinished">ارسال</translation> - </message> - </context> -<context> - <name>SignVerifyMessageDialog</name> - <message> - <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">امضا - امضاء کردن / تأیید کنید یک پیام</translation> - </message> - <message> - <source>&Sign Message</source> - <translation type="unfinished">&ثبت پیام</translation> - </message> - <message> - <source>The Bitcoin address to sign the message with</source> - <translation type="unfinished">نشانی بیتکوین برای امضاء پیغام با آن</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">آدرس استفاده شده قبلی را انتخاب کنید</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">استفاده از آدرس کلیپ بورد</translation> - </message> - <message> - <source>Enter the message you want to sign here</source> - <translation type="unfinished">پیامی که می خواهید امضا کنید را اینجا وارد کنید</translation> - </message> - <message> - <source>Signature</source> - <translation type="unfinished">امضا</translation> - </message> - <message> - <source>Copy the current signature to the system clipboard</source> - <translation type="unfinished">جریان را کپی کنید امضا به سیستم کلیپ بورد</translation> - </message> - <message> - <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">پیام را امضا کنید تا ثابت کنید این آدرس بیتکوین متعلق به شماست</translation> - </message> - <message> - <source>Sign &Message</source> - <translation type="unfinished">ثبت &پیام</translation> - </message> - <message> - <source>Reset all sign message fields</source> - <translation type="unfinished">تنظیم مجدد همه امضاء کردن زمینه های پیام</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">پاک کردن همه</translation> - </message> - <message> - <source>&Verify Message</source> - <translation type="unfinished">& تأیید پیام</translation> - </message> - <message> - <source>The Bitcoin address the message was signed with</source> - <translation type="unfinished">نشانی بیتکوین که پیغام با آن امضاء شده</translation> - </message> - <message> - <source>The signed message to verify</source> - <translation type="unfinished">پیام امضا شده برای تأیید - </translation> - </message> - <message> - <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation type="unfinished">پیام را تأیید کنید تا مطمئن شوید با آدرس Bitcoin مشخص شده امضا شده است - </translation> - </message> - <message> - <source>Verify &Message</source> - <translation type="unfinished">تایید پیام</translation> - </message> - <message> - <source>Reset all verify message fields</source> - <translation type="unfinished">بازنشانی تمام فیلدهای پیام</translation> - </message> - <message> - <source>Click "Sign Message" to generate signature</source> - <translation type="unfinished">برای تولید امضا "Sign Message" و یا "ثبت پیام" را کلیک کنید</translation> - </message> - <message> - <source>The entered address is invalid.</source> - <translation type="unfinished">آدرس وارد شده نامعتبر است.</translation> - </message> - <message> - <source>Please check the address and try again.</source> - <translation type="unfinished">لطفا ادرس را بررسی کرده و دوباره امتحان کنید. - </translation> - </message> - <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">نشانی وارد شده به هیچ کلیدی اشاره نمیکند.</translation> - </message> - <message> - <source>Wallet unlock was cancelled.</source> - <translation type="unfinished">باز کردن قفل کیف پول لغو شد. - </translation> - </message> - <message> - <source>No error</source> - <translation type="unfinished">بدون خطا</translation> - </message> - <message> - <source>Private key for the entered address is not available.</source> - <translation type="unfinished">کلید خصوصی برای نشانی وارد شده در دسترس نیست.</translation> - </message> - <message> - <source>Message signing failed.</source> - <translation type="unfinished">امضای پیام با شکست مواجه شد.</translation> - </message> - <message> - <source>Message signed.</source> - <translation type="unfinished">پیام ثبت شده</translation> - </message> - <message> - <source>The signature could not be decoded.</source> - <translation type="unfinished">امضا نمیتواند کدگشایی شود.</translation> - </message> - <message> - <source>Please check the signature and try again.</source> - <translation type="unfinished">لطفاً امضا را بررسی نموده و دوباره تلاش کنید.</translation> - </message> - <message> - <source>The signature did not match the message digest.</source> - <translation type="unfinished">امضا با خلاصه پیام مطابقت نداشت.</translation> - </message> - <message> - <source>Message verification failed.</source> - <translation type="unfinished">تأیید پیام انجام نشد.</translation> - </message> - <message> - <source>Message verified.</source> - <translation type="unfinished">پیام شما تایید شد</translation> - </message> -</context> -<context> - <name>SplashScreen</name> - <message> - <source>(press q to shutdown and continue later)</source> - <translation type="unfinished">(q را فشار دهید تا خاموش شود و بعدا ادامه دهید)</translation> - </message> - <message> - <source>press q to shutdown</source> - <translation type="unfinished">q را فشار دهید تا خاموش شود</translation> - </message> -</context> -<context> - <name>TrafficGraphWidget</name> - <message> - <source>kB/s</source> - <translation type="unfinished">کیلوبایت بر ثانیه</translation> + <source>(no label)</source> + <translation type="unfinished">(برچسبی ندارد)</translation> </message> </context> <context> <name>TransactionDesc</name> - <message> - <source>abandoned</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment> - <translation type="unfinished">رها شده</translation> - </message> - <message> - <source>%1/unconfirmed</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment> - <translation type="unfinished">%1/تأیید نشده</translation> - </message> - <message> - <source>%1 confirmations</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment> - <translation type="unfinished">%1 تأییدیه</translation> - </message> - <message> - <source>Status</source> - <translation type="unfinished">وضعیت</translation> - </message> - <message> - <source>Source</source> - <translation type="unfinished">منبع</translation> - </message> - <message> - <source>Generated</source> - <translation type="unfinished">تولید شده</translation> - </message> - <message> - <source>From</source> - <translation type="unfinished">از</translation> - </message> - <message> - <source>unknown</source> - <translation type="unfinished">ناشناس</translation> - </message> - <message> - <source>To</source> - <translation type="unfinished">به</translation> - </message> - <message> - <source>own address</source> - <translation type="unfinished">آدرس خود</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">فقط-با قابلیت دیدن</translation> - </message> - <message> - <source>label</source> - <translation type="unfinished">برچسب</translation> - </message> - <message> - <source>Credit</source> - <translation type="unfinished">اعتبار</translation> - </message> <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> @@ -2924,82 +1275,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </translation> </message> <message> - <source>not accepted</source> - <translation type="unfinished">قبول نشده</translation> - </message> - <message> - <source>Debit</source> - <translation type="unfinished">اعتبار</translation> - </message> - <message> - <source>Total credit</source> - <translation type="unfinished">تمامی اعتبار</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">کارمزد تراکنش</translation> - </message> - <message> - <source>Net amount</source> - <translation type="unfinished">میزان وجه دقیق</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">پیام</translation> - </message> - <message> - <source>Comment</source> - <translation type="unfinished">کامنت</translation> - </message> - <message> - <source>Transaction ID</source> - <translation type="unfinished">شناسه تراکنش</translation> - </message> - <message> - <source>Transaction total size</source> - <translation type="unfinished">حجم کل تراکنش</translation> - </message> - <message> - <source>Transaction virtual size</source> - <translation type="unfinished">اندازه مجازی تراکنش</translation> - </message> - <message> - <source>Merchant</source> - <translation type="unfinished">بازرگان</translation> - </message> - <message> - <source>Debug information</source> - <translation type="unfinished">اطلاعات اشکال زدایی - </translation> - </message> - <message> - <source>Transaction</source> - <translation type="unfinished">تراکنش</translation> - </message> - <message> - <source>Inputs</source> - <translation type="unfinished">ورودی ها</translation> - </message> - <message> - <source>true</source> - <translation type="unfinished">درست</translation> - </message> - <message> - <source>false</source> - <translation type="unfinished">نادرست</translation> - </message> -</context> -<context> - <name>TransactionDescDialog</name> - <message> - <source>This pane shows a detailed description of the transaction</source> - <translation type="unfinished">این بخش جزئیات تراکنش را نشان می دهد</translation> - </message> - <message> - <source>Details for %1</source> - <translation type="unfinished">جزییات %1</translation> + <source>Amount</source> + <translation type="unfinished">میزان وجه:</translation> </message> -</context> + </context> <context> <name>TransactionTableModel</name> <message> @@ -3007,186 +1286,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">نوع</translation> </message> <message> - <source>Unconfirmed</source> - <translation type="unfinished">تایید نشده</translation> - </message> - <message> - <source>Abandoned</source> - <translation type="unfinished">رهاشده</translation> - </message> - <message> - <source>Confirmed (%1 confirmations)</source> - <translation type="unfinished">تأیید شده (%1 تأییدیه)</translation> - </message> - <message> - <source>Generated but not accepted</source> - <translation type="unfinished">تولید شده ولی هنوز قبول نشده است</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">گرفته شده با</translation> - </message> - <message> - <source>Received from</source> - <translation type="unfinished">دریافت شده از</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">ارسال شده به</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">استخراج شده</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">فقط-با قابلیت دیدن</translation> - </message> - <message> - <source>(n/a)</source> - <translation type="unfinished">(موجود نیست)</translation> - </message> - <message> - <source>Transaction status. Hover over this field to show number of confirmations.</source> - <translation type="unfinished">وضعیت تراکنش. نشانگر را روی این فیلد نگه دارید تا تعداد تأییدیهها نشان داده شود.</translation> - </message> - <message> - <source>Date and time that the transaction was received.</source> - <translation type="unfinished">تاریخ و زمان تراکنش دریافت شده است</translation> + <source>(no label)</source> + <translation type="unfinished">(برچسبی ندارد)</translation> </message> - <message> - <source>Type of transaction.</source> - <translation type="unfinished">نوع تراکنش.</translation> - </message> - <message> - <source>Amount removed from or added to balance.</source> - <translation type="unfinished">میزان وجه کم شده یا اضافه شده به حساب</translation> - </message> -</context> + </context> <context> <name>TransactionView</name> <message> - <source>All</source> - <translation type="unfinished">همه</translation> - </message> - <message> - <source>Today</source> - <translation type="unfinished">امروز</translation> - </message> - <message> - <source>This week</source> - <translation type="unfinished">این هفته</translation> - </message> - <message> - <source>This month</source> - <translation type="unfinished">این ماه</translation> - </message> - <message> - <source>Last month</source> - <translation type="unfinished">ماه گذشته</translation> - </message> - <message> - <source>This year</source> - <translation type="unfinished">امسال</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">گرفته شده با</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">ارسال شده به</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">استخراج شده</translation> - </message> - <message> - <source>Enter address, transaction id, or label to search</source> - <translation type="unfinished">وارد کردن آدرس,شناسه تراکنش, یا برچسب برای جست و جو</translation> - </message> - <message> - <source>Min amount</source> - <translation type="unfinished">حداقل میزان وجه</translation> - </message> - <message> - <source>Range…</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</source> - <translation type="unfinished">کپی شناسه تراکنش </translation> - </message> - <message> - <source>Copy &raw transaction</source> - <translation type="unfinished">معامله اولیه را کپی نمائید.</translation> - </message> - <message> - <source>Copy full transaction &details</source> - <translation type="unfinished">کپی کردن تمامی اطلاعات تراکنش</translation> - </message> - <message> - <source>&Show transaction details</source> - <translation type="unfinished">نمایش جزئیات تراکنش</translation> - </message> - <message> - <source>Increase transaction &fee</source> - <translation type="unfinished">افزایش کارمزد تراکنش</translation> - </message> - <message> - <source>A&bandon transaction</source> - <translation type="unfinished">ترک معامله</translation> - </message> - <message> - <source>&Edit address label</source> - <translation type="unfinished">&ویرایش برچسب آدرس</translation> - </message> - <message> - <source>Show in %1</source> - <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment> - <translation type="unfinished">نمایش در %1</translation> - </message> - <message> - <source>Export Transaction History</source> - <translation type="unfinished">خارج کردن یا بالا بردن سابقه تراکنش ها</translation> - </message> - <message> - <source>Watch-only</source> - <translation type="unfinished">فقط برای تماشا</translation> - </message> - <message> <source>Type</source> <translation type="unfinished">نوع</translation> </message> - <message> - <source>ID</source> - <translation type="unfinished">شناسه</translation> - </message> - <message> - <source>Exporting Successful</source> - <translation type="unfinished">خارج کردن موفقیت آمیز بود Exporting</translation> - </message> - <message> - <source>Range:</source> - <translation type="unfinished">دامنه:</translation> - </message> - <message> - <source>to</source> - <translation type="unfinished">به</translation> - </message> -</context> + </context> <context> <name>WalletFrame</name> <message> @@ -3200,82 +1310,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> - <name>WalletModel</name> - <message> - <source>Send Coins</source> - <translation type="unfinished">سکه های ارسالی</translation> - </message> - <message> - <source>Increasing transaction fee failed</source> - <translation type="unfinished">افزایش کارمزد تراکنش با خطا مواجه شد</translation> - </message> - <message> - <source>Do you want to increase the fee?</source> - <extracomment>Asks a user if they would like to manually increase the fee of a transaction that has already been created.</extracomment> - <translation type="unfinished">آیا میخواهید اندازه کارمزد را افزایش دهید؟</translation> - </message> - <message> - <source>Current fee:</source> - <translation type="unfinished">کارمزد الان:</translation> - </message> - <message> - <source>Increase:</source> - <translation type="unfinished">افزایش دادن:</translation> - </message> - <message> - <source>New fee:</source> - <translation type="unfinished">کارمزد جدید:</translation> - </message> - <message> - <source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source> - <translation type="unfinished">هشدار: ممکن است در صورت لزوم، با کاهش خروجی تغییر یا افزودن ورودیها، هزینه اضافی را پرداخت کنید. اگر از قبل وجود نداشته باشد، ممکن است یک خروجی تغییر جدید اضافه کند. این تغییرات ممکن است به طور بالقوه حریم خصوصی را درز کند.</translation> - </message> - <message> - <source>PSBT copied</source> - <translation type="unfinished">PSBT کپی شد</translation> - </message> - <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">در کلیپبورد ذخیره شد</translation> - </message> - <message> - <source>Can't sign transaction.</source> - <translation type="unfinished">نمیتوان تراکنش را ثبت کرد</translation> - </message> - <message> - <source>Can't display address</source> - <translation type="unfinished">نمی توان آدرس را نشان داد</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">کیف پول پیش فرض - </translation> - </message> -</context> -<context> <name>WalletView</name> <message> - <source>Backup Wallet</source> - <translation type="unfinished">کیف پول پشتیبان - </translation> - </message> - <message> <source>Wallet Data</source> <extracomment>Name of the wallet data file format.</extracomment> <translation type="unfinished">داده های کیف پول</translation> </message> <message> - <source>Backup Failed</source> - <translation type="unfinished">پشتیبان گیری انجام نشد - </translation> - </message> - <message> - <source>Backup Successful</source> - <translation type="unfinished">پشتیبان گیری موفقیت آمیز است - </translation> - </message> - <message> <source>Cancel</source> <translation type="unfinished">لغو</translation> </message> @@ -3283,442 +1324,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <context> <name>bitcoin-core</name> <message> - <source>The %s developers</source> - <translation type="unfinished">%s توسعه دهندگان</translation> - </message> - <message> - <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for details and a full list.</source> - <translation type="unfinished">%sدرخواست گوش دادن به پورت %u. این پورت به عنوان پورت "بد" در نظر گرفته شده بنابراین بعید است که یک همتا به آن متصل شود. برای مشاهده جزییات و دیدن فهرست کامل فایل doc/p2p-bad-ports.md را مشاهده کنید.</translation> - </message> - <message> - <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> - <translation type="unfinished">نمی توان کیف پول را از نسخه %i به نسخه %i کاهش داد. نسخه کیف پول بدون تغییر</translation> - </message> - <message> - <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source> - <translation type="unfinished">نمی توان یک کیف پول تقسیم غیر HD را از نسخه %i به نسخه %i بدون ارتقا برای پشتیبانی از دسته کلید از پیش تقسیم ارتقا داد. لطفا از نسخه %i یا بدون نسخه مشخص شده استفاده کنید.</translation> - </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">فضای دیسک برای %s ممکن است فایل های بلوک را در خود جای ندهد. تقریبا %u گیگابایت داده در این فهرست ذخیره خواهد شد</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">خطا در بارگیری کیف پول. کیف پول برای بارگیری به بلوکها نیاز دارد، و نرمافزار در حال حاضر از بارگیری کیف پولها پشتیبانی نمیکند، استفاده از تصاویر گره ( نود ) های کامل جدیدی که تأیید های قدیمی را به تعویق می اندازند، باعث میشود بلوک ها بدون نظم دانلود شود. بارگیری کامل اطلاعات کیف پول فقط پس از اینکه همگامسازی گره به ارتفاع %s رسید، امکان پذیر است.</translation> - </message> - <message> - <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source> - <translation type="unfinished">خطا در خواندن %s! دادههای تراکنش ممکن است گم یا نادرست باشد. در حال اسکن مجدد کیف پول</translation> - </message> - <message> - <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> - <translation type="unfinished">خطا: رکورد قالب Dumpfile نادرست است. دریافت شده، "%s" "مورد انتظار".</translation> - </message> - <message> - <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">خطا: رکورد شناسه Dumpfile نادرست است. دریافت "%s"، انتظار می رود "%s".</translation> - </message> - <message> - <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> - <translation type="unfinished">خطا: نسخه Dumpfile پشتیبانی نمی شود. این نسخه کیف پول بیت کوین فقط از فایل های dumpfiles نسخه 1 پشتیبانی می کند. Dumpfile با نسخه %s دریافت شد</translation> - </message> - <message> - <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> - <translation type="unfinished">خطا: کیف پول های قدیمی فقط از انواع آدرس "legacy"، "p2sh-segwit" و "bech32" پشتیبانی می کنند.</translation> - </message> - <message> - <source>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">خطا: امکان تولید جزئیات برای این کیف پول نوع legacy وجود ندارد. در صورتی که کیف پول رمزگذاری شده است، مطمئن شوید که عبارت عبور آن را درست وارد کردهاید.</translation> - </message> - <message> - <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source> - <translation type="unfinished">فایل %s از قبل موجود میباشد. اگر مطمئن هستید که این همان چیزی است که می خواهید، ابتدا آن را از مسیر خارج کنید.</translation> - </message> - <message> - <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source> - <translation type="unfinished">peers.dat نامعتبر یا فاسد (%s). اگر فکر می کنید این یک اشکال است، لطفاً آن را به %s گزارش دهید. به عنوان یک راه حل، می توانید فایل (%s) را از مسیر خود خارج کنید (تغییر نام، انتقال یا حذف کنید) تا در شروع بعدی یک فایل جدید ایجاد شود.</translation> - </message> - <message> - <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> - <translation type="unfinished">هیچ فایل دامپی ارائه نشده است. برای استفاده از createfromdump، باید -dumpfile=<filename> ارائه شود.</translation> - </message> - <message> - <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> - <translation type="unfinished">هیچ فایل دامپی ارائه نشده است. برای استفاده از dump، -dumpfile=<filename> باید ارائه شود.</translation> - </message> - <message> - <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> - <translation type="unfinished">هیچ فرمت فایل کیف پول ارائه نشده است. برای استفاده از createfromdump باید -format=<format> ارائه شود.</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">هرس: آخرین هماهنگی کیف پول فراتر از داده های هرس شده است. شما باید دوباره -exe کنید (در صورت گره هرس شده دوباره کل بلاکچین را بارگیری کنید) - </translation> - </message> - <message> - <source>The transaction amount is too small to send after the fee has been deducted</source> - <translation type="unfinished">مبلغ معامله برای ارسال پس از کسر هزینه بسیار ناچیز است - </translation> - </message> - <message> - <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> - <translation type="unfinished">این یک نسخه ی آزمایشی است - با مسئولیت خودتان از آن استفاده کنید - آن را در معدن و بازرگانی بکار نگیرید.</translation> - </message> - <message> - <source>This is the transaction fee you may pay when fee estimates are not available.</source> - <translation type="unfinished">این است هزینه معامله ممکن است پرداخت چه زمانی هزینه تخمین در دسترس نیست</translation> - </message> - <message> - <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> - <translation type="unfinished">فرمت فایل کیف پول ناشناخته "%s" ارائه شده است. لطفا یکی از "bdb" یا "sqlite" را ارائه دهید.</translation> - </message> - <message> - <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> - <translation type="unfinished">هشدار: قالب کیف پول Dumpfile "%s" با فرمت مشخص شده خط فرمان %s مطابقت ندارد.</translation> - </message> - <message> - <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> - <translation type="unfinished">هشدار: کلید های خصوصی در کیف پول شما شناسایی شده است { %s} به همراه کلید های خصوصی غیر فعال</translation> - </message> - <message> - <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> - <translation type="unfinished">هشدار: به نظر نمی رسد ما کاملاً با همسالان خود موافق هستیم! ممکن است به ارتقا نیاز داشته باشید یا گره های دیگر به ارتقا نیاز دارند. - </translation> - </message> - <message> - <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> - <translation type="unfinished">دادههای شاهد برای بلوکها پس از ارتفاع %d نیاز به اعتبارسنجی دارند. لطفا با -reindex دوباره راه اندازی کنید.</translation> - </message> - <message> - <source>%s is set very high!</source> - <translation type="unfinished">%s بسیار بزرگ انتخاب شده است.</translation> - </message> - <message> - <source>Cannot resolve -%s address: '%s'</source> - <translation type="unfinished">نمی توان آدرس -%s را حل کرد: '%s'</translation> - </message> - <message> - <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> - <translation type="unfinished">هنگام تنظیم -dnsseed روی نادرست نمی توان -forcednsseed را روی درست تنظیم کرد.</translation> - </message> - <message> <source>Cannot write to data directory '%s'; check permissions.</source> <translation type="unfinished">نمیتواند پوشه داده ها را بنویسد ' %s';دسترسی ها را بررسی کنید.</translation> </message> - <message> - <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> - <translation type="unfinished">اتصالات خروجی محدود به CJDNS محدود شده است ( onlynet=cjdns- ) اما cjdnsreachable- ارائه نشده است</translation> - </message> - <message> - <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source> - <translation type="unfinished">اتصالات خروجی محدود به i2p است (onlynet=i2p-) اما 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">اندازه ورودی از حداکثر مقدار موجودی بیشتر است. لطفاً مقدار کمتری ارسال کنید یا به صورت دستی مقدار موجودی خرج نشده کیف پول خود را در ارسال تراکنش اعمال کنید. </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">مقدار کل بیتکوینی که از پیش انتخاب کردید کمتر از مبلغ مورد نظر برای انجام تراکنش است . لطفاً اجازه دهید ورودی های دیگر به طور خودکار انتخاب شوند یا مقدار بیتکوین های بیشتری را به صورت دستی اضافه کنید</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">ورودی خارج از دستور از نوع legacy در کیف پول مورد نظر پیدا شد. در حال بارگیری کیف پول %s -کیف پول ممکن است دستکاری شده یا با اهداف مخرب ایجاد شده باشد. -</translation> - </message> - <message> - <source>Copyright (C) %i-%i</source> - <translation type="unfinished">کپی رایت (C) %i-%i</translation> - </message> - <message> - <source>Corrupted block database detected</source> - <translation type="unfinished">یک پایگاه داده ی بلوک خراب یافت شد</translation> - </message> - <message> - <source>Do you want to rebuild the block database now?</source> - <translation type="unfinished">آیا میخواهید الان پایگاه داده بلاک را بازسازی کنید؟</translation> - </message> - <message> - <source>Done loading</source> - <translation type="unfinished">اتمام لود شدن</translation> - </message> - <message> - <source>Dump file %s does not exist.</source> - <translation type="unfinished">فایل زبالهٔ %s وجود ندارد.</translation> - </message> - <message> - <source>Error creating %s</source> - <translation type="unfinished">خطا در ایجاد %s</translation> - </message> - <message> - <source>Error initializing block database</source> - <translation type="unfinished">خطا در آماده سازی پایگاه داده ی بلوک</translation> - </message> - <message> - <source>Error loading %s</source> - <translation type="unfinished">خطا بازگذاری %s</translation> - </message> - <message> - <source>Error loading block database</source> - <translation type="unfinished">خطا در بارگذاری پایگاه داده بلاک block</translation> - </message> - <message> - <source>Error opening block database</source> - <translation type="unfinished">خطا در بازکردن پایگاه داده بلاک block</translation> - </message> - <message> - <source>Error reading from database, shutting down.</source> - <translation type="unfinished">خواندن از پایگاه داده با خطا مواجه شد,در حال خاموش شدن.</translation> - </message> - <message> - <source>Error reading next record from wallet database</source> - <translation type="unfinished">خطا در خواندن رکورد بعدی از پایگاه داده کیف پول</translation> - </message> - <message> - <source>Error: Cannot extract destination from the generated scriptpubkey</source> - <translation type="unfinished">خطا: نمی توان مقصد را از scriptpubkey تولید شده استخراج کرد</translation> - </message> - <message> - <source>Error: Couldn't create cursor into database</source> - <translation type="unfinished">خطا: مکان نما در پایگاه داده ایجاد نشد</translation> - </message> - <message> - <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> - <translation type="unfinished">خطا: جمع چکی Dumpfile مطابقت ندارد. محاسبه شده %s، مورد انتظار %s.</translation> - </message> - <message> - <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">خطا: کلیدی دریافت کردم که هگز نبود: %s</translation> - </message> - <message> - <source>Error: Got value that was not hex: %s</source> - <translation type="unfinished">خطا: مقداری دریافت کردم که هگز نبود: %s</translation> - </message> - <message> - <source>Error: Missing checksum</source> - <translation type="unfinished">خطا: جمع چک وجود ندارد</translation> - </message> - <message> - <source>Error: No %s addresses available.</source> - <translation type="unfinished">خطا : هیچ آدرس %s وجود ندارد.</translation> - </message> - <message> - <source>Error: Unable to parse version %u as a uint32_t</source> - <translation type="unfinished">خطا: تجزیه نسخه %u به عنوان uint32_t ممکن نیست</translation> - </message> - <message> - <source>Error: Unable to write record to new wallet</source> - <translation type="unfinished">خطا: نوشتن رکورد در کیف پول جدید امکان پذیر نیست</translation> - </message> - <message> - <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation type="unfinished">شنیدن هر گونه درگاه انجام پذیر نیست. ازlisten=0 برای اینکار استفاده کیند.</translation> - </message> - <message> - <source>Failed to rescan the wallet during initialization</source> - <translation type="unfinished">در هنگام مقداردهی اولیه ، مجدداً اسکن کیف پول انجام نشد - </translation> - </message> - <message> - <source>Importing…</source> - <translation type="unfinished">در حال واردات…</translation> - </message> - <message> - <source>Input not found or already spent</source> - <translation type="unfinished">ورودی پیدا نشد یا قبلاً خرج شده است</translation> - </message> - <message> - <source>Insufficient dbcache for block verification</source> - <translation type="unfinished">dbcache ( حافظه موقت دیتابیس ) کافی برای تأیید بلوک وجود ندارد</translation> - </message> - <message> - <source>Insufficient funds</source> - <translation type="unfinished">وجوه ناکافی</translation> - </message> - <message> - <source>Invalid -i2psam address or hostname: '%s'</source> - <translation type="unfinished">آدرس -i2psam یا نام میزبان نامعتبر است: '%s'</translation> - </message> - <message> - <source>Invalid -proxy address or hostname: '%s'</source> - <translation type="unfinished">آدرس پراکسی یا هاست نامعتبر: ' %s'</translation> - </message> - <message> - <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation type="unfinished">میزان نامعتبر برای -%s=<amount>: '%s'</translation> - </message> - <message> - <source>Invalid port specified in %s: '%s'</source> - <translation type="unfinished">پورت نامعتبری در %s انتخاب شده است : «%s»</translation> - </message> - <message> - <source>Invalid pre-selected input %s</source> - <translation type="unfinished">ورودی از پیش انتخاب شده %s نامعتبر است </translation> - </message> - <message> - <source>Loading P2P addresses…</source> - <translation type="unfinished">در حال بارگیری آدرسهای P2P…</translation> - </message> - <message> - <source>Loading banlist…</source> - <translation type="unfinished">در حال بارگیری فهرست ممنوعه…</translation> - </message> - <message> - <source>Loading block index…</source> - <translation type="unfinished">در حال بارگیری فهرست بلوک…</translation> - </message> - <message> - <source>Loading wallet…</source> - <translation type="unfinished">در حال بارگیری کیف پول…</translation> - </message> - <message> - <source>Missing amount</source> - <translation type="unfinished">مقدار گم شده</translation> - </message> - <message> - <source>Missing solving data for estimating transaction size</source> - <translation type="unfinished">داده های حل برای تخمین اندازه تراکنش وجود ندارد</translation> - </message> - <message> - <source>No addresses available</source> - <translation type="unfinished">هیچ آدرسی در دسترس نیست</translation> - </message> - <message> - <source>Not enough file descriptors available.</source> - <translation type="unfinished">توصیفگرهای فایل به اندازه کافی در دسترس نیست</translation> - </message> - <message> - <source>Not found pre-selected input %s</source> - <translation type="unfinished">ورودی از پیش انتخاب شده %s پیدا نشد </translation> - </message> - <message> - <source>Not solvable pre-selected input %s</source> - <translation type="unfinished">ورودی از پیش انتخاب شده %s قابل محاسبه نیست </translation> - </message> - <message> - <source>Pruning blockstore…</source> - <translation type="unfinished">هرس بلوک فروشی…</translation> - </message> - <message> - <source>Replaying blocks…</source> - <translation type="unfinished">در حال پخش مجدد بلوک ها…</translation> - </message> - <message> - <source>Rescanning…</source> - <translation type="unfinished">در حال اسکن مجدد…</translation> - </message> - <message> - <source>Signing transaction failed</source> - <translation type="unfinished">ثبت تراکنش با خطا مواجه شد</translation> - </message> - <message> - <source>Starting network threads…</source> - <translation type="unfinished">شروع رشته های شبکه…</translation> - </message> - <message> - <source>The source code is available from %s.</source> - <translation type="unfinished">سورس کد موجود است از %s.</translation> - </message> - <message> - <source>The specified config file %s does not exist</source> - <translation type="unfinished">فایل پیکربندی مشخص شده %s وجود ندارد</translation> - </message> - <message> - <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">مبلغ معامله برای پرداخت هزینه بسیار ناچیز است - </translation> - </message> - <message> - <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation type="unfinished">کیف پول از پرداخت کمتر از حداقل هزینه رله جلوگیری خواهد کرد. - </translation> - </message> - <message> - <source>This is experimental software.</source> - <translation type="unfinished">این یک نرم افزار تجربی است.</translation> - </message> - <message> - <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation type="unfinished">این حداقل هزینه معامله ای است که شما در هر معامله پرداخت می کنید. - </translation> - </message> - <message> - <source>This is the transaction fee you will pay if you send a transaction.</source> - <translation type="unfinished">این هزینه تراکنش است که در صورت ارسال معامله پرداخت خواهید کرد. - </translation> - </message> - <message> - <source>Transaction amount too small</source> - <translation type="unfinished">حجم تراکنش خیلی کم است</translation> - </message> - <message> - <source>Transaction amounts must not be negative</source> - <translation type="unfinished">مقدار تراکنش نمیتواند منفی باشد.</translation> - </message> - <message> - <source>Transaction must have at least one recipient</source> - <translation type="unfinished">تراکنش باید حداقل یک دریافت کننده داشته باشد</translation> - </message> - <message> - <source>Transaction needs a change address, but we can't generate it.</source> - <translation type="unfinished">تراکنش به آدرس تغییر نیاز دارد، اما ما نمیتوانیم آن را ایجاد کنیم.</translation> - </message> - <message> - <source>Transaction too large</source> - <translation type="unfinished">حجم تراکنش خیلی زیاد است</translation> - </message> - <message> - <source>Unable to find UTXO for external input</source> - <translation type="unfinished">قادر به پیدا کردن UTXO برای ورودی جانبی نیست.</translation> - </message> - <message> - <source>Unable to generate initial keys</source> - <translation type="unfinished">نمیتوان کلید های اولیه را تولید کرد.</translation> - </message> - <message> - <source>Unable to generate keys</source> - <translation type="unfinished">نمیتوان کلید ها را تولید کرد</translation> - </message> - <message> - <source>Unable to open %s for writing</source> - <translation type="unfinished">برای نوشتن %s باز نمی شود</translation> - </message> - <message> - <source>Unable to parse -maxuploadtarget: '%s'</source> - <translation type="unfinished">قادر به تجزیه -maxuploadtarget نیست: '%s'</translation> - </message> - <message> - <source>Unable to start HTTP server. See debug log for details.</source> - <translation type="unfinished">سرور HTTP راه اندازی نمی شود. برای جزئیات به گزارش اشکال زدایی مراجعه کنید. - </translation> - </message> - <message> - <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">شبکه مشخص شده غیرقابل شناسایی در onlynet: '%s'</translation> - </message> - <message> - <source>Unknown new rules activated (versionbit %i)</source> - <translation type="unfinished">قوانین جدید ناشناخته فعال شد (%iversionbit)</translation> - </message> - <message> - <source>Verifying blocks…</source> - <translation type="unfinished">در حال تأیید بلوکها…</translation> - </message> - <message> - <source>Verifying wallet(s)…</source> - <translation type="unfinished">در حال تأیید کیف ها…</translation> - </message> - <message> - <source>Settings file could not be read</source> - <translation type="unfinished">فایل تنظیمات خوانده نشد</translation> - </message> - <message> - <source>Settings file could not be written</source> - <translation type="unfinished">فایل تنظیمات نوشته نشد</translation> - </message> -</context> + </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index cbf81afdb2..c72d64d7b9 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -2,8 +2,8 @@ <context> <name>AddressBookPage</name> <message> - <source>Create a new address</source> - <translation type="unfinished">Luo uusi osoite</translation> + <source>Right-click to edit address or label</source> + <translation type="unfinished">Valitse hiiren kakkospainikkeella muokataksesi osoitetta tai nimikettä</translation> </message> <message> <source>&New</source> @@ -54,10 +54,6 @@ <translation type="unfinished">V&alitse</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">Nämä ovat Bitcoin-osoitteesi maksujen lähettämistä varten. Tarkista aina määrä ja vastaanotto-osoite ennen kolikoiden lähettämistä.</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">Nämä ovat Bitcoin-osoitteesi maksujen vastaanottoa varten. Käytä painiketta "Luo uusi vastaanotto-osoite" vastaanottovälilehdessä luodaksesi uusia osoitteita. @@ -90,6 +86,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> @@ -172,6 +176,14 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Syötä vanha ja uusi salasanalause lompakolle.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Jatka</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Takaisin</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">Muista, että salaamalla lompakkosi et täysin pysty suojaamaan bitcoineja varkaudelta, jotka aiheutuvat koneellasi olevista haittaohjelmista.</translation> </message> @@ -291,6 +303,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 +327,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 +343,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> @@ -376,7 +421,11 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <numerusform>%n vuotta</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">oletuslompakko</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -616,6 +665,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 +719,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> @@ -678,10 +739,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Naamioi arvot Yhteenveto-välilehdessä</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">oletuslompakko</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Lompakoita ei ole saatavilla</translation> </message> @@ -725,6 +782,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 +815,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 +993,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 +1088,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">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 <wallet name>-<timestamp>.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>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Pelkästään katseltavissa olevat skriptit on siirretty uuteen lompakkoon nimeltä '%1'.</translation> + </message> + <message> + <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Ratkaistavat mutta ei katsotut skriptit on siirretty uuteen lompakkoon nimeltä '%1'.</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> @@ -1017,10 +1149,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Avoimen lompakon varoitus</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">oletuslompakko</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Avaa lompakko</translation> @@ -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,30 @@ 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>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 +2390,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 +2480,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 +2554,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 +2619,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 +2631,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> @@ -2323,6 +2644,10 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Verkkoliikenne pysäytetty</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ei yhtään</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Suoritetaan komento ilman lomakkoa</translation> </message> @@ -2331,6 +2656,22 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Suoritetaan komento käyttäen lompakkoa "%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">Tervetuloa %1 RPC-konsoliin. +Käytä ylä- ja alanuolinäppäintä historiassa navigoimiseen ja näppäintä %2 näytön tyhjentämiseen. +Käytä näppäimiä %3 ja %4 fonttikoon suurentamiseen ja pienentämiseen. +Näet yleiskuvan käytettävistä komennoista kirjoittamalla %5. +Lisätietoja konsolin käytöstä saat kirjoittamalla %6. +%7VAROITUS: Huijarit ovat aktiivisesti yrittäneet varastaa käyttäjien lompakoiden sisältöä pyytämällä heitä kirjoittamaan komentoja tänne. Älä käytä tätä konsolia, jos et täysin ymmärrän komennon seurauksia.%8</translation> + </message> + <message> <source>Executing…</source> <extracomment>A console message indicating an entered command is currently being executed.</extracomment> <translation type="unfinished">Suoritetaan...</translation> @@ -2463,6 +2804,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 +3022,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 +3039,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 +3138,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 +3174,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 +3205,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> @@ -2960,10 +3363,6 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">&Allekirjoita viesti</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">Voit allekirjoittaa viestit / sopimukset omalla osoitteellasi todistaaksesi että voit vastaanottaa siihen lähetetyt bitcoinit. Varo allekirjoittamasta mitään epämääräistä, sillä phishing-hyökkääjät voivat huijata sinua luovuttamaan henkilöllisyytesi allekirjoituksella. Allekirjoita ainoastaan täysin yksityiskohtainen selvitys siitä, mihin olet sitoutumassa.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin-osoite jolla viesti allekirjoitetaan</translation> </message> @@ -3048,10 +3447,6 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Tarkista osoite ja yritä uudelleen.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Syötetty osoite ei viittaa tunnettuun avaimeen.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Lompakon avaaminen peruttiin.</translation> </message> @@ -3111,6 +3506,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 +3630,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 +3843,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 +4000,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> @@ -3585,10 +4028,6 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <source>Can't display address</source> <translation type="unfinished">Osoitetta ei voida näyttää</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">oletuslompakko</translation> - </message> </context> <context> <name>WalletView</name> @@ -3641,6 +4080,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> @@ -3661,10 +4105,6 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Useampi onion bind -osoite on tarjottu. Automaattisesti luotua Torin onion-palvelua varten käytetään %s.</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">Tarkistathan että tietokoneesi päivämäärä ja kellonaika ovat oikeassa! Jos kellosi on väärässä, %s ei toimi oikein.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Ole hyvä ja avusta, jos %s on mielestäsi hyödyllinen. Vieraile %s saadaksesi lisää tietoa ohjelmistosta.</translation> </message> @@ -3737,10 +4177,6 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">-maxmempool on oltava vähintään %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Kriittinen sisäinen virhe kohdattiin, katso debug.log lisätietoja varten</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">-%s -osoitteen '%s' selvittäminen epäonnistui</translation> </message> @@ -3753,6 +4189,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 +4277,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 +4309,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 +4341,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 +4373,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 +4397,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 +4409,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 +4441,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 +4457,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 +4529,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 +4565,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,10 +4577,18 @@ 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> @@ -4065,6 +4605,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 +4621,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 +4653,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_fil.ts b/src/qt/locale/bitcoin_fil.ts index a8d32b00c0..8aca583655 100644 --- a/src/qt/locale/bitcoin_fil.ts +++ b/src/qt/locale/bitcoin_fil.ts @@ -222,6 +222,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>BitcoinApplication</name> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation type="unfinished">Isang fatal error ang naganap. %1 ay hindi na maaaring magpatuloy nang ligtas at magtitigil.</translation> + </message> + </context> +<context> <name>QObject</name> <message> <source>Error: %1</source> @@ -299,7 +306,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">walet na default</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -377,7 +388,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Palitan ang passphrase na ginamit para sa pag-enkripto ng pitaka</translation> + <translation type="unfinished">Palitan ang passphrase na ginamit para sa pag-encrypt ng walet</translation> </message> <message> <source>&Send</source> @@ -499,10 +510,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Ipakita sa %1 ang tulong na mensahe upang makuha ang talaan ng mga posibleng opsyon ng Bitcoin command-line</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">walet na default</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Walang magagamit na mga walet</translation> </message> @@ -540,6 +547,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Kamalian: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation type="unfinished">Babala:%1</translation> + </message> + <message> <source>Date: %1 </source> <translation type="unfinished">Datiles: %1 @@ -699,7 +710,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(%1 locked)</source> - <translation type="unfinished">(%1 ay naka-lock)</translation> + <translation type="unfinished">(%1 Naka-lock)</translation> </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> @@ -745,10 +756,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Buksan ang babala sa pitaka</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">walet na default</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Buksan ang Walet</translation> @@ -1569,8 +1576,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Mapped AS</source> - <translation type="unfinished">Mapa sa AS -</translation> + <translation type="unfinished">Mapa sa AS</translation> </message> <message> <source>User Agent</source> @@ -1686,6 +1692,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Ang aktibidad ng network ay hindi gumagana.</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Wala</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Isinasagawa ang command nang walang anumang walet.</translation> </message> @@ -2026,6 +2036,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Lumikha ng Unsigned</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">Lumilikha ng isang Bahagyang Signed Bitcoin Transaction (PSBT) para magamit sa hal. isang offline na%1 wallet, o isang wallet na hardware na katugma sa PSBT.</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation type="unfinished">%1 hanggang %2</translation> + </message> + <message> <source>%1 to %2</source> <translation type="unfinished">%1 sa %2</translation> </message> @@ -2191,10 +2209,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Pirmahan ang Mensahe</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">Maaari kang pumirma ng mga mensahe/kasunduan sa iyong mga address upang mapatunayan na maaari kang makatanggap ng mga bitcoin na ipinadala sa kanila. Mag-ingat na huwag pumirma ng anumang bagay na hindi malinaw o random, dahil ang mga phishing attack ay maaaring subukan na linlangin ka sa pagpirma ng iyong pagkakakilanlan sa kanila. Pumirma lamang ng kumpletong mga pahayag na sumasang-ayon ka.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Ang Bitcoin address kung anong ipipirma sa mensahe</translation> </message> @@ -2271,10 +2285,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Mangyaring suriin ang address at subukang muli.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Ang pinasok na address ay hindi tumutukoy sa isang key.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Kinansela ang pag-unlock ng walet.</translation> </message> @@ -2712,11 +2722,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Could not commit transaction</source> <translation type="unfinished">Hindi makagawa ng transaksyon</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">walet na default</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -2767,10 +2773,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Naipamahagi sa ilalim ng lisensya ng MIT software, tingnan ang kasamang file %s o %s</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">Mangyaring suriin na ang petsa at oras ng iyong computer ay tama! Kung mali ang iyong orasan, ang %s ay hindi gagana nang maayos.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Mangyaring tumulong kung natagpuan mo ang %s kapaki-pakinabang. Bisitahin ang %s para sa karagdagang impormasyon tungkol sa software.</translation> </message> diff --git a/src/qt/locale/bitcoin_fo.ts b/src/qt/locale/bitcoin_fo.ts index 2d6a543454..15dc1b50d4 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> @@ -282,7 +286,7 @@ </message> <message> <source>Bytes:</source> - <translation type="unfinished">Byte:</translation> + <translation type="unfinished">Být:</translation> </message> <message> <source>Amount:</source> @@ -860,7 +864,7 @@ </message> <message> <source>Bytes:</source> - <translation type="unfinished">Byte:</translation> + <translation type="unfinished">Být:</translation> </message> <message> <source>Amount:</source> @@ -879,6 +883,10 @@ <translation type="unfinished">Adressa til vekslipening</translation> </message> <message> + <source>per kilobyte</source> + <translation type="unfinished">per kilobýt</translation> + </message> + <message> <source>Hide</source> <translation type="unfinished">Loka</translation> </message> @@ -1001,10 +1009,6 @@ <translation type="unfinished">&Undirrita Boð</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">Tú kann skriva undir boð/sáttmálar við tínum adressum, fyri at prógva at tú kanst móttaka bitcoin sendar til tær. Ver ansin so tú ikki skrivar undir nakað ógreitt ella tilvildarligt, tí fysking-álop kunnu royna at snýta teg til at latað tín samleika til tey. Undirrita einans nágreiniligar útsagnir ið tú tekur undir við.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin adressan at undirskriva boðini við</translation> </message> @@ -1265,10 +1269,6 @@ <translation type="unfinished">%s umbøn at lurta á portur %u. Hetta portrið er tulkað "óhóskandi" og tí er ósannlíkt at nakar viðskiftari sambindur í tað. Sí lista yvir "óhóskandi" portur og nágreiniligari upplýsingar í doc/p2p-bad-ports.md.</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">Vinaliga tryggja at dagfesting og tíð, í teldu tíni, eru røtt! Er klokkan skeiv virkar %s ikki sum ætlað.</translation> - </message> - <message> <source>%s is set very high!</source> <translation type="unfinished">Ásetingin %s er sera høgt!</translation> </message> diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 796e1affe6..5ff6d09dbd 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -35,7 +35,7 @@ </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exporter les données de l'onglet actuel vers un fichier</translation> + <translation type="unfinished">Exporter les données de l’onglet actuel vers un fichier</translation> </message> <message> <source>&Export</source> @@ -47,7 +47,7 @@ </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished">Choisir l'adresse à laquelle envoyer des pièces</translation> + <translation type="unfinished">Choisir l’adresse à laquelle envoyer des pièces</translation> </message> <message> <source>Choose the address to receive coins with</source> @@ -81,7 +81,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Export Address List</source> - <translation type="unfinished">Exporter la liste d'adresses</translation> + <translation type="unfinished">Exporter la liste d’adresses</translation> </message> <message> <source>Comma separated file</source> @@ -103,7 +103,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Exporting Failed</source> - <translation type="unfinished">Échec d'exportation</translation> + <translation type="unfinished">Échec d’exportation</translation> </message> </context> <context> @@ -184,6 +184,14 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr <translation type="unfinished">Saisir l’ancienne puis la nouvelle phrase de passe du porte-monnaie.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Poursuivre</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Retour</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">N’oubliez pas que le chiffrement de votre porte-monnaie ne peut pas protéger entièrement vos bitcoins contre le vol par des programmes malveillants qui infecteraient votre ordinateur.</translation> </message> @@ -229,7 +237,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">La phrase de passe du porte-monnaie a été modifiée.</translation> + <translation type="unfinished">La phrase de passe du porte-monnaie a été modifiée avec succès.</translation> </message> <message> <source>Passphrase change failed</source> @@ -439,6 +447,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr <source>%1 GB</source> <translation type="unfinished">%1 Go</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">porte-monnaie par défaut</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -505,11 +517,11 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Send coins to a Bitcoin address</source> - <translation type="unfinished">Envoyer des pièces à une adresse Bitcoin</translation> + <translation type="unfinished">Envoyer des pièces à une adresse Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> - <translation type="unfinished">Sauvegarder le porte-monnaie dans un autre emplacement</translation> + <translation type="unfinished">Sauvegarder le porte-monnaie vers un autre emplacement</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> @@ -533,7 +545,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&Sauvegarder le porte-monnaie…</translation> + <translation type="unfinished">&auvegarder le porte-monnaie…</translation> </message> <message> <source>&Change Passphrase…</source> @@ -557,7 +569,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Charger la TBSP d’un fichier…</translation> + <translation type="unfinished">&Charger une TBSP d’un fichier…</translation> </message> <message> <source>Open &URI…</source> @@ -617,11 +629,11 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Afficher la liste d’adresses d’envoi et d’étiquettes utilisées</translation> + <translation type="unfinished">Afficher la liste d’adresses et d’étiquettes d’envoi utilisées</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Afficher la liste d’adresses de réception et d’étiquettes utilisées</translation> + <translation type="unfinished">Afficher la liste d’adresses et d’étiquettes de réception utilisées</translation> </message> <message> <source>&Command-line options</source> @@ -684,7 +696,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Ouvrir une console de débogage des nœuds et de diagnostic</translation> + <translation type="unfinished">Ouvrir une console de débogage de nœuds et de diagnostic</translation> </message> <message> <source>&Sending addresses</source> @@ -700,7 +712,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Ouvrir un porte-monnaie</translation> + <translation type="unfinished">Ouvrir le porte-monnaie</translation> </message> <message> <source>Open a wallet</source> @@ -745,10 +757,6 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr <translation type="unfinished">Masquer les montants dans l’onglet Vue d’ensemble</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Aucun porte-monnaie n’est proposé</translation> </message> @@ -800,8 +808,8 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>%n connexion active vers le réseau Bitcoin.</numerusform> - <numerusform>%n de connexions actives vers le réseau Bitcoin.</numerusform> + <numerusform>%n connexion active avec le réseau Bitcoin.</numerusform> + <numerusform>%n connexions actives avec le réseau Bitcoin.</numerusform> </translation> </message> <message> @@ -988,11 +996,11 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr </message> <message> <source>Copy &label</source> - <translation type="unfinished">Copier l’é&tiquette</translation> + <translation type="unfinished">Copier l’&étiquette</translation> </message> <message> <source>Copy &amount</source> - <translation type="unfinished">Copier le mont&ant</translation> + <translation type="unfinished">Copier le &montant</translation> </message> <message> <source>Copy transaction &ID and output index</source> @@ -1133,11 +1141,11 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </message> <message> <source>Migration failed</source> - <translation type="unfinished">La migration a échoué</translation> + <translation type="unfinished">Échec de migration</translation> </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> @@ -1151,10 +1159,6 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio <translation type="unfinished">Avertissement d’ouverture du porte-monnaie</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Ouvrir un porte-monnaie</translation> @@ -1223,7 +1227,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 +1386,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 +1450,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> @@ -1507,7 +1511,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </message> <message> <source>calculating…</source> - <translation type="unfinished">calcul en cours…</translation> + <translation type="unfinished">calcul…</translation> </message> <message> <source>Last block time</source> @@ -1543,7 +1547,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 +1594,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 +1614,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 +1866,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 +1912,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 +1998,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 +2176,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> @@ -2285,6 +2294,14 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Nombre de connexions</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Adresses locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Adresses réseau que votre nœud Bitcoin utilise actuellement pour communiquer avec d’autres nœuds.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Chaîne de blocs</translation> </message> @@ -2333,20 +2350,20 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Sélectionnez un pair pour afficher des renseignements détaillés.</translation> </message> <message> - <source>The transport layer version: %1</source> - <translation type="unfinished">La version de la couche de transport : %1</translation> + <source>Hide Peers Detail</source> + <translation type="unfinished">Cacher les détails des pairs</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> + <source>The transport layer version: %1</source> + <translation type="unfinished">Version de la couche de transport : %1</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 +2406,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 +2456,14 @@ 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 BIP324 session ID string in hex.</source> + <translation type="unfinished">ID hexadécimale de la session BIP324.</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 +2585,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> @@ -2623,6 +2648,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">L’activité réseau est désactivée</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Aucun</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Exécution de la commande sans aucun porte-monnaie</translation> </message> @@ -2783,8 +2812,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 +2876,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 +3195,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 +3216,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> @@ -3219,6 +3258,13 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <source>A fee higher than %1 is considered an absurdly high fee.</source> <translation type="unfinished">Des frais supérieurs à %1 sont considérés comme ridiculement élevés.</translation> </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation type="unfinished"> + <numerusform>Début de confirmation estimé à %n bloc.</numerusform> + <numerusform>Début de confirmation estimé à %n de blocs.</numerusform> + </translation> + </message> <message> <source>Warning: Invalid Bitcoin address</source> <translation type="unfinished">Avertissement : L’adresse Bitcoin est invalide</translation> @@ -3321,8 +3367,8 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <translation type="unfinished">&Signer un message</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">Vous pouvez signer des messages ou des accords avec vos adresses pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Faites attention de ne rien signer de vague ou au hasard, car des attaques d’hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l’usurper. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous êtes d’accord.</translation> + <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">Vous pouvez signer des messages ou des accords avec vos anciennes adresses (P2PKH) pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Ne signer rien de vague ou au hasard, car des attaques d’hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l’usurper. Ne signez que des déclarations entièrement détaillées et que vous acceptez.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3405,8 +3451,8 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <translation type="unfinished">Veuillez vérifier l’adresse et réessayer.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">L’adresse saisie ne fait pas référence à une clé.</translation> + <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">L’adresse saisie ne fait pas référence à une ancienne clé (P2PKH). La signature des messages n’est pas prise en charge pour SegWit ni pour les autres types d’adresses non P2PKH dans cette version de %1. Vérifiez l’adresse et réessayez.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3477,12 +3523,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> @@ -3842,7 +3888,7 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi </message> <message> <source>Exporting Failed</source> - <translation type="unfinished">Échec d'exportation</translation> + <translation type="unfinished">Échec d’exportation</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> @@ -3912,7 +3958,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 +3987,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> @@ -3952,9 +3998,8 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">La TBPS a été copiée</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copié dans le presse-papiers</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">La TBSP des augmentations de frais a été copiée dans le presse-papiers.</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3965,12 +4010,12 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Impossible de valider la transaction</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Impossible d’afficher l’adresse</translation> + <source>Signer error</source> + <translation type="unfinished">Erreur de signataire</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> + <source>Can't display address</source> + <translation type="unfinished">Impossible d’afficher l’adresse</translation> </message> </context> <context> @@ -3981,7 +4026,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exporter les données de l'onglet actuel vers un fichier</translation> + <translation type="unfinished">Exporter les données de l’onglet actuel vers un fichier</translation> </message> <message> <source>Backup Wallet</source> @@ -4025,11 +4070,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 +4090,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> @@ -4104,10 +4149,6 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Aucun format de fichier de porte-monnaie n’a été indiqué. Pour utiliser createfromdump, -format=<format> doit être indiqué.</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">Veuillez vérifier que l’heure et la date de votre ordinateur sont justes. Si votre horloge n’est pas à l’heure, %s ne fonctionnera pas correctement.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Si vous trouvez %s utile, veuillez y contribuer. Pour de plus de précisions sur le logiciel, rendez-vous sur %s.</translation> </message> @@ -4117,7 +4158,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 +4166,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">Échec de renommage de '%s' en '%s'. 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 +4214,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> @@ -4216,10 +4257,6 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">-maxmempool doit être d’au moins %d Mo</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Une erreur interne fatale est survenue. Consulter debug.log pour plus de précisions</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Impossible de résoudre l’adresse -%s : « %s »</translation> </message> @@ -4237,7 +4274,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 +4286,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 +4302,12 @@ 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 remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Échec de suppression du répertoire de l’instantané d’état de la chaîne (%s). Supprimez-le manuellement avant de redémarrer.</translation> </message> <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> @@ -4273,31 +4315,55 @@ 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>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Échec de vidage du fichier des blocs sur le disque, probablement à cause d’une erreur d’E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Échec de vidage du fichier d’annulation sur le disque, probablement à cause d’une erreur d’E/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>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Le poids maximal de la transaction est inférieur au poids de la transaction sans entrées</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Le poids maximal de la transaction est trop faible et ne permet pas les sorties de monnaie</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>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Échec de renommage de « %s » en « %s ». Impossible de nettoyer le répertoire de la base de données d’état de chaîne d’arrière-plan.</translation> + </message> + <message> + <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">La combinaison des entrées présélectionnées et de la sélection automatique des entrées du porte-monnaie dépasse le poids maximal de la transaction. Essayez d’envoyer un montant inférieur ou de consolider manuellement les UTXO de votre porte-monnaie.</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 +4371,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> @@ -4342,10 +4408,14 @@ Essayez d’utiliser la version la plus récente du logiciel. </translation> </message> <message> + <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">La date et l’heure de votre ordinateur semblent décalées de plus de %d minutes par rapport au réseau, ce qui peut entraîner un échec de consensus. Après avoir confirmé l’heure de votre ordinateur, ce message ne devrait plus s’afficher après redémarrage de votre nœud. Sans redémarrage, il devrait cesser de s’afficher automatiquement si vous vous connectez à suffisamment de nouveaux pairs sortants, ce qui peut prendre du temps. Pour plus de précisions, vous pouvez inspecter le champ `timeoffset` des méthodes RPC `getpeerinfo` et `getnetworkinfo`.</translation> + </message> + <message> <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> @@ -4354,6 +4424,18 @@ Unable to restore backup of wallet.</source> Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">« whitebind » ne peut être utilisé que pour les connexions entrantes (« out » a été passé)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Une erreur interne fatale est survenue. Pour plus de précisions, consultez debug.log :</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Les données Assumeutxo sont introuvables pour l’empreinte de bloc « %s » donnée.</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">La vérification des blocs a été interrompue</translation> </message> @@ -4366,6 +4448,10 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> <translation type="unfinished">Tous droits réservés © %i à %i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Un bloc corrompu a été détecté, ce qui indique une défaillance matérielle possible.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Une base de données des blocs corrompue a été détectée</translation> </message> @@ -4394,6 +4480,10 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> <translation type="unfinished">Le fichier de vidage %s n’existe pas.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Échec du contrôle d’intégrité de la cryptographie à courbe elliptique. Fermeture de %s.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Erreur de validation de la transaction de base de données pour la suppression des transactions du porte-monnaie</translation> </message> @@ -4435,7 +4525,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 +4541,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> @@ -4542,22 +4632,50 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> <translation type="unfinished">Erreur ; La transaction de la base de données ne peut pas être exécutée pour le porte-monnaie %s</translation> </message> <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">Échec de connexion du meilleur bloc (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Échec de déconnexion du bloc.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Échec d’écoute sur tous les ports. Si cela est voulu, utiliser -listen=0.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Échec de lecture du bloc.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Échec de réanalyse du porte-monnaie lors de l’initialisation</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> <translation type="unfinished">Échec de vérification de la base de données</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">Échec d’écriture du bloc.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Échec d’écriture dans la base de données d’index des blocs.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Échec d’écriture dans la base de données des pièces.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Échec d’écriture des données d’annulation.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">Échec de retrait de la transaction :%s</translation> </message> @@ -4587,7 +4705,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 +4729,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 +4745,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> @@ -4654,6 +4772,10 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> <translation type="unfinished">Chargement du porte-monnaie…</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Le poids maximal de la transaction doit être compris entre %d et %d</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Le montant manque</translation> </message> @@ -4675,13 +4797,17 @@ 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> <translation type="unfinished">Entrée présélectionnée non soluble %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Seule la direction a été définie, sans permissions : « %s »</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">L’élagage ne peut pas être configuré avec une valeur négative</translation> </message> @@ -4726,6 +4852,18 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> <translation type="unfinished">La section [%s] n’est pas reconnue</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Le signataire n’a pas renvoyé l’adresse</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">Le signataire a renvoyé une adresse inattendue %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Le signataire a renvoyé une erreur : %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Échec de signature de la transaction</translation> </message> @@ -4747,13 +4885,25 @@ 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> <translation type="unfinished">Démarrage des processus réseau…</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Erreur système lors du vidage : %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Erreur système lors du chargement d’un fichier de blocs externe : %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Erreur système lors de l’enregistrement du bloc sur le disque : %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Le code source est publié sur %s.</translation> </message> @@ -4770,6 +4920,10 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> <translation type="unfinished">Le porte-monnaie évitera de payer moins que les frais minimaux de relais.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Il n’y a pas de « ScriptPubKeyManager » pour cette adresse.</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Ce logiciel est expérimental.</translation> </message> @@ -4787,7 +4941,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Transaction amount too small</source> - <translation type="unfinished">Le montant de la transaction est trop bas</translation> + <translation type="unfinished">Le montant de la transaction est trop petit</translation> </message> <message> <source>Transaction amounts must not be negative</source> @@ -4807,11 +4961,7 @@ 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> - </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">La transaction est trop élevée</translation> </message> <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> @@ -4827,7 +4977,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 +5001,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> @@ -4874,8 +5024,12 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> <translation type="unfinished">Les nouvelles règles inconnues sont activées (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Une option non reconnue « %s » a été indiquée dans -test=<option>.</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 +5037,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 +5065,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_fr_CM.ts b/src/qt/locale/bitcoin_fr_CM.ts index 50d27a4f85..07ceebc2ef 100644 --- a/src/qt/locale/bitcoin_fr_CM.ts +++ b/src/qt/locale/bitcoin_fr_CM.ts @@ -180,6 +180,14 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">Saisir l’ancienne puis la nouvelle phrase de passe du porte-monnaie.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Poursuivre</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Retour</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">N’oubliez pas que le chiffrement de votre porte-monnaie ne peut pas protéger entièrement vos bitcoins contre le vol par des programmes malveillants qui infecteraient votre ordinateur.</translation> </message> @@ -435,6 +443,10 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <source>%1 GB</source> <translation type="unfinished">%1 Go</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">porte-monnaie par défaut</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -501,11 +513,11 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Send coins to a Bitcoin address</source> - <translation type="unfinished">Envoyer des pièces à une adresse Bitcoin</translation> + <translation type="unfinished">Envoyer des pièces à une adresse Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> - <translation type="unfinished">Sauvegarder le porte-monnaie dans un autre emplacement</translation> + <translation type="unfinished">Sauvegarder le porte-monnaie vers un autre emplacement</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> @@ -520,6 +532,10 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">&Recevoir</translation> </message> <message> + <source>&Options…</source> + <translation type="unfinished">&Choix</translation> + </message> + <message> <source>&Encrypt Wallet…</source> <translation type="unfinished">&Chiffrer le porte-monnaie…</translation> </message> @@ -529,7 +545,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&Sauvegarder le porte-monnaie…</translation> + <translation type="unfinished">&auvegarder le porte-monnaie…</translation> </message> <message> <source>&Change Passphrase…</source> @@ -553,7 +569,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Charger la TBSP d’un fichier…</translation> + <translation type="unfinished">&Charger une TBSP d’un fichier…</translation> </message> <message> <source>Open &URI…</source> @@ -589,7 +605,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Synchronisation des en-têtes (%1 %)…</translation> + <translation type="unfinished">Synchronisation des en-têtes (%1)…</translation> </message> <message> <source>Synchronizing with network…</source> @@ -613,11 +629,11 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Afficher la liste d’adresses d’envoi et d’étiquettes utilisées</translation> + <translation type="unfinished">Afficher la liste d’adresses et d’étiquettes d’envoi utilisées</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Afficher la liste d’adresses de réception et d’étiquettes utilisées</translation> + <translation type="unfinished">Afficher la liste d’adresses et d’étiquettes de réception utilisées</translation> </message> <message> <source>&Command-line options</source> @@ -636,7 +652,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Catching up…</source> - <translation type="unfinished">Rattrapage en cours…</translation> + <translation type="unfinished">Rattrapage…</translation> </message> <message> <source>Last received block was generated %1 ago.</source> @@ -656,7 +672,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Information</source> - <translation type="unfinished">Informations</translation> + <translation type="unfinished">Renseignements</translation> </message> <message> <source>Up to date</source> @@ -680,7 +696,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Ouvrir une console de débogage des nœuds et de diagnostic</translation> + <translation type="unfinished">Ouvrir une console de débogage de nœuds et de diagnostic</translation> </message> <message> <source>&Sending addresses</source> @@ -696,7 +712,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Ouvrir un porte-monnaie</translation> + <translation type="unfinished">Ouvrir le porte-monnaie</translation> </message> <message> <source>Open a wallet</source> @@ -741,10 +757,6 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">Masquer les montants dans l’onglet Vue d’ensemble</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Aucun porte-monnaie n’est disponible</translation> </message> @@ -1092,6 +1104,10 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">Migrer le portefeuille</translation> </message> <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">Êtes-vous sûr de vouloir migrer le portefeuille <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. @@ -1143,10 +1159,6 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant la migra <translation type="unfinished">Avertissement d’ouverture du porte-monnaie</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Ouvrir un porte-monnaie</translation> @@ -2282,6 +2294,14 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Nombre de connexions</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Adresses locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Adresses réseau que votre nœud Bitcoin utilise actuellement pour communiquer avec d’autres nœuds.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Chaîne de blocs</translation> </message> @@ -2330,12 +2350,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Sélectionnez un pair pour afficher des renseignements détaillés.</translation> </message> <message> - <source>The transport layer version: %1</source> - <translation type="unfinished">La version de la couche de transport : %1</translation> + <source>Hide Peers Detail</source> + <translation type="unfinished">Cacher les détails des pairs</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> + <source>The transport layer version: %1</source> + <translation type="unfinished">La version de la couche de transport : %1</translation> </message> <message> <source>Session ID</source> @@ -2436,6 +2456,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>The BIP324 session ID string in hex.</source> + <translation type="unfinished">ID hexadécimale de la session BIP324.</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> @@ -2620,6 +2644,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">L’activité réseau est désactivée</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Aucun</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Exécution de la commande sans aucun porte-monnaie</translation> </message> @@ -3216,6 +3244,13 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <source>A fee higher than %1 is considered an absurdly high fee.</source> <translation type="unfinished">Des frais supérieurs à %1 sont considérés comme ridiculement élevés.</translation> </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation type="unfinished"> + <numerusform>Début de confirmation estimé à %n bloc.</numerusform> + <numerusform>Début de confirmation estimé à %n blocs.</numerusform> + </translation> + </message> <message> <source>Warning: Invalid Bitcoin address</source> <translation type="unfinished">Avertissement : L’adresse Bitcoin est invalide</translation> @@ -3318,8 +3353,8 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <translation type="unfinished">&Signer un message</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">Vous pouvez signer des messages ou des accords avec vos adresses pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Faites attention de ne rien signer de vague ou au hasard, car des attaques d’hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l’usurper. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous êtes d’accord.</translation> + <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">Vous pouvez signer des messages ou des accords avec vos anciennes adresses (P2PKH) pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Ne signer rien de vague ou au hasard, car des attaques d’hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l’usurper. Ne signez que des déclarations entièrement détaillées et que vous acceptez.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3402,8 +3437,8 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <translation type="unfinished">Veuillez vérifier l’adresse et réessayer.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">L’adresse saisie ne fait pas référence à une clé.</translation> + <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">L’adresse saisie ne fait pas référence à une ancienne clé (P2PKH). La signature des messages n’est pas prise en charge pour SegWit ni pour les autres types d’adresses non P2PKH dans cette version de %1. Vérifiez l’adresse et réessayez.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3949,9 +3984,8 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">La TBPS a été copiée</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copié dans le presse-papiers</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">La TBSP des augmentations de frais a été copiée dans le presse-papiers.</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3962,12 +3996,12 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Impossible de valider la transaction</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Impossible d’afficher l’adresse</translation> + <source>Signer error</source> + <translation type="unfinished">Erreur de signataire</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> + <source>Can't display address</source> + <translation type="unfinished">Impossible d’afficher l’adresse</translation> </message> </context> <context> @@ -4101,10 +4135,6 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Aucun format de fichier de porte-monnaie n’a été indiqué. Pour utiliser createfromdump, -format=<format> doit être indiqué.</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">Veuillez vérifier que l’heure et la date de votre ordinateur sont justes. Si votre horloge n’est pas à l’heure, %s ne fonctionnera pas correctement.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Si vous trouvez %s utile, veuillez y contribuer. Pour de plus de précisions sur le logiciel, rendez-vous sur %s.</translation> </message> @@ -4213,10 +4243,6 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">-maxmempool doit être d’au moins %d Mo</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Une erreur interne fatale est survenue. Consulter debug.log pour plus de précisions</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Impossible de résoudre l’adresse -%s : « %s »</translation> </message> @@ -4265,6 +4291,11 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <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> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Échec de suppression du répertoire de l’instantané d’état de la chaîne (%s). Supprimez-le manuellement avant de redémarrer.</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">Échec de renommage du fichier peers.dat invalide. Veuillez le déplacer ou le supprimer, puis réessayer.</translation> </message> @@ -4273,6 +4304,14 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">L'estimation des frais a échoué. Fallbackfee est désactivé. Attendez quelques blocs ou activez %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Échec de vidage du fichier des blocs sur le disque, probablement à cause d’une erreur d’E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Échec de vidage du fichier d’annulation sur le disque, probablement à cause d’une erreur d’E/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> </message> @@ -4281,6 +4320,14 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <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> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Le poids maximal de la transaction est inférieur au poids de la transaction sans entrées</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Le poids maximal de la transaction est trop faible et ne permet pas les sorties de monnaie</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> </message> @@ -4297,6 +4344,14 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Connexions sortantes limitées à i2p (-onlynet=i2p) mais -i2psam n'est pas fourni</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Échec de renommage de « %s » en « %s ». Impossible de nettoyer le répertoire de la base de données d’état de chaîne d’arrière-plan.</translation> + </message> + <message> + <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">La combinaison des entrées présélectionnées et de la sélection automatique des entrées du porte-monnaie dépasse le poids maximal de la transaction. Essayez d’envoyer un montant inférieur ou de consolider manuellement les UTXO de votre porte-monnaie.</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">La taille des entrées dépasse le poids maximum. Veuillez essayer d'envoyer un montant plus petit ou de consolider manuellement les UTXOs de votre portefeuille</translation> </message> @@ -4332,15 +4387,21 @@ Le portefeuille peut avoir été altéré ou créé avec des intentions malveill The wallet might had been created on a newer version. Please try running the latest software version. </source> - <translation type="unfinished">Descripteur non reconnu trouvé. Chargement du portefeuille %ss + <translation type="unfinished">Descripteur non reconnu trouvé. Chargement du portefeuille %s Le portefeuille a peut-être été créé avec une version plus récente. -Veuillez essayer d'utiliser la dernière version du logiciel.</translation> +Veuillez essayer d'utiliser la dernière version du logiciel. +</translation> + </message> + <message> + <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">La date et l’heure de votre ordinateur semblent décalées de plus de %d minutes par rapport au réseau, ce qui peut entraîner un échec de consensus. Après avoir confirmé l’heure de votre ordinateur, ce message ne devrait plus s’afficher après redémarrage de votre nœud. Sans redémarrage, il devrait cesser de s’afficher automatiquement si vous vous connectez à suffisamment de nouveaux pairs sortants, ce qui peut prendre du temps. Pour plus de précisions, vous pouvez inspecter le champ `timeoffset` des méthodes RPC `getpeerinfo` et `getnetworkinfo`.</translation> </message> <message> <source> Unable to cleanup failed migration</source> - <translation type="unfinished">Impossible de corriger l'échec de la migration</translation> + <translation type="unfinished"> +Impossible de corriger l'échec de la migration</translation> </message> <message> <source> @@ -4349,6 +4410,18 @@ Unable to restore backup of wallet.</source> Impossible de restaurer la sauvegarde du portefeuille.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">« whitebind » ne peut être utilisé que pour les connexions entrantes (« out » a été passé)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Une erreur interne fatale est survenue. Pour plus de précisions, consultez debug.log :</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Les données Assumeutxo sont introuvables pour l’empreinte de bloc « %s » donnée.</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">La vérification des blocs a été interrompue</translation> </message> @@ -4361,6 +4434,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Tous droits réservés © %i à %i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Un bloc corrompu a été détecté, ce qui indique une défaillance matérielle possible.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Une base de données des blocs corrompue a été détectée</translation> </message> @@ -4389,6 +4466,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Le fichier de vidage %s n’existe pas.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Échec du contrôle d’intégrité de la cryptographie à courbe elliptique. Fermeture de %s.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Erreur de validation des transactions de la base de données pour la suppression des transactions du porte-monnaie</translation> </message> @@ -4537,10 +4618,22 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Erreur ; La transaction de la base de données ne peut pas être exécutée pour le porte-monnaie %s</translation> </message> <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">Échec de connexion du meilleur bloc (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Échec de déconnexion du bloc.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Échec d'écoute sur tous les ports. Si cela est voulu, utiliser -listen=0.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Échec de lecture du bloc.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Échec de réanalyse du porte-monnaie lors de l’initialisation</translation> </message> @@ -4553,6 +4646,22 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Échec de vérification de la base de données</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">Échec d’écriture du bloc.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Échec d’écriture dans la base de données d’index des blocs.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Échec d’écriture dans la base de données des pièces.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Échec d’écriture des données d’annulation.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">Échec de suppression de la transaction :%s</translation> </message> @@ -4649,6 +4758,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Chargement du porte-monnaie…</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Le poids maximal de la transaction doit être compris entre %d et %d</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Le montant manque</translation> </message> @@ -4677,6 +4790,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Entrée présélectionnée non solvable %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Seule la direction a été définie, sans permissions : « %s »</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">L’élagage ne peut pas être configuré avec une valeur négative</translation> </message> @@ -4721,6 +4838,18 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">La section [%s] n’est pas reconnue</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Le signataire n’a pas fait écho à l’adresse</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">Le signataire a renvoyé une adresse inattendue %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Le signataire a renvoyé une erreur : %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Échec de signature de la transaction</translation> </message> @@ -4749,6 +4878,18 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Démarrage des processus réseau…</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Erreur système lors du vidage : %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Erreur système lors du chargement d’un fichier de blocs externe : %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Erreur système lors de l’enregistrement du bloc sur le disque : %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Le code source est publié sur %s.</translation> </message> @@ -4765,6 +4906,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Le porte-monnaie évitera de payer moins que les frais minimaux de relais.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Il n’y a pas de « ScriptPubKeyManager » pour cette adresse.</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Ce logiciel est expérimental.</translation> </message> @@ -4805,10 +4950,6 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">La transaction est trop grosse</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Impossible d'allouer de la mémoire pour -maxsigcachesize : '%s' Mo</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Impossible de se lier à %s sur cet ordinateur (la liaison a retourné l’erreur %s)</translation> </message> @@ -4869,6 +5010,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Les nouvelles règles inconnues sont activées (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Une option non reconnue « %s » a été indiquée dans -test=<option>.</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> </message> diff --git a/src/qt/locale/bitcoin_fr_LU.ts b/src/qt/locale/bitcoin_fr_LU.ts index 1c0fd095c4..76800c5658 100644 --- a/src/qt/locale/bitcoin_fr_LU.ts +++ b/src/qt/locale/bitcoin_fr_LU.ts @@ -180,6 +180,14 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">Saisir l’ancienne puis la nouvelle phrase de passe du porte-monnaie.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Poursuivre</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Retour</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">N’oubliez pas que le chiffrement de votre porte-monnaie ne peut pas protéger entièrement vos bitcoins contre le vol par des programmes malveillants qui infecteraient votre ordinateur.</translation> </message> @@ -435,6 +443,10 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <source>%1 GB</source> <translation type="unfinished">%1 Go</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">porte-monnaie par défaut</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -501,11 +513,11 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Send coins to a Bitcoin address</source> - <translation type="unfinished">Envoyer des pièces à une adresse Bitcoin</translation> + <translation type="unfinished">Envoyer des pièces à une adresse Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> - <translation type="unfinished">Sauvegarder le porte-monnaie dans un autre emplacement</translation> + <translation type="unfinished">Sauvegarder le porte-monnaie vers un autre emplacement</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> @@ -520,6 +532,10 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">&Recevoir</translation> </message> <message> + <source>&Options…</source> + <translation type="unfinished">&Choix</translation> + </message> + <message> <source>&Encrypt Wallet…</source> <translation type="unfinished">&Chiffrer le porte-monnaie…</translation> </message> @@ -529,7 +545,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&Sauvegarder le porte-monnaie…</translation> + <translation type="unfinished">&auvegarder le porte-monnaie…</translation> </message> <message> <source>&Change Passphrase…</source> @@ -553,7 +569,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Charger la TBSP d’un fichier…</translation> + <translation type="unfinished">&Charger une TBSP d’un fichier…</translation> </message> <message> <source>Open &URI…</source> @@ -589,7 +605,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Synchronisation des en-têtes (%1 %)…</translation> + <translation type="unfinished">Synchronisation des en-têtes (%1)…</translation> </message> <message> <source>Synchronizing with network…</source> @@ -613,11 +629,11 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Afficher la liste d’adresses d’envoi et d’étiquettes utilisées</translation> + <translation type="unfinished">Afficher la liste d’adresses et d’étiquettes d’envoi utilisées</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Afficher la liste d’adresses de réception et d’étiquettes utilisées</translation> + <translation type="unfinished">Afficher la liste d’adresses et d’étiquettes de réception utilisées</translation> </message> <message> <source>&Command-line options</source> @@ -636,7 +652,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Catching up…</source> - <translation type="unfinished">Rattrapage en cours…</translation> + <translation type="unfinished">Rattrapage…</translation> </message> <message> <source>Last received block was generated %1 ago.</source> @@ -656,7 +672,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Information</source> - <translation type="unfinished">Informations</translation> + <translation type="unfinished">Renseignements</translation> </message> <message> <source>Up to date</source> @@ -680,7 +696,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Ouvrir une console de débogage des nœuds et de diagnostic</translation> + <translation type="unfinished">Ouvrir une console de débogage de nœuds et de diagnostic</translation> </message> <message> <source>&Sending addresses</source> @@ -696,7 +712,7 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Ouvrir un porte-monnaie</translation> + <translation type="unfinished">Ouvrir le porte-monnaie</translation> </message> <message> <source>Open a wallet</source> @@ -741,10 +757,6 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">Masquer les montants dans l’onglet Vue d’ensemble</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Aucun porte-monnaie n’est disponible</translation> </message> @@ -1092,6 +1104,10 @@ La signature n'est possible qu'avec les adresses de type "patrimoine".</translat <translation type="unfinished">Migrer le portefeuille</translation> </message> <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">Êtes-vous sûr de vouloir migrer le portefeuille <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. @@ -1143,10 +1159,6 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant la migra <translation type="unfinished">Avertissement d’ouverture du porte-monnaie</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Ouvrir un porte-monnaie</translation> @@ -2282,6 +2294,14 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Nombre de connexions</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Adresses locales</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Adresses réseau que votre nœud Bitcoin utilise actuellement pour communiquer avec d’autres nœuds.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Chaîne de blocs</translation> </message> @@ -2330,12 +2350,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Sélectionnez un pair pour afficher des renseignements détaillés.</translation> </message> <message> - <source>The transport layer version: %1</source> - <translation type="unfinished">La version de la couche de transport : %1</translation> + <source>Hide Peers Detail</source> + <translation type="unfinished">Cacher les détails des pairs</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> + <source>The transport layer version: %1</source> + <translation type="unfinished">La version de la couche de transport : %1</translation> </message> <message> <source>Session ID</source> @@ -2436,6 +2456,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>The BIP324 session ID string in hex.</source> + <translation type="unfinished">ID hexadécimale de la session BIP324.</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> @@ -2620,6 +2644,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">L’activité réseau est désactivée</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Aucun</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Exécution de la commande sans aucun porte-monnaie</translation> </message> @@ -3216,6 +3244,13 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <source>A fee higher than %1 is considered an absurdly high fee.</source> <translation type="unfinished">Des frais supérieurs à %1 sont considérés comme ridiculement élevés.</translation> </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation type="unfinished"> + <numerusform>Début de confirmation estimé à %n bloc.</numerusform> + <numerusform>Début de confirmation estimé à %n blocs.</numerusform> + </translation> + </message> <message> <source>Warning: Invalid Bitcoin address</source> <translation type="unfinished">Avertissement : L’adresse Bitcoin est invalide</translation> @@ -3318,8 +3353,8 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <translation type="unfinished">&Signer un message</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">Vous pouvez signer des messages ou des accords avec vos adresses pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Faites attention de ne rien signer de vague ou au hasard, car des attaques d’hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l’usurper. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous êtes d’accord.</translation> + <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">Vous pouvez signer des messages ou des accords avec vos anciennes adresses (P2PKH) pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Ne signer rien de vague ou au hasard, car des attaques d’hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l’usurper. Ne signez que des déclarations entièrement détaillées et que vous acceptez.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3402,8 +3437,8 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <translation type="unfinished">Veuillez vérifier l’adresse et réessayer.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">L’adresse saisie ne fait pas référence à une clé.</translation> + <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">L’adresse saisie ne fait pas référence à une ancienne clé (P2PKH). La signature des messages n’est pas prise en charge pour SegWit ni pour les autres types d’adresses non P2PKH dans cette version de %1. Vérifiez l’adresse et réessayez.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3949,9 +3984,8 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">La TBPS a été copiée</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copié dans le presse-papiers</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">La TBSP des augmentations de frais a été copiée dans le presse-papiers.</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3962,12 +3996,12 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Impossible de valider la transaction</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Impossible d’afficher l’adresse</translation> + <source>Signer error</source> + <translation type="unfinished">Erreur de signataire</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">porte-monnaie par défaut</translation> + <source>Can't display address</source> + <translation type="unfinished">Impossible d’afficher l’adresse</translation> </message> </context> <context> @@ -4101,10 +4135,6 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Aucun format de fichier de porte-monnaie n’a été indiqué. Pour utiliser createfromdump, -format=<format> doit être indiqué.</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">Veuillez vérifier que l’heure et la date de votre ordinateur sont justes. Si votre horloge n’est pas à l’heure, %s ne fonctionnera pas correctement.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Si vous trouvez %s utile, veuillez y contribuer. Pour de plus de précisions sur le logiciel, rendez-vous sur %s.</translation> </message> @@ -4213,10 +4243,6 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">-maxmempool doit être d’au moins %d Mo</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Une erreur interne fatale est survenue. Consulter debug.log pour plus de précisions</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Impossible de résoudre l’adresse -%s : « %s »</translation> </message> @@ -4265,6 +4291,11 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <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> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Échec de suppression du répertoire de l’instantané d’état de la chaîne (%s). Supprimez-le manuellement avant de redémarrer.</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">Échec de renommage du fichier peers.dat invalide. Veuillez le déplacer ou le supprimer, puis réessayer.</translation> </message> @@ -4273,6 +4304,14 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">L'estimation des frais a échoué. Fallbackfee est désactivé. Attendez quelques blocs ou activez %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Échec de vidage du fichier des blocs sur le disque, probablement à cause d’une erreur d’E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Échec de vidage du fichier d’annulation sur le disque, probablement à cause d’une erreur d’E/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> </message> @@ -4281,6 +4320,14 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <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> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Le poids maximal de la transaction est inférieur au poids de la transaction sans entrées</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Le poids maximal de la transaction est trop faible et ne permet pas les sorties de monnaie</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> </message> @@ -4297,6 +4344,14 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. <translation type="unfinished">Connexions sortantes limitées à i2p (-onlynet=i2p) mais -i2psam n'est pas fourni</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Échec de renommage de « %s » en « %s ». Impossible de nettoyer le répertoire de la base de données d’état de chaîne d’arrière-plan.</translation> + </message> + <message> + <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">La combinaison des entrées présélectionnées et de la sélection automatique des entrées du porte-monnaie dépasse le poids maximal de la transaction. Essayez d’envoyer un montant inférieur ou de consolider manuellement les UTXO de votre porte-monnaie.</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">La taille des entrées dépasse le poids maximum. Veuillez essayer d'envoyer un montant plus petit ou de consolider manuellement les UTXOs de votre portefeuille.</translation> </message> @@ -4332,15 +4387,21 @@ Le portefeuille peut avoir été altéré ou créé avec des intentions malveill The wallet might had been created on a newer version. Please try running the latest software version. </source> - <translation type="unfinished">Descripteur non reconnu trouvé. Chargement du portefeuille %ss + <translation type="unfinished">Descripteur non reconnu trouvé. Chargement du portefeuille %s Le portefeuille a peut-être été créé avec une version plus récente. -Veuillez essayer d'utiliser la dernière version du logiciel.</translation> +Veuillez essayer d'utiliser la dernière version du logiciel. +</translation> + </message> + <message> + <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">La date et l’heure de votre ordinateur semblent décalées de plus de %d minutes par rapport au réseau, ce qui peut entraîner un échec de consensus. Après avoir confirmé l’heure de votre ordinateur, ce message ne devrait plus s’afficher après redémarrage de votre nœud. Sans redémarrage, il devrait cesser de s’afficher automatiquement si vous vous connectez à suffisamment de nouveaux pairs sortants, ce qui peut prendre du temps. Pour plus de précisions, vous pouvez inspecter le champ `timeoffset` des méthodes RPC `getpeerinfo` et `getnetworkinfo`.</translation> </message> <message> <source> Unable to cleanup failed migration</source> - <translation type="unfinished">Impossible de corriger l'échec de la migration</translation> + <translation type="unfinished"> +Impossible de corriger l'échec de la migration</translation> </message> <message> <source> @@ -4349,6 +4410,18 @@ Unable to restore backup of wallet.</source> Impossible de restaurer la sauvegarde du portefeuille.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">« whitebind » ne peut être utilisé que pour les connexions entrantes (« out » a été passé)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Une erreur interne fatale est survenue. Pour plus de précisions, consultez debug.log :</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Les données Assumeutxo sont introuvables pour l’empreinte de bloc « %s » donnée.</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">La vérification des blocs a été interrompue</translation> </message> @@ -4361,6 +4434,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Tous droits réservés © %i à %i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Un bloc corrompu a été détecté, ce qui indique une défaillance matérielle possible.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Une base de données des blocs corrompue a été détectée</translation> </message> @@ -4389,6 +4466,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Le fichier de vidage %s n’existe pas.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Échec du contrôle d’intégrité de la cryptographie à courbe elliptique. Fermeture de %s.</translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Erreur de validation des transactions de la base de données pour la suppression des transactions du porte-monnaie</translation> </message> @@ -4537,10 +4618,22 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Erreur ; La transaction de la base de données ne peut pas être exécutée pour le porte-monnaie %s</translation> </message> <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">Échec de connexion du meilleur bloc (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Échec de déconnexion du bloc.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Échec d'écoute sur tous les ports. Si cela est voulu, utiliser -listen=0.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Échec de lecture du bloc.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Échec de réanalyse du porte-monnaie lors de l’initialisation</translation> </message> @@ -4553,6 +4646,22 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Échec de vérification de la base de données</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">Échec d’écriture du bloc.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Échec d’écriture dans la base de données d’index des blocs.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Échec d’écriture dans la base de données des pièces.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Échec d’écriture des données d’annulation.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">Échec de suppression de la transaction :%s</translation> </message> @@ -4649,6 +4758,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Chargement du porte-monnaie…</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Le poids maximal de la transaction doit être compris entre %d et %d</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Le montant manque</translation> </message> @@ -4677,6 +4790,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Entrée présélectionnée non solvable %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Seule la direction a été définie, sans permissions : « %s »</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">L’élagage ne peut pas être configuré avec une valeur négative</translation> </message> @@ -4721,6 +4838,18 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">La section [%s] n’est pas reconnue</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Le signataire n’a pas fait écho à l’adresse</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">Le signataire a renvoyé une adresse inattendue %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Le signataire a renvoyé une erreur : %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Échec de signature de la transaction</translation> </message> @@ -4749,6 +4878,18 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Démarrage des processus réseau…</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Erreur système lors du vidage : %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Erreur système lors du chargement d’un fichier de blocs externe : %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Erreur système lors de l’enregistrement du bloc sur le disque : %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Le code source est publié sur %s.</translation> </message> @@ -4765,6 +4906,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Le porte-monnaie évitera de payer moins que les frais minimaux de relais.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Il n’y a pas de « ScriptPubKeyManager » pour cette adresse.</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Ce logiciel est expérimental.</translation> </message> @@ -4805,10 +4950,6 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">La transaction est trop grosse</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Impossible d'allouer de la mémoire pour -maxsigcachesize : '%s' Mo</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Impossible de se lier à %s sur cet ordinateur (la liaison a retourné l’erreur %s)</translation> </message> @@ -4869,6 +5010,10 @@ Impossible de restaurer la sauvegarde du portefeuille.</translation> <translation type="unfinished">Les nouvelles règles inconnues sont activées (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Une option non reconnue « %s » a été indiquée dans -test=<option>.</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> </message> diff --git a/src/qt/locale/bitcoin_ga.ts b/src/qt/locale/bitcoin_ga.ts index 901748a146..1b7b9c0ec3 100644 --- a/src/qt/locale/bitcoin_ga.ts +++ b/src/qt/locale/bitcoin_ga.ts @@ -171,6 +171,14 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Cuir isteach an sean pasfhrása agus an pasfhrása nua don sparán.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Leanúint ar aghaidh</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Ar ais</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">Cuimhnigh nach dtugann chriptiú do sparán cosaint go hiomlán do do bitcoins ó bheith goidte ag bogearraí mailíseacha atá ag ionfhabhtú do ríomhaire.</translation> </message> @@ -215,6 +223,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 +249,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 +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,12 +417,16 @@ 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> + <message> + <source>default wallet</source> + <translation type="unfinished">sparán réamhshocraithe</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -369,6 +458,10 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">&Maidir le %1</translation> </message> <message> + <source>Show information about %1</source> + <translation type="unfinished">Taispeáin faisnéis faoi %1</translation> + </message> + <message> <source>About &Qt</source> <translation type="unfinished">Maidir le &Qt</translation> </message> @@ -377,10 +470,18 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Taispeáin faisnéis faoi Qt</translation> </message> <message> + <source>Modify configuration options for %1</source> + <translation type="unfinished">Mionathraigh roghanna cumraíochta do %1</translation> + </message> + <message> <source>Create a new wallet</source> <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 +515,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 +587,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 +625,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 +635,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 +667,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 +707,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> @@ -550,14 +741,25 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Masc na luachanna sa gcluaisín Forléargas</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">sparán réamhshocraithe</translation> - </message> - <message> <source>No wallets available</source> <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 +780,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 +984,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 +1068,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> @@ -814,15 +1152,44 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Rabhadh oscail sparán</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">sparán réamhshocraithe</translation> - </message> - <message> <source>Open Wallet</source> <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 +1220,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 +1264,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 +1360,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 +1382,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 +1397,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 +1431,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 +1443,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 +1477,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 +1504,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 +1535,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 +1575,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 +1587,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 +1603,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 +1639,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 +1693,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 +1719,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 +1759,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 +1799,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 +1827,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 +1850,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 +1870,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 +1895,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 +1983,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 +1999,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 +2015,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 +2051,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 +2096,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 +2135,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 +2159,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 +2212,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 +2235,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> @@ -1711,6 +2292,14 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Líon naisc</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Seoltaí Áitiúla</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Seoltaí líonra go bhfuil do nód Bitcoin úsáid faoi láthair chun cumarsáid a dhéanamh le nóid eile.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Blocshlabhra</translation> </message> @@ -1759,10 +2348,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>Hide Peers Detail</source> + <translation type="unfinished">Folaigh Sonraí na bPiaraí</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>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 +2388,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 +2400,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 +2458,51 @@ 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 BIP324 session ID string in hex.</source> + <translation type="unfinished">Teaghrán ID an tseisiúin BIP324 i heicsidheachúlach.</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 +2567,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 +2632,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 +2644,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> @@ -1907,14 +2657,48 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Gníomhaíocht líonra díchumasaithe</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Faic</translation> + </message> + <message> <source>Executing command without any wallet</source> <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 +2723,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 +2806,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 +2857,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 +2889,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 +3031,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 +3059,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 +3119,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 +3149,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 +3198,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 +3224,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 +3276,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> @@ -2455,8 +3383,8 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">&Sínigh Teachtaireacht</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">Féadfaidh tú teachtaireachtaí / comhaontuithe a shíniú le do sheoltaí chun a chruthú gur féidir leat bitcoins a sheoltear chucu a fháil. Bí cúramach gan aon rud doiléir nó randamach a shíniú, mar d’fhéadfadh ionsaithe fioscaireachta iarracht ar d’aitheantas a shíniú chucu. Ná sínigh ach ráitis lán-mhionsonraithe a aontaíonn tú leo.</translation> + <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">Is féidir leat teachtaireachtaí/comhaontuithe a shíniú le do sheoltaí oidhreachta (P2PKH) lena chruthú gur féidir leat bitcoins a sheoltar chucu a fháil. Bí cúramach gan aon rud doiléir nó randamach a shíniú, mar seans go ndéanfaidh ionsaithe fioscaireachta iarracht tú a mhealladh chun d'aitheantas a shíniú leo. Ná sínigh ach ráitis mhionsonraithe a n-aontaíonn tú leo.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -2543,10 +3471,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Seiceáil an seoladh le do thoil agus triail arís.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Ní thagraíonn an seoladh a iontráladh d’eochair.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Cuireadh díghlasáil sparán ar ceal.</translation> </message> @@ -2588,6 +3512,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 +3530,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 +3601,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 +3655,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 +3844,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> @@ -2944,6 +3942,10 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Easpórtáil Rathúil</translation> </message> <message> + <source>The transaction history was successfully saved to %1.</source> + <translation type="unfinished">Sábháladh stair an idirbhirt go rathúil chuig %1.</translation> + </message> + <message> <source>Range:</source> <translation type="unfinished">Raon:</translation> </message> @@ -3023,6 +4025,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 +4041,10 @@ 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>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Cóipeáil PSBT bump táille chuig an ngearrthaisce</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation type="unfinished">Ní féidir síniú idirbheart.</translation> </message> @@ -3043,8 +4053,12 @@ 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>default wallet</source> - <translation type="unfinished">sparán réamhshocraithe</translation> + <source>Signer error</source> + <translation type="unfinished">Earráid sínitheora</translation> + </message> + <message> + <source>Can't display address</source> + <translation type="unfinished">Ní féidir an seoladh a thaispeáint</translation> </message> </context> <context> @@ -3062,6 +4076,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,20 +4112,84 @@ 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>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> + <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 contribute if you find %s useful. Visit %s for further information about the software.</source> @@ -3117,10 +4200,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 +4252,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 +4284,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> @@ -3181,14 +4300,14 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Caithfidh -maxmempool a bheith ar a laghad %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Tharla earráid mharfach inmheánach, féach debug.log le haghaidh sonraí</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <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 +4316,171 @@ 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 remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Theip ar bhaint an tsainstáit seat seat (%s). Bain de láimh é roimh atosú.</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>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Theip ar chomhad blocála a shruthlú go diosca. Is dócha gur earráid I/O é seo.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Theip ar shruthlú an chomhaid chealaigh go diosca. Is dócha gur earráid I/O é seo.</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>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Tá an t-uasmheáchan idirbhirt níos lú ná meáchan idirbhirt gan ionchuir</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Tá meáchan uasta idirbheart ró-íseal, ní féidir freastal ar aschur athraithe</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>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Theip ar athainmniú '%s' -> '%s'. Ní féidir eolaire leveldb an tslabhra cúlra a ghlanadh.</translation> + </message> + <message> + <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">Sáraíonn meascán na n-ionchur réamhroghnaithe agus an rogha ionchuir uathoibríoch sparán an t-uasmheáchan idirbhirt. 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 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>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">Is cosúil go bhfuil dáta agus am do ríomhaire níos mó ná %d nóiméad as sioncronú leis an líonra, seans go dteipfidh ar chomhdhearcadh dá bharr. Tar éis duit clog do ríomhaire a dheimhniú, níor cheart go mbeadh an teachtaireacht seo le feiceáil a thuilleadh nuair a atosóidh tú do nód. Gan atosú, ba cheart go stopfadh sé ag taispeáint go huathoibríoch tar éis duit nasc a dhéanamh le líon imleor piaraí nua amach, a d'fhéadfadh roinnt ama a ghlacadh. Is féidir leat an réimse `timeoffset` de na modhanna RPC `getpeerinfo` agus `getnetworkinfo` a iniúchadh chun tuilleadh faisnéise a fháil.</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>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">ní féidir ceangaltán bán a úsáid ach amháin le haghaidh naisc isteach (ritheadh "amach")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Tharla earráid mharfach inmheánach, féach debug.log le haghaidh sonraí:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Ní bhfuarthas sonraí Assumeutxo don bhlocshlabhra '%s' a tugadh.</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> @@ -3205,6 +4489,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Cóipcheart (C) %i-%i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Bloc truaillithe aimsithe a léirigh teip crua-earraí féideartha.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Braitheadh bunachar sonraí bloic truaillithe</translation> </message> @@ -3229,6 +4517,22 @@ 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>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Teip seiceála sláintíochta cripteagrafaíochta cuar éilipseach. Tá %s ag múchadh.</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,30 +4565,162 @@ 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 connect best block (%s).</source> + <translation type="unfinished">Theip ar nascadh an bhloc is fearr (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Theip ar dhínascadh an bhloc.</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> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Theip ar léamh an bhloc.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <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>Failed to write block.</source> + <translation type="unfinished">Theip ar scríobh an bhloc.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Theip ar scríobh chuig an mbunachar sonraí innéacs bloc.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Theip ar scríobh chuig an mbunachar sonraí boinn.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Theip ar scríobh sonraí cealaigh.</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 +4729,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 +4741,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 +4769,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 +4785,70 @@ 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>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Caithfidh uasmheáchan an idirbhirt a bheith idir %d agus %d</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>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Níor socraíodh ach treo, gan cead: '%s'</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 +4857,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> @@ -3365,6 +4893,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Ní aithnítear rannán [%s].</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Níor thug an sínitheoir macalla don seoladh</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">D'fhreagair an sínitheoir seoladh %s gan choinne</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Earráid faighte ag sínitheoir: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Theip ar síniú idirbheart</translation> </message> @@ -3385,10 +4925,34 @@ 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>System error while flushing: %s</source> + <translation type="unfinished">Earráid chórais agus é á shruthlú: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Earráid chórais agus blocchomhad seachtrach á luchtú: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Earráid chórais agus an bloc á shábháil ar an diosca: %s</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> @@ -3397,6 +4961,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Seachnóidh an sparán níos lú ná an táille athsheachadán íosta a íoc.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Níl aon Bhainisteoir ScriptPubKey ann don seoladh seo</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Is bogearraí turgnamhacha é seo.</translation> </message> @@ -3409,6 +4977,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,10 +4989,18 @@ 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> @@ -3437,6 +5017,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 +5029,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 +5061,60 @@ 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>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Rogha neamhaitheanta "%s" curtha ar fáil i -test=1.</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..4f6398d9ff 100644 --- a/src/qt/locale/bitcoin_ga_IE.ts +++ b/src/qt/locale/bitcoin_ga_IE.ts @@ -171,6 +171,14 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Cuir isteach an sean pasfhrása agus an pasfhrása nua don sparán.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Leanúint ar aghaidh</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Ar ais</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">Cuimhnigh nach dtugann chriptiú do sparán cosaint go hiomlán do do bitcoins ó bheith goidte ag bogearraí mailíseacha atá ag ionfhabhtú do ríomhaire.</translation> </message> @@ -211,10 +219,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 +253,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 +314,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 +334,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 +381,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,12 +425,16 @@ 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> + <message> + <source>default wallet</source> + <translation type="unfinished">sparán réamhshocraithe</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -369,6 +466,10 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">&Maidir le %1</translation> </message> <message> + <source>Show information about %1</source> + <translation type="unfinished">Taispeáin faisnéis faoi %1</translation> + </message> + <message> <source>About &Qt</source> <translation type="unfinished">Maidir le &Qt</translation> </message> @@ -377,10 +478,18 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Taispeáin faisnéis faoi Qt</translation> </message> <message> + <source>Modify configuration options for %1</source> + <translation type="unfinished">Mionathraigh roghanna cumraíochta do %1</translation> + </message> + <message> <source>Create a new wallet</source> <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 +523,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 +595,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 +633,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 +643,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 +675,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 +715,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> @@ -550,14 +749,25 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Masc na luachanna sa gcluaisín Forléargas</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">sparán réamhshocraithe</translation> - </message> - <message> <source>No wallets available</source> <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 +788,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 +992,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 +1076,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> @@ -814,15 +1160,44 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Rabhadh oscail sparán</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">sparán réamhshocraithe</translation> - </message> - <message> <source>Open Wallet</source> <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 +1228,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 +1272,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 +1368,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 +1390,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 +1405,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 +1439,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 +1451,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 +1485,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 +1512,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 +1543,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 +1583,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 +1595,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 +1611,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 +1647,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 +1701,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 +1727,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 +1767,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 +1807,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 +1835,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 +1858,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 +1878,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 +1903,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 +1991,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 +2007,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 +2023,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 +2059,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 +2104,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 +2143,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 +2167,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 +2220,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 +2243,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> @@ -1711,6 +2300,14 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Líon naisc</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Seoltaí Áitiúla</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Seoltaí líonra go bhfuil do nód Bitcoin úsáid faoi láthair chun cumarsáid a dhéanamh le nóid eile.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Blocshlabhra</translation> </message> @@ -1759,10 +2356,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>Hide Peers Detail</source> + <translation type="unfinished">Folaigh Sonraí na bPiaraí</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>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 +2396,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 +2408,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 +2466,51 @@ 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 BIP324 session ID string in hex.</source> + <translation type="unfinished">Teaghrán ID an tseisiúin BIP324 i heicsidheachúlach.</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 +2575,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 +2645,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 +2657,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> @@ -1907,14 +2670,48 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Gníomhaíocht líonra díchumasaithe</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Faic</translation> + </message> + <message> <source>Executing command without any wallet</source> <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 +2736,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 +2819,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 +2870,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 +2902,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 +3044,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 +3072,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 +3132,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 +3162,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 +3211,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 +3242,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 +3294,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> @@ -2455,8 +3401,8 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">&Sínigh Teachtaireacht</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">Féadfaidh tú teachtaireachtaí / comhaontuithe a shíniú le do sheoltaí chun a chruthú gur féidir leat bitcoins a sheoltear chucu a fháil. Bí cúramach gan aon rud doiléir nó randamach a shíniú, mar d’fhéadfadh ionsaithe fioscaireachta iarracht ar d’aitheantas a shíniú chucu. Ná sínigh ach ráitis lán-mhionsonraithe a aontaíonn tú leo.</translation> + <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">Is féidir leat teachtaireachtaí/comhaontuithe a shíniú le do sheoltaí oidhreachta (P2PKH) lena chruthú gur féidir leat bitcoins a sheoltar chucu a fháil. Bí cúramach gan aon rud doiléir nó randamach a shíniú, mar seans go ndéanfaidh ionsaithe fioscaireachta iarracht tú a mhealladh chun d'aitheantas a shíniú leo. Ná sínigh ach ráitis mhionsonraithe a n-aontaíonn tú leo.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -2543,8 +3489,8 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Seiceáil an seoladh le do thoil agus triail arís.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Ní thagraíonn an seoladh a iontráladh d’eochair.</translation> + <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">Ní thagraíonn an seoladh isteach d'eochair leagáide (P2PKH). Ní thacaítear le síniú teachtaireachta do SegWit agus cineálacha seoltaí eile nach P2PKH iad sa leagan seo de %1. Seiceáil an seoladh agus bain triail eile as.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -2588,6 +3534,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 +3552,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 +3623,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 +3677,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 +3866,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> @@ -2944,6 +3964,10 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation> <translation type="unfinished">Easpórtáil Rathúil</translation> </message> <message> + <source>The transaction history was successfully saved to %1.</source> + <translation type="unfinished">Sábháladh stair an idirbhirt go rathúil chuig %1.</translation> + </message> + <message> <source>Range:</source> <translation type="unfinished">Raon:</translation> </message> @@ -3023,6 +4047,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 +4063,10 @@ 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>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Cóipeáil PSBT bump táille chuig an ngearrthaisce</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation type="unfinished">Ní féidir síniú idirbheart.</translation> </message> @@ -3043,8 +4075,12 @@ 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>default wallet</source> - <translation type="unfinished">sparán réamhshocraithe</translation> + <source>Signer error</source> + <translation type="unfinished">Earráid sínitheora</translation> + </message> + <message> + <source>Can't display address</source> + <translation type="unfinished">Ní féidir an seoladh a thaispeáint</translation> </message> </context> <context> @@ -3062,6 +4098,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,20 +4134,84 @@ 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>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> + <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 contribute if you find %s useful. Visit %s for further information about the software.</source> @@ -3117,10 +4222,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 +4274,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 +4306,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> @@ -3181,14 +4322,14 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Caithfidh -maxmempool a bheith ar a laghad %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Tharla earráid mharfach inmheánach, féach debug.log le haghaidh sonraí</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <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 +4338,174 @@ 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 remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Theip ar bhaint an tsainstáit seat seat (%s). Bain de láimh é roimh atosú. +</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>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Theip ar chomhad blocála a shruthlú go diosca. Is dócha gur earráid I/O é seo.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Theip ar shruthlú an chomhaid chealaigh go diosca. Is dócha gur earráid I/O é seo.</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>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Tá an t-uasmheáchan idirbhirt níos lú ná meáchan idirbhirt gan ionchuir</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Tá meáchan uasta idirbheart ró-íseal, ní féidir freastal ar aschur athraithe</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>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Theip ar athainmniú '%s' -> '%s'. Ní féidir eolaire leveldb an tslabhra cúlra a ghlanadh.</translation> + </message> + <message> + <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">Sáraíonn meascán na n-ionchur réamhroghnaithe agus an rogha ionchuir uathoibríoch sparán an t-uasmheáchan idirbhirt. 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 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>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">Is cosúil go bhfuil dáta agus am do ríomhaire níos mó ná %d nóiméad as sioncronú leis an líonra, seans go dteipfidh ar chomhdhearcadh dá bharr. Tar éis duit clog do ríomhaire a dheimhniú, níor cheart go mbeadh an teachtaireacht seo le feiceáil a thuilleadh nuair a atosóidh tú do nód. Gan atosú, ba cheart go stopfadh sé ag taispeáint go huathoibríoch tar éis duit nasc a dhéanamh le líon imleor piaraí nua amach, a d'fhéadfadh roinnt ama a ghlacadh. Is féidir leat an réimse `timeoffset` de na modhanna RPC `getpeerinfo` agus `getnetworkinfo` a iniúchadh chun tuilleadh faisnéise a fháil.</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>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">ní féidir ceangaltán bán a úsáid ach amháin le haghaidh naisc isteach (ritheadh "amach")</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Tharla earráid mharfach inmheánach, féach debug.log le haghaidh sonraí:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Ní bhfuarthas sonraí Assumeutxo don bhlocshlabhra '%s' a tugadh.</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> @@ -3205,6 +4514,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Cóipcheart (C) %i-%i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Bloc truaillithe aimsithe a léirigh teip crua-earraí féideartha.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Braitheadh bunachar sonraí bloic truaillithe</translation> </message> @@ -3229,6 +4542,22 @@ 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>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Teip seiceála sláintíochta cripteagrafaíochta cuar éilipseach. Tá %s ag múchadh.</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,30 +4590,162 @@ 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 connect best block (%s).</source> + <translation type="unfinished">Theip ar nascadh an bhloc is fearr (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Theip ar dhínascadh an bhloc.</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> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Theip ar léamh an bhloc.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <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>Failed to write block.</source> + <translation type="unfinished">Theip ar scríobh an bhloc.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Theip ar scríobh chuig an mbunachar sonraí innéacs bloc.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Theip ar scríobh chuig an mbunachar sonraí boinn.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Theip ar scríobh sonraí cealaigh.</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 +4754,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 +4766,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 +4794,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 +4810,70 @@ 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>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Caithfidh uasmheáchan an idirbhirt a bheith idir %d agus %d</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>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Níor socraíodh ach treo, gan cead: '%s'</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 +4882,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> @@ -3365,6 +4918,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Ní aithnítear rannán [%s].</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Níor thug an sínitheoir macalla don seoladh</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">D'fhreagair an sínitheoir seoladh %s gan choinne</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Earráid faighte ag sínitheoir: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Theip ar síniú idirbheart</translation> </message> @@ -3385,10 +4950,34 @@ 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>System error while flushing: %s</source> + <translation type="unfinished">Earráid chórais agus é á shruthlú: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Earráid chórais agus blocchomhad seachtrach á luchtú: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Earráid chórais agus an bloc á shábháil ar an diosca: %s</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> @@ -3397,6 +4986,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Seachnóidh an sparán níos lú ná an táille athsheachadán íosta a íoc.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Níl aon Bhainisteoir ScriptPubKey ann don seoladh seo</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Is bogearraí turgnamhacha é seo.</translation> </message> @@ -3409,6 +5002,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,10 +5014,18 @@ 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> @@ -3437,6 +5042,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 +5054,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 +5086,60 @@ 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>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Rogha neamhaitheanta "%s" curtha ar fáil i -test=<option>.</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..53e038ecd0 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> @@ -171,6 +184,10 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Introduce a frase contrasinal anterior mais a nova frase contrasinal para a carteira.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continuar</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">Recorda que encriptar a tua carteira non protexe completamente que os teus bitcoins poidan ser roubados por malware que afecte ó teu computador.</translation> </message> @@ -211,10 +228,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 +262,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> @@ -289,7 +338,11 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">moedeiro por defecto</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -382,10 +435,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> @@ -501,10 +566,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Mostra a %1 mensaxe de axuda para obter unha lista cas posibles opcións de línea de comando de Bitcoin </translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">moedeiro por defecto</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Non hai moedeiros dispoñíbeis</translation> </message> @@ -736,10 +797,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <context> <name>OpenWalletActivity</name> <message> - <source>default wallet</source> - <translation type="unfinished">moedeiro por defecto</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Abrir Moedeiro</translation> @@ -1595,10 +1652,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Por favor comproba a dirección e proba de novo.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">A dirección introducida non se refire a ninguna clave.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Cancelouse o desbloqueo do moedeiro.</translation> </message> @@ -1876,6 +1929,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> @@ -1937,11 +1995,7 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <source>Send Coins</source> <translation type="unfinished">Moedas Enviadas</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">moedeiro por defecto</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_gl_ES.ts b/src/qt/locale/bitcoin_gl_ES.ts index 854aebfc6f..47951fa6f2 100644 --- a/src/qt/locale/bitcoin_gl_ES.ts +++ b/src/qt/locale/bitcoin_gl_ES.ts @@ -2,10 +2,6 @@ <context> <name>AddressBookPage</name> <message> - <source>Right-click to edit address or label</source> - <translation type="unfinished">Fai Click co botón dereito para editar o enderezo ou etiqueta</translation> - </message> - <message> <source>Create a new address</source> <translation type="unfinished">Crea un novo enderezo</translation> </message> @@ -84,11 +80,24 @@ 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> </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 Fallida</translation> </message> @@ -167,6 +176,10 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Introduce a frase contrasinal anterior mais a nova frase contrasinal para a carteira.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continuar</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">Recorda que encriptar a tua carteira non protexe completamente que os teus bitcoins poidan ser roubados por malware que afecte ó teu computador.</translation> </message> @@ -207,10 +220,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,13 +254,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>Amount</source> <translation type="unfinished">Cantidade</translation> </message> @@ -281,7 +326,11 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">Carteira por defecto</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -374,10 +423,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> @@ -489,10 +550,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Mostra a %1 mensaxe de axuda para obter unha lista cas posibles opcións de línea de comando de Bitcoin </translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Carteira por defecto</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Non hai carteiras dispoñibles</translation> </message> @@ -724,10 +781,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <context> <name>OpenWalletActivity</name> <message> - <source>default wallet</source> - <translation type="unfinished">Carteira por defecto</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Abrir carteira</translation> @@ -1061,6 +1114,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> @@ -1089,13 +1147,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">Carteira por defecto</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> diff --git a/src/qt/locale/bitcoin_gu.ts b/src/qt/locale/bitcoin_gu.ts index 54f2cd1741..146b9e2e24 100644 --- a/src/qt/locale/bitcoin_gu.ts +++ b/src/qt/locale/bitcoin_gu.ts @@ -11,7 +11,7 @@ </message> <message> <source>&New</source> - <translation type="unfinished">નવું</translation> + <translation type="unfinished">& નવું</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> @@ -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,167 @@ 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">વૉલેટ માટે નવો પાસફ્રેઝ દાખલ કરો. <br> કૃપા કરીને <b> દસ અથવા વધુ અજાન્યા અક્ષરો </2> અથવા <b> આઠ અથવા વધુ શબ્દોના પાસફ્રેઝનો ઉપયોગ કરો </b> .</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation type="unfinished">પાકીટ માટે જુના શબ્દસમૂહ અને નવા શબ્દસમૂહ દાખલ કરો.</translation> + </message> + <message> + <source>Continue</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>Wallet passphrase was successfully changed.</source> + <translation type="unfinished">વૉલેટ પાસફ્રેઝ સફળતાપૂર્વક બદલવામાં આવ્યો</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">ચેતવણી: કેપ્સલોક કી ચાલુ છે!</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 +346,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"> @@ -234,72 +421,1005 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">મૂળભૂત વૉલેટ</translation> + </message> +</context> <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>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>UnitDisplayStatusBarControl</name> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation type="unfinished">રકમ બતાવવા માટે એકમ. અન્ય એકમ પસંદ કરવા માટે ક્લિક કરો.</translation> + </message> +</context> <context> <name>CoinControlDialog</name> <message> + <source>Coin Selection</source> + <translation type="unfinished">સિક્કાની પસંદગી</translation> + </message> + <message> + <source>Quantity:</source> + <translation type="unfinished">જથ્થો:</translation> + </message> + <message> + <source>Bytes:</source> + <translation type="unfinished">બાઇટ્સ:</translation> + </message> + <message> + <source>Amount:</source> + <translation type="unfinished">રકમ:</translation> + </message> + <message> + <source>Fee:</source> + <translation type="unfinished">ફી:</translation> + </message> + <message> + <source>After Fee:</source> + <translation type="unfinished">પછીની ફી:</translation> + </message> + <message> + <source>Change:</source> + <translation type="unfinished">બદલો:</translation> + </message> + <message> + <source>(un)select all</source> + <translation type="unfinished">બધા (ના)પસંદ કરો</translation> + </message> + <message> + <source>Tree mode</source> + <translation type="unfinished">ટ્રી પદ્ધતિ</translation> + </message> + <message> + <source>List mode</source> + <translation type="unfinished">સૂચિ પદ્ધતિ</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">રકમ</translation> </message> <message> + <source>Received with label</source> + <translation type="unfinished">લેબલ સાથે પ્રાપ્ત</translation> + </message> + <message> + <source>Received with address</source> + <translation type="unfinished">સરનામા સાથે પ્રાપ્ત</translation> + </message> + <message> + <source>Date</source> + <translation type="unfinished">તારીખ</translation> + </message> + <message> + <source>Confirmations</source> + <translation type="unfinished">પુષ્ટિકરણો</translation> + </message> + <message> + <source>Confirmed</source> + <translation type="unfinished">પુષ્ટિ</translation> + </message> + <message> + <source>Copy amount</source> + <translation type="unfinished">રકમની નકલ કરો</translation> + </message> + <message> + <source>&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>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 +1427,781 @@ 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>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> + <translation type="unfinished">આ પ્રારંભિક સિંક્રનાઇઝેશન ખૂબ જ માગણી કરે છે, અને તમારા કમ્પ્યુટર સાથેની હાર્ડવેર સમસ્યાઓનો પર્દાફાશ કરી શકે છે જે અગાઉ કોઈનું ધ્યાન ગયું ન હતું. દરેક વખતે જ્યારે તમે ચાલુ કરો %1, ત્યારે તે ડાઉનલોડ કરવાનું ચાલુ રાખશે જ્યાંથી તેણે છોડ્યું હતું.</translation> + </message> + <message> + <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source> + <translation type="unfinished">જ્યારે તમે ઓકે ક્લિક કરો છો,%1સંપૂર્ણ ડાઉનલોડ અને પ્રક્રિયા કરવાનું શરૂ કરશે%4બ્લોક ચેન (સાંકળ) (%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 +2212,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 +2228,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>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>None</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 +2890,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 +2975,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 +3029,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 +3048,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,6 +3095,10 @@ 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>WalletView</name> @@ -469,5 +3110,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_hak.ts b/src/qt/locale/bitcoin_hak.ts index ca7723785c..4ad802e718 100644 --- a/src/qt/locale/bitcoin_hak.ts +++ b/src/qt/locale/bitcoin_hak.ts @@ -10,10 +10,6 @@ <translation type="unfinished">新增一個位址</translation> </message> <message> - <source>&New</source> - <translation type="unfinished">新增 &N</translation> - </message> - <message> <source>Copy the currently selected address to the system clipboard</source> <translation type="unfinished">把目前选择的地址复制到系统粘贴板中</translation> </message> @@ -179,6 +175,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">输入钱包的旧密码和新密码。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</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> @@ -261,6 +265,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -432,7 +440,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 GB (十億位元組)</translation> </message> -</context> + </context> <context> <name>BitcoinGUI</name> <message> @@ -510,7 +518,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">修改钱包加密密码</translation> + <translation type="unfinished">更改钱包密码</translation> </message> <message> <source>&Send</source> @@ -521,16 +529,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">接收(&R)</translation> </message> <message> - <source>&Options…</source> - <translation type="unfinished">选项(&O)</translation> - </message> - <message> - <source>&Encrypt Wallet…</source> - <translation type="unfinished">加密钱包(&E)</translation> - </message> - <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">把你钱包中的私钥加密</translation> + <translation type="unfinished">將錢包中之密鑰加密</translation> </message> <message> <source>&Backup Wallet…</source> @@ -541,22 +541,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">修改密码(&C)</translation> </message> <message> - <source>Sign &message…</source> - <translation type="unfinished">签名消息(&M)</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">验证消息(&V)</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">从文件加载PSBT(&L)...</translation> </message> @@ -573,32 +561,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">创建钱包...</translation> </message> <message> - <source>Close All Wallets…</source> - <translation type="unfinished">关闭所有钱包...</translation> - </message> - <message> <source>&File</source> - <translation type="unfinished">文件(&F)</translation> + <translation type="unfinished">&文件</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">设置(&S)</translation> + <translation type="unfinished">&設定</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">帮助(&H)</translation> + <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> + <translation type="unfinished">分頁工具列</translation> </message> <message> <source>Indexing blocks on disk…</source> @@ -610,7 +586,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> @@ -640,15 +616,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">赶上...</translation> + <translation type="unfinished">正在追上进度...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">最新收到的区块产生于 %1 之前。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">在此之后的交易尚不可见</translation> </message> <message> <source>Error</source> @@ -734,7 +710,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation type="unfinished">显示 %1 帮助信息,获取可用命令行选项列表</translation> + <translation type="unfinished">显示%1帮助消息以获得可能包含Bitcoin命令行选项的列表</translation> </message> <message> <source>&Mask values</source> @@ -745,10 +721,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -786,15 +758,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 client</source> - <translation type="unfinished">%1 客户端</translation> + <translation type="unfinished">%1 客戶端</translation> </message> <message> <source>&Hide</source> - <translation type="unfinished">隐藏(&H)</translation> + <translation type="unfinished">&躲</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">&顯示</translation> + <translation type="unfinished">显示(&H)</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -806,26 +778,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <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> + <translation type="unfinished">關閉網路紀錄</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">預先同步標頭(%1%)</translation> + <translation type="unfinished">预同步区块头 (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -927,11 +889,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Quantity:</source> - <translation type="unfinished">总量:</translation> + <translation type="unfinished">數量:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished">位元組數:</translation> + <translation type="unfinished">位元組:</translation> </message> <message> <source>Amount:</source> @@ -946,14 +908,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">計費後金額:</translation> </message> <message> - <source>Change:</source> - <translation type="unfinished">找零:</translation> - </message> - <message> - <source>(un)select all</source> - <translation type="unfinished">全(不)选</translation> - </message> - <message> <source>Tree mode</source> <translation type="unfinished">树状模式</translation> </message> @@ -966,22 +920,10 @@ Signing is only possible with addresses of the type 'legacy'.</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>Confirmed</source> - <translation type="unfinished">已确认</translation> - </message> - <message> <source>Copy amount</source> <translation type="unfinished">复制金额</translation> </message> @@ -1006,10 +948,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">锁定未花费(&O)</translation> </message> <message> - <source>&Unlock unspent</source> - <translation type="unfinished">解锁未花费(&U)</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">复制数目</translation> </message> @@ -1045,11 +983,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>change from %1 (%2)</source> <translation type="unfinished">找零來自於 %1 (%2)</translation> </message> - <message> - <source>(change)</source> - <translation type="unfinished">(找零)</translation> - </message> -</context> + </context> <context> <name>CreateWalletActivity</name> <message> @@ -1141,10 +1075,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1194,7 +1124,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">您确定想要关闭所有钱包吗?</translation> + <translation type="unfinished">您確定要關閉所有錢包嗎?</translation> </message> </context> <context> @@ -1245,7 +1175,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Create</source> - <translation type="unfinished">创建</translation> + <translation type="unfinished">創建</translation> </message> </context> <context> @@ -1284,7 +1214,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> - <translation type="unfinished">地址“%1”已经存在,它是一个收款地址,标签为“%2”,所以它不能作为一个付款地址被添加进来。</translation> + <translation type="unfinished">地址“%1”為已登記存在“%2”的地址,因此無法新增為發送地址。</translation> </message> <message> <source>The entered address "%1" is already in the address book with label "%2".</source> @@ -1307,7 +1237,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>name</source> - <translation type="unfinished">名称</translation> + <translation type="unfinished">姓名</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> @@ -1315,7 +1245,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Path already exists, and is not a directory.</source> - <translation type="unfinished">路径已存在,并且不是一个目录。</translation> + <translation type="unfinished">已經有指定的路徑了,並且不是一個目錄。</translation> </message> <message> <source>Cannot create data directory here.</source> @@ -1352,7 +1282,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">会在此目录中存储约 %1 GB 的数据。</translation> + <translation type="unfinished">此目錄中將儲存約%1 GB 的資料。</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1383,7 +1313,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Welcome to %1.</source> - <translation type="unfinished">欢迎使用 %1</translation> + <translation type="unfinished">歡迎來到 %1。</translation> </message> <message> <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> @@ -1391,7 +1321,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation type="unfinished">取消此设置需要重新下载整个区块链。先完整下载整条链再进行修剪会更快。这会禁用一些高级功能。</translation> + <translation type="unfinished">恢復此設定需要重新下載整個區塊鏈。 先下載完整鏈然後再修剪它的速度更快。 禁用一些高級功能。</translation> </message> <message> <source>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> @@ -1437,7 +1367,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">在此窗口消失前不要关闭计算机。</translation> + <translation type="unfinished">在該視窗消失之前,請勿關閉電腦。</translation> </message> </context> <context> @@ -1448,15 +1378,15 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation type="unfinished">近期交易可能尚未显示,因此当前余额可能不准确。以上信息将在与比特币网络完全同步后更正。详情如下</translation> + <translation type="unfinished">最近的交易可能還看不到,因此錢包餘額可能不正確。在錢包軟體完成跟 bitcoin 網路的同步後,這裡的資訊就會正確。詳情請見下面。</translation> </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation type="unfinished">尝试使用受未可见交易影响的余额将不被网络接受。</translation> + <translation type="unfinished">嘗試花費受尚未顯示的交易影響的比特幣將不會被網路接受。</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">剩余区块数量</translation> + <translation type="unfinished">剩餘區塊數量</translation> </message> <message> <source>Unknown…</source> @@ -1468,7 +1398,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>Progress</source> @@ -1480,7 +1410,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Estimated time left until synced</source> - <translation type="unfinished">预计剩余同步时间</translation> + <translation type="unfinished">預計完成同步所需時間</translation> </message> <message> <source>Hide</source> @@ -1508,7 +1438,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <source>Paste address from clipboard</source> <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> </context> <context> @@ -1519,11 +1449,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>&Main</source> - <translation type="unfinished">主要(&M)</translation> + <translation type="unfinished">&主要(&Main)</translation> </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">在登入系统后自动启动 %1</translation> + <translation type="unfinished">登錄系統%1後自動啟動。</translation> </message> <message> <source>&Start %1 on system login</source> @@ -1535,11 +1465,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Size of &database cache</source> - <translation type="unfinished">数据库缓存大小(&D)</translation> + <translation type="unfinished">資料庫快取的大小 </translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">脚本验证线程数(&V)</translation> + <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> @@ -2290,10 +2220,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2400,6 +2326,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/类型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2462,7 +2392,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>&Open</source> @@ -2568,7 +2498,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 天(&A)</translation> + <translation type="unfinished">一天</translation> </message> <message> <source>1 &week</source> @@ -2592,6 +2522,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">无</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -2627,7 +2561,7 @@ For more information on using this console, type %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(节点: %1)</translation> + <translation type="unfinished">(同儕:%1)</translation> </message> <message> <source>via %1</source> @@ -2817,11 +2751,11 @@ For more information on using this console, type %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">验证(&V)</translation> + <translation type="unfinished">&驗證</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">在像是硬件钱包屏幕的地方检验这个地址</translation> + <translation type="unfinished">在例如硬體錢包螢幕上驗證這個地址</translation> </message> <message> <source>&Save Image…</source> @@ -2959,7 +2893,7 @@ For more information on using this console, type %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">输入...</translation> + <translation type="unfinished">輸入…</translation> </message> <message> <source>Choose…</source> @@ -2973,9 +2907,9 @@ For more information on using this console, type %6. <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">指定交易虚拟大小的每kB (1,000字节) 自定义费率。 + <translation type="unfinished">指定每千字節(1,000字節)交易虛擬大小的自訂手續費。 -附注:因为矿工费是按字节计费的,所以如果费率是“每kvB支付100聪”,那么对于一笔500虚拟字节 (1kvB的一半) 的交易,最终将只会产生50聪的矿工费。(译注:这里就是提醒单位是字节,而不是千字节,如果搞错的话,矿工费会过低,导致交易长时间无法确认,或者压根无法发出)</translation> +注意:由於手續費是按每字節計算的,對於虛擬大小為500字節(半千字節)的交易,手續費率為「每千字節100聰」,最終將只收取50聰的手續費。</translation> </message> <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> @@ -3090,6 +3024,10 @@ 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 balance:</source> + <translation type="unfinished">外部餘額:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">或</translation> </message> @@ -3098,6 +3036,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">你可以之後再提高手續費(有 BIP-125 手續費追加的標記)</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">請檢查您的交易提案。這將產生部分簽名的比特幣交易(PSBT),您可以儲存或複製該交易,然後使用簽名。離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 from wallet '%2'</source> <translation type="unfinished">%1 来自钱包 “%2”</translation> </message> @@ -3229,7 +3172,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Remove this entry</source> @@ -3286,10 +3229,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">簽署訊息(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以使用您的地址簽名訊息/協議,以證明您可以接收發送給他們的比特幣。但是請小心,不要簽名語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽名的手法來冒充是你。只有簽名您同意的詳細內容。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3299,7 +3238,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Enter the message you want to sign here</source> @@ -3374,10 +3313,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -3430,6 +3365,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <source>kB/s</source> + <translation type="unfinished">千字節/秒</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -3808,7 +3750,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Confirmed</source> - <translation type="unfinished">已确认</translation> + <translation type="unfinished">已確認</translation> </message> <message> <source>Watch-only</source> @@ -3946,11 +3888,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT已複製</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">沒辦法簽署交易。</translation> </message> @@ -3960,11 +3897,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Can't display address</source> - <translation type="unfinished">無法顯示地址</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">默认钱包</translation> + <translation type="unfinished">無法顯示錢包位址</translation> </message> </context> <context> @@ -4014,6 +3947,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s 開發人員</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation type="unfinished">%s損壞。嘗試使用錢包工具bitcoin-wallet挽救或還原備份。</translation> + </message> + <message> <source>%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 验证 -assumeutxo 快照状态失败。这表明硬件可能有问题,也可能是软件bug,或者还可能是软件被不当修改、从而让非法快照也能够被加载。因此,将关闭节点并停止使用从这个快照构建出的任何状态,并将链高度从 %d 重置到 %d 。下次启动时,节点将会不使用快照数据从 %d 继续同步。请将这个事件报告给 %s 并在报告中包括您是如何获得这份快照的。无效的链状态快照仍被保存至磁盘上,以供诊断问题的原因。</translation> </message> @@ -4027,7 +3964,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">无法锁定数据目录 %s。%s 可能已经在运行。</translation> + <translation type="unfinished">無法在資料目錄上獲取鎖定%s。%s可能已經在運行了。</translation> </message> <message> <source>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> @@ -4055,7 +3992,9 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">错误: 转储文件标识符记录不正确。得到的是 "%s",而预期本应得到的是 "%s"。</translation> + <translation type="unfinished"> +錯誤:轉存檔案識別記錄不正確。獲得%s,預期 +%s。</translation> </message> <message> <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> @@ -4094,10 +4033,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">没有提供钱包格式。要使用 createfromdump ,必须提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4206,10 +4141,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">參數 -maxmempool 至少要給 %d 百萬位元組(MB)</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">沒辦法解析 -%s 參數指定的地址: '%s'</translation> </message> @@ -4344,6 +4275,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4361,7 +4296,7 @@ Unable to restore backup of wallet.</source> </message> <message> <source>Could not find asmap file %s</source> - <translation type="unfinished">找不到asmap文件%s</translation> + <translation type="unfinished">找不到asmap 檔案 %s</translation> </message> <message> <source>Could not parse asmap file %s</source> @@ -4452,14 +4387,34 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: %s 所在的磁盘空间低。</translation> </message> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">錯誤:轉存檔案的校驗和不匹配。%s計算得%s</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">错误:创建新仅观察钱包失败</translation> </message> <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的鍵不是十六進制:%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的值不是十六進制:%s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">錯誤:keypool已用完,請先重新呼叫keypoolrefill</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">錯誤:缺少校驗和</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">錯誤: 沒有可用的 %s 地址</translation> + </message> + <message> <source>Error: This wallet already uses SQLite</source> <translation type="unfinished">错误:此钱包已经在使用SQLite</translation> </message> @@ -4512,6 +4467,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: 钱包%s的数据库事务无法被执行</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to start indexes, shutting down..</source> <translation type="unfinished">无法启动索引,关闭中...</translation> </message> @@ -4520,6 +4479,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">校验数据库失败</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4544,6 +4511,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">dbcache不足以用于区块验证</translation> </message> <message> + <source>Insufficient funds</source> + <translation type="unfinished">金额不足</translation> + </message> + <message> <source>Invalid -i2psam address or hostname: '%s'</source> <translation type="unfinished">无效的 -i2psam 地址或主机名: '%s'</translation> </message> @@ -4716,10 +4687,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易位元量太大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation type="unfinished">沒辦法繫結在這台電腦上的 %s 。%s 可能已經在執行了。</translation> </message> diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index e3979b07e4..17fc4dc382 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">העתק את הכתובת המסומנת ללוח</translation> + <translation type="unfinished">העתקת הכתובת המסומנת ללוח</translation> </message> <message> <source>&Copy</source> @@ -184,6 +184,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">נא לספק את הסיסמה הישנה ולתת סיסמה חדשה לארנק.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">המשך</translation> + </message> + <message> + <source>Back</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> @@ -398,6 +406,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 ג״ב</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">ארנק בררת מחדל</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -692,6 +704,14 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -705,10 +725,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> </translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">ארנק בררת מחדל</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">אין ארנקים זמינים</translation> </message> @@ -793,6 +809,10 @@ Signing is only possible with addresses of the type 'legacy'.</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 @@ -1008,6 +1028,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">הסבת ארנק</translation> + </message> + </context> +<context> <name>OpenWalletActivity</name> <message> <source>Open wallet failed</source> @@ -1018,10 +1045,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -1597,6 +1620,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">בקובץ ההגדרות ניתן לציין אפשרויות מתקדמות אשר יקבלו עדיפות על ההגדרות בממשק הגרפי. כמו כן, אפשרויות בשורת הפקודה יקבלו עדיפות על קובץ ההגדרות.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">המשך</translation> + </message> + <message> <source>Cancel</source> <translation type="unfinished">ביטול</translation> </message> @@ -2158,6 +2185,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">פעילות הרשת נוטרלה</translation> </message> <message> + <source>None</source> + <translation type="unfinished">ללא</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">מבצע פקודה ללא כל ארנק</translation> </message> @@ -2721,10 +2752,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">חתימה על הו&דעה</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">אפשר לחתום על הודעות/הסכמים באמצעות הכתובות שלך, כדי להוכיח שבאפשרותך לקבל את הביטקוינים הנשלחים אליהן. יש להיזהר ולא לחתום על תוכן עמום או אקראי, מכיוון שתקיפות דיוג עשויות לנסות לגנוב את זהותך. יש לחתום רק על הצהרות מפורטות שהנך מסכים/ה להן.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">כתובת הביטקוין איתה לחתום את ההודעה</translation> </message> @@ -2809,10 +2836,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">נא לבדוק את הכתובת ולנסות שוב.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">הכתובת שסיפקת לא מתייחסת למפתח.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">שחרור הארנק בוטל.</translation> </message> @@ -3327,11 +3350,7 @@ Go to File > Open Wallet to load a wallet. <source>Could not commit transaction</source> <translation type="unfinished">שילוב העסקה נכשל</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">ארנק בררת מחדל</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -3383,12 +3402,16 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s משובש. נסו להשתמש בכלי הארנק bitcoin-wallet כדי להציל או לשחזר מגיבוי..</translation> </message> <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation type="unfinished">לא ניתן לנעול את תיקיית הנתונים %s. %s כנראה כבר רץ.</translation> + </message> + <message> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> <translation type="unfinished">מופץ תחת רשיון התוכנה של MIT, ראה קובץ מלווה %s או %s</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">נא בדקו שהתאריך והשעה במחשב שלכם נכונים! אם השעון שלכם לא מסונכרן, %s לא יעבוד כהלכה.</translation> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation type="unfinished">נא לשקול לתרום אם %s שימושי בשבילך. יש לבקר ב־%s למידע נוסף על התוכנה.</translation> </message> <message> <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> @@ -3455,10 +3478,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool חייב להיות לפחות %d מ״ב</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">שגיאה פטלית פנימית אירעה, לפירוט ראה את לוג הדיבאג.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">לא מצליח לפענח -%s כתובת: '%s'</translation> </message> diff --git a/src/qt/locale/bitcoin_hi.ts b/src/qt/locale/bitcoin_hi.ts index 414670e7a2..8f77bdc79c 100644 --- a/src/qt/locale/bitcoin_hi.ts +++ b/src/qt/locale/bitcoin_hi.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">पता या लेबल संपादित करने के लिए राइट-क्लिक करें</translation> + <translation type="unfinished">पते या लेबल में बदलाव करने के लिए राइट-क्लिक करें</translation> </message> <message> <source>Create a new address</source> @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">मौजूदा चयनित पते को सिस्टम क्लिपबोर्ड पर कॉपी करें</translation> + <translation type="unfinished">चुने गए मौजूदा पते को सिस्टम क्लिपबोर्ड पर कॉपी करें</translation> </message> <message> <source>&Copy</source> @@ -27,7 +27,7 @@ </message> <message> <source>Delete the currently selected address from the list</source> - <translation type="unfinished">सूची से मौजूदा चयनित पता हटाएं</translation> + <translation type="unfinished">सूची से अभी चुना गया पता डिलीट करें</translation> </message> <message> <source>Enter address or label to search</source> @@ -35,7 +35,7 @@ </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">मौजूदा टैब में डेटा को फ़ाइल में निर्यात करें</translation> + <translation type="unfinished">मौजूदा टैब में डेटा को फ़ाइल में एक्सपोर्ट करें</translation> </message> <message> <source>&Export</source> @@ -43,7 +43,7 @@ </message> <message> <source>&Delete</source> - <translation type="unfinished">मिटाना</translation> + <translation type="unfinished">डिलीट करें</translation> </message> <message> <source>Choose the address to send coins to</source> @@ -55,7 +55,7 @@ </message> <message> <source>C&hoose</source> - <translation type="unfinished">&चुज़</translation> + <translation type="unfinished">&चुनें</translation> </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> @@ -69,19 +69,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Copy Address</source> - <translation type="unfinished">&कॉपी पता</translation> + <translation type="unfinished">&पता कॉपी करें</translation> </message> <message> <source>Copy &Label</source> - <translation type="unfinished">कॉपी और लेबल</translation> + <translation type="unfinished">&लेबल कॉपी करें</translation> </message> <message> <source>&Edit</source> - <translation type="unfinished">&एडीट</translation> + <translation type="unfinished">&बदलाव करें</translation> </message> <message> <source>Export Address List</source> - <translation type="unfinished">पता की सूची को निर्यात करें</translation> + <translation type="unfinished">पते की सूची को एक्सपोर्ट करें</translation> </message> <message> <source>Comma separated file</source> @@ -94,8 +94,12 @@ 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>Exporting Failed</source> - <translation type="unfinished">निर्यात विफल हो गया है</translation> + <translation type="unfinished">एक्सपोर्ट नहीं हो पाया</translation> </message> </context> <context> @@ -121,7 +125,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Enter passphrase</source> - <translation type="unfinished">पासफ़्रेज़ मे प्रवेश करें</translation> + <translation type="unfinished">पासफ्रेज़ दर्ज करें</translation> </message> <message> <source>New passphrase</source> @@ -405,10 +409,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -422,101 +422,25 @@ Signing is only possible with addresses of the type 'legacy'.</source> </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">फ़ाइल से पीएसबीटी &लोड करें…</translation> - </message> - <message> - <source>Open &URI…</source> - <translation type="unfinished"> &यूआरआई खोलिये…</translation> - </message> - <message> <source>Close Wallet…</source> - <translation type="unfinished">वॉलेट बंद करें…</translation> + <translation type="unfinished">बटुआ बंद करें...</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">वॉलेट बनाएं</translation> + <translation type="unfinished">वॉलेट बनाएं...</translation> </message> <message> <source>Close All Wallets…</source> - <translation type="unfinished">सभी वॉलेट बंद करें…</translation> - </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> + <translation type="unfinished">सारे बटुएँ बंद करें...</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> <numerusform>Processed %n block(s) of transaction history.</numerusform> - <numerusform>ट्रानजेक्शन हिस्ट्री के ब्लॉक संसाधित किए गए है %n .</numerusform> + <numerusform>Processed %n block(s) of transaction history.</numerusform> </translation> </message> <message> - <source>Load PSBT from &clipboard…</source> - <translation type="unfinished">पीएसबीटी को &क्लिपबोर्ड से लोड करें…</translation> - </message> - <message> <source>Migrate Wallet</source> <translation type="unfinished">वॉलेट माइग्रेट करें</translation> </message> @@ -533,6 +457,30 @@ Signing is only possible with addresses of the type 'legacy'.</source> </translation> </message> <message> + <source>Click for more actions.</source> + <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> + <translation type="unfinished">अधिक विकल्पों के लिए क्लिक करें</translation> + </message> + <message> + <source>Show Peers tab</source> + <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment> + <translation type="unfinished">पीयर्स टैब दिखाएं</translation> + </message> + <message> + <source>Disable network activity</source> + <extracomment>A context menu item.</extracomment> + <translation type="unfinished">नेटवर्क गतिविधि अक्षम करें</translation> + </message> + <message> + <source>Enable network activity</source> + <extracomment>A context menu item. The network activity was disabled previously.</extracomment> + <translation type="unfinished">नेटवर्क गतिविधि सक्षम करें</translation> + </message> + <message> + <source>Error creating wallet</source> + <translation type="unfinished">बटवा निर्माण में गलती</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">त्रुटि: %1</translation> </message> @@ -608,7 +556,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Date</source> - <translation type="unfinished">तारीख़</translation> + <translation type="unfinished">डेट</translation> </message> <message> <source>Confirmations</source> @@ -651,13 +599,22 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">कॉपी बाइट्स</translation> </message> <message> + <source>Copy change</source> + <translation type="unfinished">कॉपी चैंज</translation> + </message> + <message> <source>(no label)</source> - <translation type="unfinished">(कोई लेबल नहीं)</translation> + <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>Create wallet failed</source> <translation type="unfinished">वॉलेट बनाना विफल</translation> </message> @@ -682,6 +639,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 +656,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> @@ -1373,10 +1341,6 @@ For more information on using this console, type %6. <translation type="unfinished">मेसेज</translation> </message> <message> - <source>(no label)</source> - <translation type="unfinished">(कोई लेबल नहीं)</translation> - </message> - <message> <source>(no message)</source> <translation type="unfinished">(नो मेसेज)</translation> </message> @@ -1556,6 +1520,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">कॉपी बाइट्स</translation> </message> <message> + <source>Copy change</source> + <translation type="unfinished">कॉपी चैंज</translation> + </message> + <message> <source>%1 (%2 blocks)</source> <translation type="unfinished">%1 (%2 ब्लाकस)</translation> </message> @@ -1732,11 +1700,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> <translation type="unfinished">आपके द्वारा परिवर्तन के लिए चुना गया पता इस वॉलेट का हिस्सा नहीं है। आपके वॉलेट में कोई भी या सभी धनराशि इस पते पर भेजी जा सकती है। क्या आपको यकीन है?</translation> </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(कोई लेबल नहीं)</translation> - </message> -</context> + </context> <context> <name>SendCoinsEntry</name> <message> @@ -1826,10 +1790,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">&संदेश पर हस्ताक्षर करें</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">आप अपने पते के साथ संदेशों/समझौतों पर हस्ताक्षर करके यह साबित कर सकते हैं कि आप उन्हें भेजे गए बिटकॉइन प्राप्त कर सकते हैं। सावधान रहें कि कुछ भी अस्पष्ट या यादृच्छिक पर हस्ताक्षर न करें, क्योंकि फ़िशिंग हमले आपको अपनी पहचान पर हस्ताक्षर करने के लिए छल करने का प्रयास कर सकते हैं। केवल पूरी तरह से विस्तृत बयानों पर हस्ताक्षर करें जिनसे आप सहमत हैं।</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">संदेश पर हस्ताक्षर करने के लिए बिटकॉइन पता</translation> </message> @@ -1922,10 +1882,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">कृपया पते की जांच करें और पुनः प्रयास करें।</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">दर्ज किया गया पता एक कुंजी को संदर्भित नहीं करता है।</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">वॉलेट अनलॉक रद्द कर दिया गया था। </translation> @@ -2217,10 +2173,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">(असंबंधित)</translation> </message> <message> - <source>(no label)</source> - <translation type="unfinished">(कोई लेबल नहीं)</translation> - </message> - <message> <source>Transaction status. Hover over this field to show number of confirmations.</source> <translation type="unfinished">लेनदेन की जानकारी. इस फ़ील्ड पर कर्सर लाएं ताकि कन्फ़र्मेशन की संख्या पता चले.</translation> </message> @@ -2346,11 +2298,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>Send Coins</source> <translation type="unfinished">सेन्ड कॉइन्स</translation> </message> - <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">क्लिपबोर्ड में कापी किया गया</translation> - </message> </context> <context> <name>WalletView</name> @@ -2366,6 +2313,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <context> <name>bitcoin-core</name> <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 अनुरोध %u पोर्ट पर सुनने का. इस बंदरगाह को "खराब" माना जाता है और इस प्रकार यह संभावना नहीं है कि कोई भी सहकर्मी इससे जुड़ेगा। विवरण और पूरी सूची के लिए doc/p2p-bad-ports.md देखें।</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">%s के लिए डिस्क स्थान ब्लॉक फ़ाइलों को समायोजित नहीं कर सकता है। इस निर्देशिका में लगभग %u GB डेटा संग्रहीत किया जाएगा।</translation> </message> @@ -2400,7 +2351,8 @@ The wallet might have been tampered with or created with malicious intent. </source> <translation type="unfinished">डिस्क्रिप्टर वॉलेट में अप्रत्याशित विरासत प्रविष्टि मिली। %s बटुआ लोड हो रहा है -हो सकता है कि वॉलेट से छेड़छाड़ की गई हो या दुर्भावनापूर्ण इरादे से बनाया गया हो।</translation> +हो सकता है कि वॉलेट से छेड़छाड़ की गई हो या दुर्भावनापूर्ण इरादे से बनाया गया हो। +</translation> </message> <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index e843aed672..c157aca5cc 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -176,6 +176,10 @@ Potpisivanje je moguće samo sa 'legacy' adresama. </translation> <translation type="unfinished">Unesite staru i novu lozinku za novčanik.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Nastavi</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">Zapamtite da šifriranje vašeg novčanika ne može u potpunosti zaštititi vaše bitcoinove od zloćudnog softvera kojim se zarazi vaše računalo.</translation> </message> @@ -393,7 +397,11 @@ Potpisivanje je moguće samo sa 'legacy' adresama. </translation> <numerusform>%n godina</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">uobičajeni novčanik</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -483,7 +491,7 @@ Potpisivanje je moguće samo sa 'legacy' adresama. </translation> </message> <message> <source>&Options…</source> - <translation type="unfinished">&Postavke</translation> + <translation type="unfinished">&Opcije</translation> </message> <message> <source>&Encrypt Wallet…</source> @@ -519,7 +527,7 @@ Potpisivanje je moguće samo sa 'legacy' adresama. </translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Učitaj PSBT iz datoteke</translation> + <translation type="unfinished">&Učitaj PSBT iz datoteke...</translation> </message> <message> <source>Open &URI…</source> @@ -690,10 +698,6 @@ Potpisivanje je moguće samo sa 'legacy' adresama. </translation> <translation type="unfinished">Sakrij vrijednost u tabu Pregled </translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">uobičajeni novčanik</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Nema dostupnih novčanika</translation> </message> @@ -1028,10 +1032,6 @@ Potpisivanje je moguće samo sa 'legacy' adresama. </translation> <translation type="unfinished">Upozorenje kod otvaranja novčanika</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">uobičajeni novčanik</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Otvorite novčanik</translation> @@ -2395,6 +2395,10 @@ Ako imate ovu grešku, od trgovca zatražite URI koji je kompatibilan sa BIP21.< <translation type="unfinished">Mrežna aktivnost isključena</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ništa</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Izvršava se naredba bez bilo kakvog novčanika</translation> </message> @@ -2742,8 +2746,7 @@ Za više informacija o korištenju ove konzile, utipkajte %6. </message> <message> <source>Hide transaction fee settings</source> - <translation type="unfinished">Sakrijte postavke za transakcijske provizije -</translation> + <translation type="unfinished">Sakrijte postavke za transakcijske provizije</translation> </message> <message> <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. @@ -3073,10 +3076,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation type="unfinished">&Potpišite poruku</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">Možete potpisati poruke/dogovore svojim adresama kako biste dokazali da možete pristupiti bitcoinima poslanim na te adrese. Budite oprezni da ne potpisujte ništa nejasno ili nasumično, jer napadi phishingom vas mogu prevariti da prepišite svoj identitet njima. Potpisujte samo detaljno objašnjene izjave s kojima se slažete.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin adresa pomoću koje ćete potpisati poruku</translation> </message> @@ -3161,10 +3160,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation type="unfinished">Molim provjerite adresu i pokušajte ponovo.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Unesena adresa ne odnosi se na ključ.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Otključavanje novčanika je otkazano.</translation> </message> @@ -3728,10 +3723,6 @@ Idi na Datoteka > Otvori novčanik za učitanje novčanika. <source>Can't display address</source> <translation type="unfinished">Ne mogu prikazati adresu</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">uobičajeni novčanik</translation> - </message> </context> <context> <name>WalletView</name> @@ -3844,10 +3835,6 @@ Idi na Datoteka > Otvori novčanik za učitanje novčanika. <translation type="unfinished">Format datoteke novčanika nije dostupan. Kako biste koristili reatefromdump, -format=<format> mora biti osiguran.</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Molimo provjerite jesu li datum i vrijeme na vašem računalu točni. Ako je vaš sat krivo namješten, %s neće raditi ispravno.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Molimo vas da doprinijete programu %s ako ga smatrate korisnim. Posjetite %s za više informacija.</translation> </message> @@ -3932,10 +3919,6 @@ Idi na Datoteka > Otvori novčanik za učitanje novčanika. <translation type="unfinished">-maxmempool mora biti barem %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Dogodila se kobna greška, vidi detalje u debug.log.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Ne može se razriješiti adresa -%s: '%s'</translation> </message> diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index a2f27b94a0..f3c9416193 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -184,6 +184,14 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> <translation type="unfinished">Írja be a tárca régi és új jelmondatát.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Tovább</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Vissza</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">Ne feledje, hogy a tárca titkosítása nem nyújt teljes védelmet az adathalász programok fertőzésével szemben.</translation> </message> @@ -303,6 +311,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> @@ -413,7 +433,11 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> <numerusform>%n év</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">alapértelmezett tárca</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -491,7 +515,7 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Tárcatitkosító jelmondat megváltoztatása</translation> + <translation type="unfinished">Tárcatitkosító jelszó megváltoztatása</translation> </message> <message> <source>&Send</source> @@ -519,7 +543,7 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>&Change Passphrase…</source> - <translation type="unfinished">Jelmondat &megváltoztatása…</translation> + <translation type="unfinished">Jelszó &megváltoztatása…</translation> </message> <message> <source>Sign &message…</source> @@ -527,7 +551,7 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Üzenetek aláírása a Bitcoin-címeivel, amivel bizonyíthatja, hogy az Öné</translation> + <translation type="unfinished">Üzenetek aláírása a Bitcoin-címeivel, amivel bizonyíthatja hogy a cím az Öné</translation> </message> <message> <source>&Verify message…</source> @@ -551,7 +575,7 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Tárca létrehozása...</translation> + <translation type="unfinished">Tárca készítése…</translation> </message> <message> <source>Close All Wallets…</source> @@ -607,7 +631,7 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">Paran&cssori opciók</translation> + <translation type="unfinished">Paran&cssor kapcsolók</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -637,7 +661,7 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>Warning</source> - <translation type="unfinished">Figyelmeztetés</translation> + <translation type="unfinished">Figyelem</translation> </message> <message> <source>Information</source> @@ -681,11 +705,11 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Tárca megnyitása</translation> + <translation type="unfinished">Tárca Megnyitása</translation> </message> <message> <source>Open a wallet</source> - <translation type="unfinished">Egy tárca megnyitása</translation> + <translation type="unfinished">Tárca megnyitása</translation> </message> <message> <source>Close wallet</source> @@ -726,17 +750,13 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> <translation type="unfinished">Értékek elrejtése az Áttekintés fülön</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">alapértelmezett tárca</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Nincs elérhető tárca</translation> </message> <message> <source>Wallet Data</source> <extracomment>Name of the wallet data file format.</extracomment> - <translation type="unfinished">Tárca adat</translation> + <translation type="unfinished">Tárca adatai</translation> </message> <message> <source>Load Wallet Backup</source> @@ -976,11 +996,11 @@ Aláírni csak régi típusú, egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>Copy &label</source> - <translation type="unfinished">C&ímke másolása</translation> + <translation type="unfinished">Címke &másolása</translation> </message> <message> <source>Copy &amount</source> - <translation type="unfinished">&Összeg másolása</translation> + <translation type="unfinished">Ö&sszeg másolása</translation> </message> <message> <source>Copy transaction &ID and output index</source> @@ -1139,10 +1159,6 @@ A migrációs folyamat készít biztonsági mentést a tárcáról migrálás el <translation type="unfinished">Tárca-megnyitási figyelmeztetés</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">alapértelmezett tárca</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Tárca megnyitása</translation> @@ -1598,6 +1614,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> @@ -2329,10 +2349,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Átvitel</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">A BIP324 munkamenet azonosító hex formátumú szöveglánca, ha van.</translation> - </message> - <message> <source>Session ID</source> <translation type="unfinished">Munkamenet azonosító</translation> </message> @@ -2439,6 +2455,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Irány/Típus</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">A BIP324 munkamenet-azonosító hex formátumban.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">A hálózati protokoll amin keresztül ez a partner kapcsolódik: IPv4, IPv6, Onion, I2P vagy CJDNS.</translation> </message> @@ -2631,10 +2651,18 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Hálózati tevékenység letiltva</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Semmi</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Parancs végrehajtása tárca nélkül</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Csomópont 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> @@ -3347,8 +3375,8 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk <translation type="unfinished">Üzenet &aláírása</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">Címeivel aláírhatja az üzeneteket/egyezményeket, amivel bizonyíthatja, hogy át tudja venni az ezekre a címekre küldött bitcoin-t. Vigyázzon, hogy ne írjon alá semmi félreérthetőt, mivel adathalász támadásokkal megpróbálhatják becsapni, hogy az azonosságát átírja másokra. Csak olyan részletes állításokat írjon alá, amivel egyetért.</translation> + <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">Aláírhat üzeneteket/megállapodásokat a régí típusú (P2PKH) címeivel amivel bizonyítja, hogy fogadni és elkölteni is tudja az oda küldött bitcoint. Legyen óvatos és ne írjon alá semmilyen ködös vagy véletlenszerű üzenetet, mivel adathalászok megkísérelhetik rávenni a személyazonosságának átruházására. Csak olyan alaposan részletezett állításokat írjon alá amivel teljesen egyetért.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3435,8 +3463,8 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk <translation type="unfinished">Ellenőrizze a címet és próbálja meg újra.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">A megadott cím nem hivatkozik egy kulcshoz sem.</translation> + <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">A megadott cím nem régi típusú (P2PKH) kulcsra hivatkozik. Üzenetek aláírása SegWit és más nem P2PKH típusú címekkel nem támogatott a jelenlegi %1 verzióban. Kérjük ellenőrizze a címet majd próbálja újra.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -4011,9 +4039,8 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">PSBT másolva</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Vágólapra másolva</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Díj emelési PSBT a vágólapra másolva</translation> </message> <message> <source>Can't sign transaction.</source> @@ -4024,12 +4051,12 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">A tranzakciót nem lehet elküldeni</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Nem lehet a címet megjeleníteni</translation> + <source>Signer error</source> + <translation type="unfinished">Aláíró hiba</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">alapértelmezett tárca</translation> + <source>Can't display address</source> + <translation type="unfinished">Nem lehet a címet megjeleníteni</translation> </message> </context> <context> @@ -4049,7 +4076,7 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <message> <source>Wallet Data</source> <extracomment>Name of the wallet data file format.</extracomment> - <translation type="unfinished">Tárca adat</translation> + <translation type="unfinished">Tárca adatai</translation> </message> <message> <source>Backup Failed</source> @@ -4163,10 +4190,6 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">Nincs tárca fájlformátum megadva. A createfromdump használatához -format=<format> megadása kötelező.</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">Ellenőrizze, hogy helyesen van-e beállítva a gépén a dátum és az idő! A %s nem fog megfelelően működni, ha rosszul van beállítva az óra.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Kérjük támogasson, ha hasznosnak találta a %s-t. Az alábbi linken további információt találhat a szoftverről: %s.</translation> </message> @@ -4275,10 +4298,6 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">-maxmempool legalább %d MB kell legyen.</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Súlyos belső hiba történt, részletek a debug.log-ban</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">-%s cím feloldása nem sikerült: '%s'</translation> </message> @@ -4292,7 +4311,7 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">Nem lehet írni a '%s' könyvtárba; ellenőrizze a jogosultságokat.</translation> + <translation type="unfinished">Nem tudok írni a '%s' könyvtárba, ellenőrizd a jogosultságokat.</translation> </message> <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> @@ -4327,6 +4346,12 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">Sikertelen az emelt díjak becslése, mert a megerősítetlen UTXO-k hatalmas mennyiségű megerősítetlen tranzakcióktól függnek.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Nem sikerült a láncállapot pillanatkép könyvtárat (%s) eltávolítani. Távolítsa el kézzel újraindítás előtt. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">Az érvénytelen peers.dat fájl átnevezése sikertelen. Kérjük mozgassa vagy törölje, majd próbálja újra.</translation> </message> @@ -4335,6 +4360,14 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">Díjbecslés sikertelen. Alapértelmezett díj letiltva. Várjon néhány blokkot vagy engedélyezze ezt: %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Nem sikerült a blokk fájlt lemezre írni. Ez valószínű I/O hiba következménye.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Nem sikerült a visszavonási fájlt lemezre írni. Ez valószínű I/O hiba következménye.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Összeférhetetlen beállítások: -dnsseed=1 lett megadva, de az -onlynet megtiltja az IPv4/IPv6 kapcsolatokat</translation> </message> @@ -4343,6 +4376,14 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">Érvénytelen összeg: %s=<amount>: '%s' (legalább a minrelay összeg azaz %s kell legyen, hogy ne ragadjon be a tranzakció)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Maximális tranzakciós súly kevesebb, mint a bemenetek nélküli tranzakció súlya</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Maximális tranzakciós súly túl alacsony, nincs hely a visszajáró kimenetnek</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">A kilépő kapcsolatok CJDNS-re korlátozottak (-onlynet=cjdns) de nincs megadva -cjdnsreachable</translation> </message> @@ -4359,6 +4400,14 @@ A "Fájl > Tárca megnyitása" menüben tölthet be egyet. <translation type="unfinished">A kilépő kapcsolatok i2p-re korlátozottak (-onlynet=i2p) de nincs megadva -i2psam</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Nem sikerült az '%s' -> '%s' átnevezés. Nem lehet kitisztítani a háttér láncállapot leveldb könyvtárat.</translation> + </message> + <message> + <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">Az előre kiválasztott bemenetek és a tárca automatikus bemeneteinek kombinációja meghaladja a maximális tranzakciós súlyt. Kérjük próbáljon kisebb összeget küldeni vagy kézzel egyesítse a tárca UTXO-it.</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">A bemenetek mérete meghaladja a maximum súlyt. Kérjük próbáljon kisebb összeget küldeni vagy kézzel egyesítse a tárca UTXO-it.</translation> </message> @@ -4401,6 +4450,10 @@ Kérjük próbálja futtatni a legújabb szoftver verziót. </translation> </message> <message> + <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">A számítógépének órája több mint %d perces eltérést mutat a hálózatéhoz képest, ez hátráltathatja a konszenzusra jutást. Miután megbizonyosodott az óra helyességéről ennek az üzenetnek nem szabad megjelennie a csomópont újraindítása után. Újraindítás nélkül nem jelenik meg többször miután elegendő új kimenő partnerhez csatlakozott, ami eltarthat egy ideig. További információért tanulmányozhatja a `timeoffset` mezőt a `getpeerinfo` és a `getnetworkinfo` RPC parancsokban.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4413,6 +4466,18 @@ Unable to restore backup of wallet.</source> A tárca biztonsági mentésének visszaállítása sikertelen.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">A whitebind csak bejövő kapcsolatokhoz használható ("out" lett megadva)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Végzetes belső hiba történt, részletek a debug.log fájlban:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Nem található assumeutxo adat a megadott blokk ellenőrzőösszeghez '%s'.</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">Blokkok ellenőrzése megszakítva</translation> </message> @@ -4425,6 +4490,10 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">Szerzői jog (C) fenntartva %i-%i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Hibás blokk találata valószínűleg hardver hibára utal.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Sérült blokk-adatbázis észlelve</translation> </message> @@ -4453,6 +4522,14 @@ 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>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Elliptikus görbés kriptográfia épségi ellenőrzése sikertelen. %s most leáll.</translation> + </message> + <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">Hiba a tárca tranzakciókat eltávolító adatbázis tranzakció létrehozása közben</translation> + </message> + <message> <source>Error creating %s</source> <translation type="unfinished">Hiba %s létrehozása közben</translation> </message> @@ -4501,6 +4578,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">Hiba a tárca tranzakciókat eltávolító adatbázis tranzakció indítása közben</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,10 +4666,30 @@ 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">Hiba: címjegyzék másolása sikertelen ehhez a tárcához: %s</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">Hiba: adatbázis tranzakció végrehajtása sikertelen ehhez a tárcához: %s</translation> + </message> + <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">Sikertelen a legjobb blokkhoz (%s) csatlakozás.</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Blokk szétkapcsolása nem sikerült.</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> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Blokk olvasása nem sikerült.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Indítás közben nem sikerült átfésülni a tárcát</translation> </message> @@ -4601,6 +4702,26 @@ 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>Failed to write block.</source> + <translation type="unfinished">Blokk írása nem sikerült.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">A blokk-index adatbázis írása nem sikerült.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Az érme-adatbázis írása nem sikerült.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Visszavonási adatok írása nem sikerült.</translation> + </message> + <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">Tranzakció eltávolítása nem sikerült: %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> @@ -4693,6 +4814,10 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">Tárca betöltése…</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Maximális tranzakciós súlynak %d és %d között kell lennie.</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Hiányzó összeg</translation> </message> @@ -4721,6 +4846,10 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">Nem megoldható az előre kiválasztott bemenet %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Csak az irány lett beállítva, engedélyek nem: '%s'</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Ritkított üzemmódot nem lehet negatív értékkel konfigurálni.</translation> </message> @@ -4765,6 +4894,18 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">Ismeretlen bekezdés [%s]</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Az aláíró nem jelzett vissza címet</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">Az aláíró váratlan címet jelzett vissza: %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Aláíró hibát jelzett: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Tranzakció aláírása sikertelen</translation> </message> @@ -4793,6 +4934,18 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">Hálózati szálak indítása…</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Rendszerhiba lemezre írás közben: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Rendszerhiba külső blokk fájl betöltése közben: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Rendszerhiba blokk lemezre mentése közben: %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">A forráskód elérhető innen: %s.</translation> </message> @@ -4809,6 +4962,10 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">A tárca nem fog a minimális továbbítási díjnál kevesebbet fizetni. </translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Nem tartozik ScriptPubKeyManager ehhez a címhez</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Ez egy kísérleti szoftver.</translation> </message> @@ -4821,6 +4978,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">A %s tranzakció nem tartozik ehhez a tárcához</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">Tranzakció összege túl alacsony</translation> </message> @@ -4845,10 +5006,6 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">Túl nagy tranzakció</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Nem sikerült a memóriát lefoglalni -maxsigcachesize számára: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Ezen a számítógépen nem lehet ehhez társítani: %s (a bind ezzel a hibával tért vissza: %s)</translation> </message> @@ -4909,6 +5066,10 @@ A tárca biztonsági mentésének visszaállítása sikertelen.</translation> <translation type="unfinished">Ismeretlen új szabályok aktiválva (verzióbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Ismeretlen beállítás "%s" lett megadva itt: -test=<option>.</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished">Nem támogatott globális naplózási szint %s=%s. Lehetséges értékek: %s.</translation> </message> @@ -4929,6 +5090,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">Hiba: Nem lehet törölni csak megfigyelt tranzakciókat.</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..864787803d 100644 --- a/src/qt/locale/bitcoin_id.ts +++ b/src/qt/locale/bitcoin_id.ts @@ -79,6 +79,14 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <translation type="unfinished">Terjadi sebuah kesalahan saat mencoba menyimpan daftar alamat ke %1. Silakan coba lagi.</translation> </message> <message> + <source>Sending addresses - %1</source> + <translation type="unfinished">Alamat pengirim - %1</translation> + </message> + <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">Penerima alamat - %1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">Gagal Mengekspor</translation> </message> @@ -87,7 +95,7 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <name>AddressTableModel</name> <message> <source>Address</source> - <translation type="unfinished">Alamat</translation> + <translation type="unfinished">0x5a52E96BAcdaBb82fd05763E25335261B270Efcb</translation> </message> <message> <source>(no label)</source> @@ -259,6 +267,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"> @@ -295,10 +315,102 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <numerusform>%n year(s)</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">wallet default</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> + <source>Change the passphrase used for wallet encryption</source> + <translation type="unfinished">Ubah kata kunci yang digunakan untuk enkripsi dompet</translation> + </message> + <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&Enkripsi wallet...</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation type="unfinished">Enkripsi private key yang dimiliki dompet Anda</translation> + </message> + <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Cadangkan Dompet...</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">&Ganti kata sandi...</translation> + </message> + <message> + <source>Sign &message…</source> + <translation type="unfinished">Tanda tangani dan kirim pessan...</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation type="unfinished">Tanda tangani sebuah pesan menggunakan alamat Bitcoin Anda untuk membuktikan bahwa Anda adalah pemiliknya</translation> + </message> + <message> + <source>&Verify message…</source> + <translation type="unfinished">&Verifikasi pesan...</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation type="unfinished">Verifikasi pesan untuk memastikan bahwa pesan tersebut ditanda tangani oleh suatu alamat Bitcoin tertentu</translation> + </message> + <message> + <source>&Load PSBT from file…</source> + <translation type="unfinished">&Muat PSBT dari file...</translation> + </message> + <message> + <source>Open &URI…</source> + <translation type="unfinished">Buka &URI...</translation> + </message> + <message> + <source>Close Wallet…</source> + <translation type="unfinished">Tutup Dompet...</translation> + </message> + <message> + <source>Create Wallet…</source> + <translation type="unfinished">Bikin dompet...</translation> + </message> + <message> + <source>Close All Wallets…</source> + <translation type="unfinished">Tutup semua dompet...</translation> + </message> + <message> + <source>&File</source> + <translation type="unfinished">&Berkas</translation> + </message> + <message> + <source>&Settings</source> + <translation type="unfinished">&Pengaturan</translation> + </message> + <message> + <source>&Help</source> + <translation type="unfinished">&Bantuan</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation type="unfinished">Baris tab</translation> + </message> + <message> + <source>Syncing Headers (%1%)…</source> + <translation type="unfinished">Singkronisasi Header (%1%)...</translation> + </message> + <message> + <source>Synchronizing with network…</source> + <translation type="unfinished">Mensinkronisasi dengan jaringan</translation> + </message> + <message> + <source>Indexing blocks on disk…</source> + <translation type="unfinished">Mengindeks blok pada disk...</translation> + </message> + <message> + <source>Processing blocks on disk…</source> + <translation type="unfinished">Memproses blok pada disk ...</translation> + </message> + <message> <source>Connecting to peers…</source> <translation type="unfinished">Menghubungkan ke peers...</translation> </message> @@ -321,7 +433,7 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>Processed %n block(s) of transaction history.</numerusform> + <numerusform>%n blok riwayat transaksi diproses.</numerusform> </translation> </message> <message> @@ -357,6 +469,50 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <translation type="unfinished">Terbaru</translation> </message> <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation type="unfinished">Muat transaksi Bitcoin yang ditandatangani seperapat</translation> + </message> + <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Masukkan PSBT dari &clipboard</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation type="unfinished">Muat transaksi Bitcoin yang ditandatangani seperapat dari clipboard</translation> + </message> + <message> + <source>Node window</source> + <translation type="unfinished">Jendela Node</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation type="unfinished">Buka konsol debug dan diagnosa node</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation type="unfinished">Address &Pengirim</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation type="unfinished">Address &Penerima</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation type="unfinished">Buka URI bitcoin:</translation> + </message> + <message> + <source>Open Wallet</source> + <translation type="unfinished">Buka Wallet</translation> + </message> + <message> + <source>Open a wallet</source> + <translation type="unfinished">Buka sebuah wallet</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Tutup wallet</translation> + </message> + <message> <source>Restore Wallet…</source> <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> <translation type="unfinished">Pulihkan Dompet…</translation> @@ -391,10 +547,6 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <translation type="unfinished">Mask nilai yang ada di tab Overview</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">wallet default</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Tidak ada wallet tersedia</translation> </message> @@ -426,23 +578,11 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <source>Main Window</source> <translation type="unfinished">Jendela Utama</translation> </message> - <message> - <source>%1 client</source> - <translation type="unfinished">%1 klien</translation> - </message> - <message> - <source>&Hide</source> - <translation type="unfinished">Sembunyi</translation> - </message> - <message> - <source>S&how</source> - <translation type="unfinished">Tampilkan</translation> - </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>%n koneksi yang aktif ke jaringan Bitcoin</numerusform> + <numerusform>%n active connection(s) to Bitcoin network.</numerusform> </translation> </message> <message> @@ -488,19 +628,10 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <source>(%1 locked)</source> <translation type="unfinished">(%1 terkunci)</translation> </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(tidak ada label)</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">Bikin dompet</translation> - </message> - <message> <source>Too many external signers found</source> <translation type="unfinished">Terlalu banyak penanda tangan eksternal ditemukan</translation> </message> @@ -525,6 +656,10 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <translation type="unfinished">Migrasi dompet</translation> </message> <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">Anda yakin ingin memindahkan dompet <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. @@ -553,6 +688,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> @@ -572,10 +711,6 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <translation type="unfinished">Peringatan membuka wallet</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">wallet default</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">Membuka Wallet <b>%1</b>...</translation> @@ -974,6 +1109,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 +1251,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> @@ -1154,10 +1297,6 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <translation type="unfinished">Transpor</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">String ID sesi BIP324 dalam heksadesimal, jika ada.</translation> - </message> - <message> <source>Session ID</source> <translation type="unfinished">ID sesi</translation> </message> @@ -1184,6 +1323,10 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <translation type="unfinished">Jumlah total alamat yang diterima dari rekan ini yang dihapus (tidak diproses) karena pembatasan tarif.</translation> </message> <message> + <source>Node window</source> + <translation type="unfinished">Jendela Node</translation> + </message> + <message> <source>Last block time</source> <translation type="unfinished">Waktu blok terakhir</translation> </message> @@ -1244,6 +1387,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 +1433,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> @@ -1318,18 +1469,6 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan </message> </context> <context> - <name>WalletModel</name> - <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Disalin ke clipboard</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">wallet default</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> @@ -1350,7 +1489,7 @@ wallet</translation> <name>bitcoin-core</name> <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 gagal memvalidasi status snapshot -assumeutxo. Ini mengindikasikan masalah perangkat keras, atau bug pada perangkat lunak, atau modifikasi perangkat lunak yang buruk yang memungkinkan snapshot yang tidak valid dimuat. Sebagai akibatnya, node akan dimatikan dan berhenti menggunakan status apa pun yang dibangun di atas snapshot, mengatur ulang tinggi rantai dari %d ke %d. Pada restart berikutnya, node akan melanjutkan sinkronisasi dari %d tanpa menggunakan data snapshot apa pun. Silakan laporkan kejadian ini ke %s, termasuk bagaimana Anda mendapatkan snapshot tersebut. Chainstate snapshot yang tidak valid akan dibiarkan di disk jika hal itu membantu dalam mendiagnosis masalah yang menyebabkan kesalahan ini.</translation> + <translation type="unfinished">%s gagal memvalidasi status snapshot -asumsikan UTXO (Keluaran Transaksi yang tidak terpakai). Ini mengindikasikan masalah perangkat keras, atau bug pada perangkat lunak, atau modifikasi perangkat lunak yang buruk yang memungkinkan snapshot yang tidak valid dimuat. Sebagai akibatnya, node akan dimatikan dan berhenti menggunakan status apa pun yang dibangun di atas snapshot, mengatur ulang tinggi rantai dari %d ke %d. Pada restart berikutnya, node akan melanjutkan sinkronisasi dari %d tanpa menggunakan data snapshot apa pun. Silakan laporkan kejadian ini ke %s, termasuk bagaimana Anda mendapatkan snapshot tersebut. Status rantai snapshot yang tidak valid akan dibiarkan di disk jika hal ini membantu dalam mendiagnosis masalah yang menyebabkan kesalahan ini.</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> @@ -1382,7 +1521,7 @@ wallet</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">Tingkat penebangan khusus kategori yang tidak didukung %1$s=%2$s. Diharapkan %1$s=<kategori>:<loglevel>. Kategori yang valid: %3$s. Tingkat pencatatan yang valid: %4$s.</translation> + <translation type="unfinished">Tingkat penebangan khusus kategori yang tidak didukung %1$s=%2$s. Diharapkan %1$s=<category>:<loglevel>. Kategori yang valid: %3$s. Tingkat pencatatan yang valid: %4$s.</translation> </message> <message> <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> @@ -1397,6 +1536,10 @@ wallet</translation> <translation type="unfinished">Dompet berhasil dimuat. Tipe dompet lama akan ditinggalkan dan dukungan untuk membuat dan membuka dompet ini akan dihapus di masa depan. Dompet lama dapat dimigrasikan ke dompet deskriptor dengan migratewallet.</translation> </message> <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation type="unfinished">Tidak dapat menulis ke direktori data '%s'; periksa izinnya.</translation> + </message> + <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> <translation type="unfinished">%s ditetapkan sangat tinggi! Biaya sebesar ini dapat dibayarkan dalam satu transaksi.</translation> </message> @@ -1422,7 +1565,7 @@ wallet</translation> </message> <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> - <translation type="unfinished">Estimasi biaya gagal. Fallbackfee dinonaktifkan. Tunggu beberapa blok atau aktifkan %s.</translation> + <translation type="unfinished">Estimasi biaya gagal. Biaya cadangan dinonaktifkan. Tunggu beberapa blok atau aktifkan %s.</translation> </message> <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> @@ -1430,7 +1573,7 @@ wallet</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">Jumlah yang tidak valid untuk %s=<jumlah>: '%s' (harus setidaknya biaya minrelay sebesar %s untuk mencegah transaksi macet)</translation> + <translation type="unfinished">Jumlah yang tidak valid untuk %s=<amount>: '%s' (harus setidaknya biaya minrelay sebesar %s untuk mencegah transaksi macet)</translation> </message> <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> @@ -1507,10 +1650,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,20 +1690,44 @@ 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> <message> <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> - <translation type="unfinished">Jumlah yang tidak valid untuk %s=<jumlah>: '%s' (harus minimal %s)</translation> + <translation type="unfinished">Jumlah yang tidak valid untuk %s=<amount>: '%s' (harus minimal %s)</translation> </message> <message> <source>Invalid amount for %s=<amount>: '%s'</source> @@ -1583,8 +1758,8 @@ Tidak dapat memulihkan cadangan dompet..</translation> <translation type="unfinished">Direktori data yang ditentukan "%s" tidak ada.</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> + <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 find UTXO for external input</source> @@ -1599,8 +1774,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_it.ts b/src/qt/locale/bitcoin_it.ts index 83410574dd..8a2cf107e1 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -184,6 +184,14 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation> <translation type="unfinished">Inserisci la vecchia passphrase e la nuova passphrase per il portafoglio.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continua</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Indietro</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">Ricorda che la cifratura del portafoglio non protegge del tutto i tuoi bitcoin dal furto da parte di malware che infettasse il tuo computer.</translation> </message> @@ -197,7 +205,7 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation> </message> <message> <source>Your wallet is now encrypted. </source> - <translation type="unfinished">Il tuo portafoglio è ora cifrato.</translation> + <translation type="unfinished">Il tuo portafoglio ora è cifrato.</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> @@ -402,7 +410,11 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation> <numerusform>%n anni</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">portafoglio predefinito</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -427,7 +439,7 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation> </message> <message> <source>Quit application</source> - <translation type="unfinished">Chiudi applicazione</translation> + <translation type="unfinished">Chiudi l'applicazione</translation> </message> <message> <source>&About %1</source> @@ -560,19 +572,19 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Sincronizzando Headers (1%1%)...</translation> + <translation type="unfinished">Sincronizzazione Intestazioni in corso (1%1%)...</translation> </message> <message> <source>Synchronizing with network…</source> - <translation type="unfinished">Sincronizzando con la rete...</translation> + <translation type="unfinished">Sincronizzazione con la rete in corso...</translation> </message> <message> <source>Indexing blocks on disk…</source> - <translation type="unfinished">Indicizzando i blocchi su disco...</translation> + <translation type="unfinished">Indicizzazione dei blocchi su disco in corso...</translation> </message> <message> <source>Processing blocks on disk…</source> - <translation type="unfinished">Processando i blocchi su disco...</translation> + <translation type="unfinished">Elaborazione dei blocchi su disco in corso...</translation> </message> <message> <source>Connecting to peers…</source> @@ -635,7 +647,7 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">Carica Partially Signed Bitcoin Transaction</translation> + <translation type="unfinished">Carica Transazione Bitcoin Parzialmente Firmata (PSBT)</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -712,10 +724,6 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation> <translation type="unfinished">Maschera gli importi nella sezione "Panoramica"</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">portafoglio predefinito</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Nessun portafoglio disponibile</translation> </message> @@ -1080,7 +1088,7 @@ Il processo di migrazione creerà un backup del portafoglio prima della migrazio </message> <message> <source>Migrate Wallet</source> - <translation type="unfinished">Migra Wallet</translation> + <translation type="unfinished">Migra Portafoglio</translation> </message> <message> <source>Migrating Wallet <b>%1</b>…</source> @@ -1118,10 +1126,6 @@ Il processo di migrazione creerà un backup del portafoglio prima della migrazio <translation type="unfinished">Avviso apertura portafoglio</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">portafoglio predefinito</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Apri Portafoglio</translation> @@ -2253,6 +2257,14 @@ Se ricevi questo errore, dovresti richiedere al commerciante di fornire un URI c <translation type="unfinished">Numero di connessioni</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Indirizzi Locali</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Indirizzi di rete che il tuo nodo Bitcoin sta usando per comunicare con altri nodi.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Catena di Blocchi</translation> </message> @@ -2297,6 +2309,10 @@ Se ricevi questo errore, dovresti richiedere al commerciante di fornire un URI c <translation type="unfinished">Seleziona un peer per visualizzare informazioni più dettagliate.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Nascondi Dettagli Peers</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versione del livello di trasporto (transport layer): %1</translation> </message> @@ -2305,10 +2321,6 @@ Se ricevi questo errore, dovresti richiedere al commerciante di fornire un URI c <translation type="unfinished">Trasporto</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">La stringa dell' ID sessione BIP324 nell'hex, se presente.</translation> - </message> - <message> <source>Session ID</source> <translation type="unfinished">ID Sessione</translation> </message> @@ -2595,6 +2607,10 @@ Se ricevi questo errore, dovresti richiedere al commerciante di fornire un URI c <translation type="unfinished">Attività di rete disabilitata</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Nessuno</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Esecuzione del comando senza alcun portafoglio</translation> </message> @@ -3297,8 +3313,8 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation type="unfinished">&Firma Messaggio</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">È possibile firmare messaggi/accordi con i propri indirizzi in modo da dimostrare di poter ricevere bitcoin attraverso di essi. Presta attenzione a non firmare dichiarazioni vaghe o casuali, perché attacchi di phishing potrebbero cercare di indurti ad apporre la firma su di esse. Firma esclusivamente dichiarazioni completamente dettagliate e delle quali condividi in pieno il contenuto.</translation> + <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">È possibile firmare messaggi/accordi con i tuoi indirizzi (P2PKH) legacy per dimostrare di poter ricevere bitcoin attraverso di essi. Presta attenzione a non firmare dichiarazioni vaghe o casuali, perché attacchi di phishing potrebbero cercare di indurti ad apporre la firma su di esse. Firma esclusivamente dichiarazioni completamente dettagliate e delle quali condividi in pieno il contenuto.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3385,8 +3401,8 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation type="unfinished">Per favore controlla l'indirizzo e prova di nuovo.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">L'indirizzo bitcoin inserito non è associato a nessuna chiave.</translation> + <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">L'indirizzo inserito non si riferisce a una chiave legacy (P2PKH). La firma dei messaggi per SegWit e altri tipi di indirizzi non P2PKH non è supportata in questa versione di %1. Controlla l'indirizzo e riprova.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3958,9 +3974,8 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">PSBT copiata</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiato negli appunti</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Aumento delle tariffe PSBT copiato negli appunti</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3971,12 +3986,12 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">Non è stato possibile completare la transazione</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Non è possibile mostrare l'indirizzo</translation> + <source>Signer error</source> + <translation type="unfinished">Errore del firmatario</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">portafoglio predefinito</translation> + <source>Can't display address</source> + <translation type="unfinished">Non è possibile mostrare l'indirizzo</translation> </message> </context> <context> @@ -4110,10 +4125,6 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">Nessun formato assegnato al file del portafoglio. Per usare createfromdump, -format=<format> deve essere fornito.</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">Per favore controllate che la data del computer e l'ora siano corrette! Se il vostro orologio è sbagliato %s non funzionerà correttamente.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Per favore contribuite se ritenete %s utile. Visitate %s per maggiori informazioni riguardo il software.</translation> </message> @@ -4222,10 +4233,6 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">-maxmempool deve essere almeno %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Si è verificato un errore interno fatale, consultare debug.log per i dettagli</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Impossobile risolvere l'indirizzo -%s: '%s'</translation> </message> @@ -4274,6 +4281,12 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">Impossibile calcolare il salto di commissioni, poiché gli UTXO non confermati dipendono da una enorme serie di transazioni non confermate.</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Impossibile rimuovere la directory dello stato della catena dello snapshot (1%s). Rimuovilo manualmente prima di riavviare. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">Mancata rinominazione del file peers.dat non valido. Per favore spostarlo o eliminarlo e provare di nuovo.</translation> </message> @@ -4282,6 +4295,14 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">La stima della tariffa non è riuscita. La Commissione di riserva è disabilitata. Attendere qualche blocco o abilitare %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Lo scaricamento del file di blocco su disco non è riuscito. Questo è probabilmente il risultato di un errore I/O.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Lo scaricamento del file di annullamento su disco non è riuscito. Questo è probabilmente il risultato di un errore I/O.</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Opzioni incompatibili: -dnsseed=1 è stato specificato esplicitamente, ma -onlynet vieta le connessioni a IPv4/IPv6</translation> </message> @@ -4290,6 +4311,14 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">Importo non valido per %s=<amount>: '%s' (deve essere almeno la commissione minrelay di %s per evitare transazioni bloccate)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Il peso massimo della transazione è inferiore al peso della transazione senza input</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Il peso massimo della transazione è troppo basso, non può contenere il resto di ritorno</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">Le connessioni in uscita sono limitate a CJDNS (-onlynet=cjdns) ma -cjdnsreachable non è fornito.</translation> </message> @@ -4306,6 +4335,14 @@ Vai su File > Apri Portafoglio per caricare un portafoglio. <translation type="unfinished">Le connessioni in uscita sono limitate a i2p (-onlynet=i2p), ma -i2psam non è fornito.</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Rinominazione di '%s' -> '%s' fallita. Impossibile ripulire la directory di background chainstate leveldb.</translation> + </message> + <message> + <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">La combinazione degli input preselezionati e della selezione automatica degli input del portafoglio supera il peso massimo della transazione. Prova ad inviare un importo inferiore o a consolidare manualmente gli UTXO del portafoglio.</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">La dimensione degli inputs supera il peso massimo. Si prega di provare a inviare una quantità inferiore o a consolidare manualmente gli UTXO del portafoglio.</translation> </message> @@ -4348,6 +4385,10 @@ Provare a eseguire l'ultima versione del software. </translation> </message> <message> + <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">La data e l'ora del computer sembrano essere più di %d minuti fuori sicnronismo con la rete, questo potrebbe causare un errore di consenso. Dopo aver confermato l'orario del computer, questo messaggio non dovrebbe più apparire al riavvio del nodo. Senza un riavvio, dovrebbe smettere di apparire automaticamente dopo che ci si è connessi a un numero sufficiente di nuovi nodi, il che può richiedere del tempo. È possibile ispezionare il campo `timeoffset` dei metodi RPC `getpeerinfo` e `getnetworkinfo` per ottenere maggiori informazioni.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4360,6 +4401,18 @@ Unable to restore backup of wallet.</source> Non in grado di ripristinare il backup del portafoglio.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind può essere usato solo per le connessioni in entrata ("out" è stato passato)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Si è verificato un errore interno fatale, vedere debug.log per i dettagli: </translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Dati Assumeutxo non trovati per il blockhash fornito '%s'.</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">La verifica del blocco è stata interrotta</translation> </message> @@ -4372,6 +4425,10 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Diritto d'autore (C) %i-%i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">È stato trovato un blocco corrotto che indica un potenziale guasto hardware.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Rilevato database blocchi corrotto</translation> </message> @@ -4400,6 +4457,10 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Il dumpfile %s non esiste.</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Errore nel controllo di integrità della crittografia a curva ellittica. %s in spegnimento. </translation> + </message> + <message> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished">Errore nel completamento della db txn per rimuovere transazioni dal wallet</translation> </message> @@ -4548,10 +4609,22 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Errore: la transazione database non può essere eseguita per il portafoglio %s</translation> </message> <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">Non è stato possibile connettersi al blocco migliore (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Non è stato possibile scollegare il blocco.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Nessuna porta disponibile per l'ascolto. Usa -listen=0 se vuoi procedere comunque.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Errore nella lettura del blocco.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Impossibile ripetere la scansione del portafoglio durante l'inizializzazione</translation> </message> @@ -4564,10 +4637,31 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Errore nella verifica del database</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">Errore nella scrittura del blocco.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Non è stato possibile scrivere sul database degli indici di blocco.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Impossibile scrivere sul database delle monete.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished"> +Errore nella scrittura dei dati di ripristino.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">La rimozione della transazione è fallita: %s</translation> </message> <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation type="unfinished">Il tasso di conversione(%s) è inferiore al minore tasso di conversione delle impostazioni(%s)</translation> + </message> + <message> <source>Ignoring duplicate -wallet %s.</source> <translation type="unfinished">Ignorando il duplicato -wallet %s.</translation> </message> @@ -4656,6 +4750,10 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Caricando il portafoglio...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Il peso massimo della transazione deve essere tra %d e %d</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Quantità mancante</translation> </message> @@ -4684,6 +4782,10 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Ingresso pre-selezionato non risolvibile %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">È stata impostata solo la direzione, senza autorizzazioni: '%s'</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Prune non può essere configurato con un valore negativo.</translation> </message> @@ -4728,6 +4830,18 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">La sezione [%s] non è riconosciuta</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">Signer non ha generato un indirizzo di ritorno</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">Signer ha generato un indirizzo imprevisto %s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">Signer restituito un errore: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Firma transazione fallita</translation> </message> @@ -4756,6 +4870,19 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">L'esecuzione delle threads della rete sta iniziando...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Errore di sistema in fase di svuotamento: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished"> Errore di sistema in fase di caricamento del file di blocco esterno: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished"> +Errore di sistema in fase di salvataggio del blocco nel disco: %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Il codice sorgente è disponibile in %s</translation> </message> @@ -4772,6 +4899,10 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Il portafoglio eviterà di pagare meno della tariffa minima di trasmissione.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Non c'è uno ScriptPubKeyManager per questo indirizzo</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Questo è un software sperimentale.</translation> </message> @@ -4812,10 +4943,6 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Transazione troppo grande</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Impossibile allocare memoria per -maxsigcachesize: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Impossibile associarsi a %s su questo computer (l'associazione ha restituito l'errore %s)</translation> </message> @@ -4876,6 +5003,10 @@ Non in grado di ripristinare il backup del portafoglio.</translation> <translation type="unfinished">Nuove regole non riconosciute sono state attivate (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opzione non riconosciuta "%s" fornita in -test=<option>.</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished">Livello di logging globale non supportato %s=%s. Regole valide: %s.</translation> </message> @@ -4909,7 +5040,7 @@ Non in grado di ripristinare il backup del portafoglio.</translation> </message> <message> <source>Verifying wallet(s)…</source> - <translation type="unfinished">Verificando il(i) portafoglio(portafogli)...</translation> + <translation type="unfinished">Verifica portafoglio(portafogli) in corso...</translation> </message> <message> <source>Wallet needed to be rewritten: restart %s to complete</source> diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index bdd23b7c04..1b9a9c3ab0 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -3,7 +3,8 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">右クリックでアドレスまたはラベルを編集</translation> + <translation type="unfinished"> +右クリックしてアドレスまたはラベルを編集します。</translation> </message> <message> <source>Create a new address</source> @@ -64,8 +65,7 @@ <message> <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. Signing is only possible with addresses of the type 'legacy'.</source> - <translation type="unfinished">これらは支払いを受け取るための、あなたの Bitcoin アドレスです。新しいアドレスを作成するには受取タブ内の「新しい受取用アドレスを作成」ボタンを使用します。 -署名は、タイプが「レガシー」のアドレスのみ可能です。</translation> + <translation type="unfinished">これが支払いを受け取るためのあなたのビットコインアドレスです。新しいアドレスを作成するには、受信タブの「新しい受信アドレスを作成」ボタンを使用してください。署名は「レガシー」タイプのアドレスでのみ可能です。</translation> </message> <message> <source>&Copy Address</source> @@ -81,7 +81,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Export Address List</source> - <translation type="unfinished">アドレス帳をエクスポート</translation> + <translation type="unfinished">アドレス帳データをエクスポートする</translation> </message> <message> <source>Comma separated file</source> @@ -184,6 +184,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ウォレット用の旧パスフレーズと新パスフレーズを入力してください。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">続ける</translation> + </message> + <message> + <source>Back</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">ウォレットを暗号化しても、コンピュータに感染したマルウェアなどによる Bitcoin の盗難を完全に防ぐことはできないことにご注意ください。</translation> </message> @@ -303,6 +311,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> @@ -417,7 +437,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 kB</source> <translation type="unfinished">%1 KB</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">デフォルトウォレット</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -511,7 +535,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">ウォレットを暗号化(&E)…</translation> + <translation type="unfinished">ウォレットを暗号化…(&E)</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -519,15 +543,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">ウォレットをバックアップ(&B)…</translation> + <translation type="unfinished">ウォレットをバックアップ…(&B)</translation> </message> <message> <source>&Change Passphrase…</source> - <translation type="unfinished">パスフレーズを変更(&C)…</translation> + <translation type="unfinished">パスフレーズを変更…(&C)</translation> </message> <message> <source>Sign &message…</source> - <translation type="unfinished">メッセージに署名(&m)…</translation> + <translation type="unfinished">メッセージを署名…(&m)</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> @@ -535,7 +559,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Verify message…</source> - <translation type="unfinished">メッセージを検証(&V)…</translation> + <translation type="unfinished">メッセージを検証…(&V)</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> @@ -543,11 +567,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">PSBTをファイルから読む(&L)…</translation> + <translation type="unfinished">PSBTをファイルから読む…(&L)</translation> </message> <message> <source>Open &URI…</source> - <translation type="unfinished">URIを開く(&U)…</translation> + <translation type="unfinished">URIを開く…(&U)</translation> </message> <message> <source>Close Wallet…</source> @@ -555,7 +579,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">ウォレットを作成...</translation> + <translation type="unfinished">ウォレットを作成…</translation> </message> <message> <source>Close All Wallets…</source> @@ -579,23 +603,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">ヘッダを同期中 (%1%)...</translation> + <translation type="unfinished">ヘッダを同期中 (%1%)…</translation> </message> <message> <source>Synchronizing with network…</source> - <translation type="unfinished">ネットワークに同期中…</translation> + <translation type="unfinished">ネットワークに同期中……</translation> </message> <message> <source>Indexing blocks on disk…</source> - <translation type="unfinished">ディスク上のブロックをインデックス中...</translation> + <translation type="unfinished">ディスク上のブロックをインデックス中…</translation> </message> <message> <source>Processing blocks on disk…</source> - <translation type="unfinished">ディスク上のブロックを処理中...</translation> + <translation type="unfinished">ディスク上のブロックを処理中…</translation> </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">ピアに接続中…</translation> + <translation type="unfinished">ピアに接続中...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> @@ -653,7 +677,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">部分的に署名されたBitcoinの取引を読み込む</translation> + <translation type="unfinished">部分的に署名されたビットコインのトランザクションを読み込み</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -661,7 +685,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">部分的に署名されたBitcoinの取引をクリップボードから読み込む</translation> + <translation type="unfinished">部分的に署名されたビットコインのトランザクションをクリップボードから読み込み</translation> </message> <message> <source>Node window</source> @@ -723,19 +747,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Mask values</source> - <translation type="unfinished">値を隠す (&M)</translation> + <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> + <translation type="unfinished">ウォレットは利用できません</translation> </message> <message> <source>Wallet Data</source> @@ -775,23 +795,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Hide</source> - <translation type="unfinished">隠す (&H)</translation> + <translation type="unfinished">隠す</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">表示 (&h)</translation> + <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>Bitcoinネットワークへの %n のアクティブな接続。</numerusform> + <numerusform>%n ビットコイン ネットワークへのアクティブな接続。</numerusform> </translation> </message> <message> <source>Click for more actions.</source> <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> - <translation type="unfinished">クリックして、さらにアクションを表示。</translation> + <translation type="unfinished">クリックして、より多くのアクションを表示。</translation> </message> <message> <source>Show Peers tab</source> @@ -801,16 +821,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <source>Disable network activity</source> <extracomment>A context menu item.</extracomment> - <translation type="unfinished">ネットワーク活動を停止する</translation> + <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> + <translation type="unfinished">ネットワーク活動を有効化する</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">ヘッダーを事前同期中 (%1 %)…</translation> + <translation type="unfinished">事前同期ヘッダー (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -952,11 +972,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Received with label</source> - <translation type="unfinished">ラベル</translation> + <translation type="unfinished">対応するラベル</translation> </message> <message> <source>Received with address</source> - <translation type="unfinished">アドレス</translation> + <translation type="unfinished">対応するアドレス</translation> </message> <message> <source>Date</source> @@ -964,7 +984,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Confirmations</source> - <translation type="unfinished">承認数</translation> + <translation type="unfinished">検証数</translation> </message> <message> <source>Confirmed</source> @@ -988,7 +1008,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Copy transaction &ID and output index</source> - <translation type="unfinished">取引IDとアウトプットのインデックスをコピー(&I)</translation> + <translation type="unfinished">取引IDとアウトプットのインデックスをコピー</translation> </message> <message> <source>L&ock unspent</source> @@ -1000,7 +1020,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Copy quantity</source> - <translation type="unfinished">金額をコピー</translation> + <translation type="unfinished">選択数をコピー</translation> </message> <message> <source>Copy fee</source> @@ -1032,11 +1052,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>change from %1 (%2)</source> - <translation type="unfinished">%1 (%2) からのお釣り</translation> + <translation type="unfinished">%1 (%2) からのおつり</translation> </message> <message> <source>(change)</source> - <translation type="unfinished">(お釣り)</translation> + <translation type="unfinished">(おつり)</translation> </message> </context> <context> @@ -1057,7 +1077,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Create wallet warning</source> - <translation type="unfinished">ウォレット作成の警告</translation> + <translation type="unfinished">ウォレットを作成 - 警告</translation> </message> <message> <source>Can't list signers</source> @@ -1105,7 +1125,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Migrate Wallet</source> - <translation type="unfinished">ウォレットを移行する</translation> + <translation type="unfinished">ウォレットの移行</translation> </message> <message> <source>Migrating Wallet <b>%1</b>…</source> @@ -1143,10 +1163,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1594,6 +1610,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> @@ -2331,10 +2351,6 @@ BIP70には広範なセキュリティー上の問題があるので、ウォレ <translation type="unfinished">トランスポート</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">BIP324 のセッション ID の16進文字列 (存在する場合) 。</translation> - </message> - <message> <source>Session ID</source> <translation type="unfinished">セッション ID</translation> </message> @@ -2441,6 +2457,10 @@ BIP70には広範なセキュリティー上の問題があるので、ウォレ <translation type="unfinished">方向/タイプ</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">BIP324 のセッション ID の16進文字列</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, or CJDNS.</translation> </message> @@ -2633,10 +2653,18 @@ BIP70には広範なセキュリティー上の問題があるので、ウォレ <translation type="unfinished">ネットワーク活動が停止しました</translation> </message> <message> + <source>None</source> + <translation type="unfinished">なし</translation> + </message> + <message> <source>Executing command without any wallet</source> <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> @@ -2885,7 +2913,7 @@ For more information on using this console, type %6. </message> <message> <source>(no label)</source> - <translation type="unfinished">(ラベルなし)</translation> + <translation type="unfinished">(ラベル無し)</translation> </message> <message> <source>(no message)</source> @@ -3184,7 +3212,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <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> + <translation type="unfinished">%1kvB</translation> </message> <message> <source>Not signalling Replace-By-Fee, BIP-125.</source> @@ -3244,10 +3272,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>A fee higher than %1 is considered an absurdly high fee.</source> <translation type="unfinished">%1 よりも高い手数料は、法外に高い手数料と判定されます。</translation> </message> - <message> - <source>%1/kvB</source> - <translation type="unfinished">%1 /kvB</translation> - </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> @@ -3272,7 +3296,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>(no label)</source> - <translation type="unfinished">(ラベルなし)</translation> + <translation type="unfinished">(ラベル無し)</translation> </message> </context> <context> @@ -3356,8 +3380,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">メッセージに署名(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">あなたが所有しているアドレスでメッセージや契約書に署名をすることで、それらのアドレスへ送られた Bitcoin を受け取ることができることを証明できます。フィッシング攻撃者があなたを騙して、あなたの身分情報に署名させようとしている可能性があるため、よくわからないものやランダムな文字列に対して署名しないでください。あなたが同意した、よく詳細の記された文言にのみ署名するようにしてください。</translation> + <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">あなたの所有しているレガシー(P2PKH)アドレスによりメッセージや合意書に署名をすることで、それらアドレスに対して送られたビットコインを受け取ることができることを証明できます。フィッシング攻撃により不正にあなたの識別情報を署名させられてしまうことを防ぐために、不明確なものやランダムなものに対して署名しないよう注意してください。あなたが同意した、よく詳細の記された文言にのみ署名するようにしてください。</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3444,8 +3468,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">アドレスが正しいか確かめてから、もう一度試してください。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">入力されたアドレスに紐づく鍵がありません。</translation> + <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">入力されたアドレスはレガシー (P2PKH) 鍵を指していません。 SegWit およびその他の非 P2PKH アドレス タイプのメッセージ署名は、%1のバージョンではサポートされていません。アドレスを確認して、もう一度お試しください。</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3748,7 +3772,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>(no label)</source> - <translation type="unfinished">(ラベルなし)</translation> + <translation type="unfinished">(ラベル無し)</translation> </message> <message> <source>Transaction status. Hover over this field to show number of confirmations.</source> @@ -4019,9 +4043,8 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBTがコピーされました</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">クリップボードにコピーしました</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">手数料引き上げのPSBTをクリップボードにコピーしました</translation> </message> <message> <source>Can't sign transaction.</source> @@ -4032,12 +4055,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">取引の作成に失敗しました</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">アドレスを表示できません</translation> + <source>Signer error</source> + <translation type="unfinished">サイナーエラー</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">デフォルトウォレット</translation> + <source>Can't display address</source> + <translation type="unfinished">アドレスを表示できません</translation> </message> </context> <context> @@ -4171,10 +4194,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">ウォレットファイルフォーマットが指定されていません。createfromdumpを使用するには、-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> - <translation type="unfinished">お使いのコンピューターの日付と時刻が正しいことを確認してください! PCの時計が正しくない場合 %s は正確に動作しません。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">%s が有用だと感じられた方はぜひプロジェクトへの貢献をお願いします。ソフトウェアのより詳細な情報については %s をご覧ください。</translation> </message> @@ -4283,10 +4302,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool は最低でも %d MB 必要です</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">致命的な内部エラーが発生しました。詳細はデバッグ用のログファイル debug.log を参照してください</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">-%s アドレス '%s' を解決できません</translation> </message> @@ -4335,6 +4350,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">未承認の UTXO は未承認の取引の巨大なクラスターに依存しているため、バンプ料金の計算に失敗しました。</translation> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">スナップショットのchainstateディレクトリ(%s)を削除できませんでした。再起動する前に手動で削除してください。 +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">無効な peers.dat ファイルの名前を変更できませんでした。移動または削除してから、もう一度お試しください。</translation> </message> @@ -4343,6 +4364,14 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">手数料推定に失敗しました。代替手数料が無効です。数ブロック待つか、%s オプションを有効にしてください。</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">ブロックファイルのディスクへのフラッシュに失敗しました。これはI/Oエラーの結果である可能性があります。</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">元へ戻すファイルのディスクへのフラッシュに失敗しました。これはI/Oエラーの結果である可能性があります。</translation> + </message> + <message> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">不適切なオプション: -dnsseed=1 が明示的に指定されましたが、-onlynet は IPv4/IPv6 への接続を禁止します</translation> </message> @@ -4351,6 +4380,14 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s=<amount> オプションに対する不正な金額: '%s' (取引の停滞防止のため、最小中継手数料の %s より大きい必要があります)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">最大トランザクションweightがインプットのないトランザクションweightよりも小さい</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">最大トランザクションweightが低すぎるため、お釣り用のアウトプットに対応できません</translation> + </message> + <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished">アウトバウンド接続がCJDNS (-onlynet=cjdns)に制限されていますが、-cjdnsreachableが設定されていません。</translation> </message> @@ -4367,6 +4404,14 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">アウトバウンド接続がi2p (-onlynet=i2p)に制限されていますが、-i2psamが設定されていません。</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">「%s」->「%s」への名称変更に失敗しました。バックグラウンドでchainstate leveldbディレクトリのクリーンアップができません。</translation> + </message> + <message> + <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">事前に選択されたインプットとウォレットの自動インプット選択の組み合わせがトランザクションの最大weightを超えました。より少ない金額を送信するか、ウォレットのUTXOを手動で統合してみてください</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">インプットのサイズが、最大ウェイトを超過しています。送金額を減らすか、ウォレットのUTXOを手動で集約してみてください。</translation> </message> @@ -4409,6 +4454,10 @@ Please try running the latest software version. </translation> </message> <message> + <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">コンピューターの日付と時間がネットワークと%d分以上ずれているようです。これはコンセンサスエラーにつながる可能性があります。コンピューターの時計を確認した後、ノードを再起動するとこのメッセージは表示されなくなります。再起動しない場合は、十分な数の新しいアウトバウンドピアに接続すると表示されなくなりますが、これには時間がかかる場合があります。`getpeerinfo` RPCおよび `getnetworkinfo` RPCメソッドの`timeoffset`フィールドを調べると詳細が得られます。</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4421,6 +4470,18 @@ Unable to restore backup of wallet.</source> ウォレットのバックアップを復元できません。</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebindは受信接続のみに使用できます("out"が渡されました)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">致命的な内部エラーが発生しました。詳細はデバッグ用のログファイル debug.log を参照してください:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">指定されたブロックハッシュ「%s」に対するassumeutxoデータが見つかりません。</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">ブロック検証が中断されました</translation> </message> @@ -4429,6 +4490,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">%s の設定は、 [%s] セクションに書かれた場合のみ %s ネットワークへ適用されます。</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">潜在的なハードウェア障害を示す破損ブロックが見つかりました。</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">破損したブロック データベースが見つかりました</translation> </message> @@ -4457,6 +4522,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">ダンプファイル %s が存在しません。</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</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 +4578,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,10 +4666,30 @@ 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 connect best block (%s).</source> + <translation type="unfinished">ベストブロック(%s)への接続に失敗しました。</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">ブロックの切断に失敗しました。</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">ポートのリッスンに失敗しました。必要であれば -listen=0 を指定してください。</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">ブロックの読み取りに失敗しました。</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">初期化中にウォレットの再スキャンに失敗しました</translation> </message> @@ -4605,6 +4702,26 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">データベースの検証に失敗しました</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">ブロックの書き込みに失敗しました。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">ブロックインデックスデータベースの書き込みに失敗しました。</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">コインデータベースへの書き込みに失敗しました。</translation> + </message> + <message> + <source>Failed to write undo data.</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> @@ -4697,6 +4814,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">ウォレットの読み込み中…</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">最大トランザクションweightは%dから%dの間でなければなりません。</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">金額不足</translation> </message> @@ -4725,6 +4846,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">事前選択されたインプット%sが解決できません</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">方向のみが設定されており、権限がありません: '%s'</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">剪定モードの設定値は負の値にはできません。</translation> </message> @@ -4769,6 +4894,18 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">セクション名 [%s] は認識されません。</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">サイナーがアドレスをエコーしませんでした</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">サイナーが予期しないアドレス%sをエコーしました</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">サイナーがエラーを返しました: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">取引の署名に失敗しました</translation> </message> @@ -4797,6 +4934,18 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">ネットワークスレッドの起動中…</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">フラッシュ中のシステムエラー: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">外部ブロックファイルのロード中のシステムエラー: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">ブロックをディスクに保存中にシステムエラー: %s</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">ソースコードは %s から入手できます。</translation> </message> @@ -4813,6 +4962,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">ウォレットは最小中継手数料を下回る金額は支払いません。</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">このアドレスにはScriptPubKeyManagerがありません</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">これは実験用のソフトウェアです。</translation> </message> @@ -4825,6 +4978,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> @@ -4849,10 +5006,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">取引が大きすぎます</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">-maxsigcachesize にメモリを割り当てることができません: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">このコンピュータの %s にバインドすることができません(%s エラーが返されました)</translation> </message> @@ -4913,6 +5066,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">不明な新ルールがアクティベートされました (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished"> -test=<option>で提供されたオプション「%s」が認識されません。</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished">未サポートのログレベル %s=%s。 正しい値は: %s。</translation> </message> @@ -4933,6 +5090,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_ka.ts b/src/qt/locale/bitcoin_ka.ts index e15938e277..157fcc3376 100644 --- a/src/qt/locale/bitcoin_ka.ts +++ b/src/qt/locale/bitcoin_ka.ts @@ -176,6 +176,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">შეიყვანეთ ძველი საიდუმლო ფრაზა და ახალი საიდუმლო ფრაზა საფულისთვის</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">გაგრძელება</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">გახსოვდეთ, რომ თქვენი საფულის დაშიფვრა ვერ უზრუნველყოფს სრულად დაიცვას თქვენი ბიტკოინების მოპარვა კომპიუტერში მავნე პროგრამებით.</translation> </message> @@ -368,7 +372,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">ნაგულისხმევი საფულე</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -433,6 +441,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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">მონეტების გაგზავნა Bitcoin-მისამართზე</translation> </message> @@ -642,10 +654,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -923,10 +931,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -2333,10 +2337,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">შეამოწმეთ მისამართი და სცადეთ ხელახლა.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">შეყვანილი მისამართი არ არის კავშირში გასაღებთან.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">საფულის განბლოკვა შეწყვეტილია.</translation> </message> @@ -2780,11 +2780,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Send Coins</source> <translation type="unfinished">მონეტების გაგზავნა</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">ნაგულისხმევი საფულე</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -2844,10 +2840,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">-maxmempool უნდა იყოს მინიმუმ %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">მოხდა ფატალური შიდა შეცდომა. გამართვის დეტალებისთვის იხილეთ debug.log</translation> - </message> - <message> <source>Corrupted block database detected</source> <translation type="unfinished">შენიშნულია ბლოკთა ბაზის დაზიანება</translation> </message> diff --git a/src/qt/locale/bitcoin_kk.ts b/src/qt/locale/bitcoin_kk.ts index d40c6e56a1..4346f22521 100644 --- a/src/qt/locale/bitcoin_kk.ts +++ b/src/qt/locale/bitcoin_kk.ts @@ -481,7 +481,7 @@ </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 артта</translation> + <translation type="unfinished">%1 қалмады</translation> </message> <message> <source>Catching up…</source> @@ -489,7 +489,7 @@ </message> <message> <source>Error</source> - <translation type="unfinished">Қате</translation> + <translation type="unfinished">қате</translation> </message> <message> <source>Warning</source> @@ -497,7 +497,7 @@ </message> <message> <source>Information</source> - <translation type="unfinished">Ақпарат</translation> + <translation type="unfinished">Информация</translation> </message> <message> <source>Up to date</source> diff --git a/src/qt/locale/bitcoin_kk@latin.ts b/src/qt/locale/bitcoin_kk@latin.ts index 981b8a191c..af3d2abe58 100644 --- a/src/qt/locale/bitcoin_kk@latin.ts +++ b/src/qt/locale/bitcoin_kk@latin.ts @@ -481,7 +481,7 @@ </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 артта</translation> + <translation type="unfinished">%1 қалмады</translation> </message> <message> <source>Catching up…</source> @@ -489,7 +489,7 @@ </message> <message> <source>Error</source> - <translation type="unfinished">Қате</translation> + <translation type="unfinished">қате</translation> </message> <message> <source>Warning</source> @@ -497,7 +497,7 @@ </message> <message> <source>Information</source> - <translation type="unfinished">Ақпарат</translation> + <translation type="unfinished">Информация</translation> </message> <message> <source>Up to date</source> diff --git a/src/qt/locale/bitcoin_km.ts b/src/qt/locale/bitcoin_km.ts index e62aee0aff..36d0852039 100644 --- a/src/qt/locale/bitcoin_km.ts +++ b/src/qt/locale/bitcoin_km.ts @@ -184,6 +184,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">វាយបញ្ចូលឃ្លាសម្ងាត់ចាស់ និងឃ្លាសសម្លាត់ថ្មី សម្រាប់កាបូបចល័តរបស់អ្នក។</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">បន្ត</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">សូមចងចាំថាការអ៊ិនគ្រីបកាបូបរបស់អ្នកមិនអាចការពារបានពេញលេញនូវ bitcoins របស់អ្នកពីការលួចដោយមេរោគដែលឆ្លងកុំព្យូទ័ររបស់អ្នក។</translation> </message> @@ -372,7 +376,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 kB</source> <translation type="unfinished"> %1 kB</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">កាបូបលំនាំដើម</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -400,6 +408,14 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -642,6 +658,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">កាបូបMigrate</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation type="unfinished">បង្ហាញសារជំនួយ%1ដើម្បីទទួលបានបញ្ជីជាមួយនឹងជម្រើសបន្ទាត់ពាក្យបញ្ជា Bitcoin ដែលអាចធ្វើទៅបាន</translation> + </message> + <message> + <source>&Mask values</source> + <translation type="unfinished">តម្លៃMask(&M)</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation type="unfinished">តម្លៃMaskនៅក្នុងថេបទិដ្ឋភាពទូទៅ</translation> + </message> + <message> <source>No wallets available</source> <translation type="unfinished">មិនមានកាបូបអេឡិចត្រូនិច</translation> </message> @@ -667,15 +695,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Window</source> - <translation type="unfinished">&វិនដូ</translation> + <translation type="unfinished">វិនដូ(&W)</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> + <translation type="unfinished">លាក់(&H)</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">S&របៀប</translation> + <translation type="unfinished">របៀប(&S)</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -706,6 +742,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">បើកសកម្មភាពបណ្តាញ</translation> </message> <message> + <source>Error: %1</source> + <translation type="unfinished">កំហុស៖%1</translation> + </message> + <message> <source>Warning: %1</source> <translation type="unfinished">ប្រុងប្រយ័ត្នៈ %1</translation> </message> @@ -888,6 +928,14 @@ Signing is only possible with addresses of the type 'legacy'.</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 satoshi(s)ច្រើនក្នុងការបញ្ជូលមួយ។</translation> </message> @@ -1900,6 +1948,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">សកម្មភាពបណ្តាញ ត្រូវបានដាក់អោយប្រើការលែងបាន។</translation> </message> <message> + <source>None</source> + <translation type="unfinished">មិន</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">ប្រត្តិបត្តិបញ្ជារដោយគ្មានកាបូបអេឡិចត្រូនិច។</translation> </message> @@ -1908,6 +1960,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Ctrl+T</translation> </message> <message> + <source>Executing command using "%1" wallet</source> + <translation type="unfinished">ប្រត្តិបត្តិបញ្ចារដោយប្រើ ៉%1 ៉ កាបូបអេឡិចត្រូនិច</translation> + </message> + <message> <source>Executing…</source> <extracomment>A console message indicating an entered command is currently being executed.</extracomment> <translation type="unfinished">កំពុងប្រតិបត្តិ…</translation> @@ -2027,7 +2083,11 @@ If you are receiving this error you should request the merchant provide a BIP21 <source>Could not unlock wallet.</source> <translation type="unfinished">មិនអាចបើកសោរ កាបូបអេឡិចត្រូនិចបាន។</translation> </message> - </context> + <message> + <source>Could not generate new %1 address</source> + <translation type="unfinished">មិនអាចបង្កើតអាសយដ្ឋាន%1ថ្មី</translation> + </message> +</context> <context> <name>ReceiveRequestDialog</name> <message> @@ -2078,7 +2138,11 @@ If you are receiving this error you should request the merchant provide a BIP21 <source>Payment information</source> <translation type="unfinished">ព័ត៏មានទូរទាត់ប្រាក់</translation> </message> - </context> + <message> + <source>Request payment to %1</source> + <translation type="unfinished">សំណើរសុំទូរទាត់ប្រាក់ដល់ %1</translation> + </message> +</context> <context> <name>RecentRequestsTableModel</name> <message> @@ -2091,7 +2155,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>(no label)</source> - <translation type="unfinished">(គ្មានស្លាក)</translation> + <translation type="unfinished">(គ្មានស្លាកសញ្ញា)</translation> </message> <message> <source>(no message)</source> @@ -2233,6 +2297,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">ចម្លងតម្លៃ</translation> </message> <message> + <source>Copy change</source> + <translation type="unfinished">ចម្លងការផ្លាស់ប្តូរ</translation> + </message> + <message> <source>Sign on device</source> <extracomment>"device" usually means a hardware wallet.</extracomment> <translation type="unfinished">ចុះហត្ថលេខាលើឧបករណ៍</translation> @@ -2247,6 +2315,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">កំណត់ទីតាំងscript អ្នកចុះហត្ថលេខាខាងក្រៅនៅក្នុងជម្រើស -> កាបូប</translation> </message> <message> + <source>%1 to %2</source> + <translation type="unfinished">%1 ទៅ %2</translation> + </message> + <message> <source>To review recipient list click "Show Details…"</source> <translation type="unfinished">ដើម្បីពិនិត្យមើលបញ្ជីអ្នកទទួលសូមចុច "បង្ហាញព័ត៌មានលម្អិត..."</translation> </message> @@ -2291,6 +2363,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">អ្នកអាចបង្កើនកម្រៃពេលក្រោយ( សញ្ញា ជំនួសដោយកម្រៃ BIP-125)។</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">សូមពិនិត្យសំណើរប្រត្តិបត្តិការរបស់អ្នកឡើងវិញ។ វានឹងបង្កើតប្រត្តិបត្តិការប៊ីតខញដែលបានចុះហត្ថលេខាដោយផ្នែក (PSBT) ដែលអ្នកអាចរក្សាទុក ឬថតចម្លង រួចហើយសូមចុះហត្ថលេខា។ ឧទាហរណ៏ កាបូបអេឡិចត្រូនិចដែលមិនមានភ្ជាប់អ៊ីនធឺណេត %1 ឬកាបូបដែលមានផ្នែករឹងដែលអាចធ្វើការជាមួយ PSBT។</translation> + </message> + <message> <source>Do you want to create this transaction?</source> <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment> <translation type="unfinished">តើអ្នកចង់បង្កើតប្រតិបត្តិការនេះទេ?</translation> @@ -2334,6 +2411,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">ចំនួនលើសសមតុល្យរបស់អ្នក។</translation> </message> <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation type="unfinished">ចំនួនសរុបលើសសមតុល្យរបស់អ្នកនៅពេលដែលកម្រៃប្រត្តិបត្តិការ%1ត្រូវបានបូកបញ្ចូល។</translation> + </message> + <message> <source>Duplicate address found: addresses should only be used once each.</source> <translation type="unfinished">អាសយដ្ឋានស្ទួនត្រូវបានរកឃើញៈ គ្រប់អាសយដ្ឋានគួរត្រូវបានប្រើតែម្តង</translation> </message> @@ -2341,6 +2422,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>Transaction creation failed!</source> <translation type="unfinished">បង្កើតប្រត្តិបត្តិការមិនជោគជ័យ!</translation> </message> + <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation type="unfinished">កម្រៃខ្ពស់ជាង %1 ចាត់ទុកថាតម្លៃមិនសមស្រប។</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> @@ -2350,7 +2435,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>(no label)</source> - <translation type="unfinished">(គ្មានស្លាក)</translation> + <translation type="unfinished">(គ្មានស្លាកសញ្ញា)</translation> </message> </context> <context> @@ -2545,6 +2630,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">បានបោះបង់ចោល</translation> </message> <message> + <source>%1/unconfirmed</source> + <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment> + <translation type="unfinished">%1 មិនទាន់បានបញ្ចាក់</translation> + </message> + <message> + <source>%1 confirmations</source> + <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment> + <translation type="unfinished">%1 ការបញ្ចាក់</translation> + </message> + <message> <source>Status</source> <translation type="unfinished">ស្ថានភាព</translation> </message> @@ -2637,6 +2732,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TransactionDescDialog</name> + <message> + <source>Details for %1</source> + <translation type="unfinished">លម្អិត %1</translation> + </message> +</context> +<context> <name>TransactionTableModel</name> <message> <source>Date</source> @@ -2659,6 +2761,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">បានបោះបង់</translation> </message> <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation type="unfinished">កំពុងបញ្ចាក់(%1 នៃ %2 សេចក្តីបញ្ចាក់ដែលបានណែនាំ)</translation> + </message> + <message> + <source>Confirmed (%1 confirmations)</source> + <translation type="unfinished">បានបញ្ចាក់(%1 ការបញ្ចាក់)</translation> + </message> + <message> <source>Conflicted</source> <translation type="unfinished">បានប្រឆាំងតទល់គ្នា</translation> </message> @@ -2692,7 +2802,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>(no label)</source> - <translation type="unfinished">(គ្មានស្លាក)</translation> + <translation type="unfinished">(គ្មានស្លាកសញ្ញា)</translation> </message> <message> <source>Transaction status. Hover over this field to show number of confirmations.</source> @@ -2815,10 +2925,18 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">ការនាំចេញបានបរាជ័យ</translation> </message> <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation type="unfinished">មានបញ្ហាមួយក្នុងការព្យាយាមរក្សាទុកប្រវត្តិប្រត្តិបត្តិការ %1។</translation> + </message> + <message> <source>Exporting Successful</source> <translation type="unfinished">កំពុងនាំចេញដោយជោគជ័យ</translation> </message> <message> + <source>The transaction history was successfully saved to %1.</source> + <translation type="unfinished">ប្រវត្តប្រត្តិបត្តិការបានទទួលជោគជ័យ និងបានរក្សាទុក %1។</translation> + </message> + <message> <source>Range:</source> <translation type="unfinished">លំដាប់ពីៈ</translation> </message> @@ -2910,10 +3028,18 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">ថតចម្លងទុកមិនទទួលបានជោគជ័យ</translation> </message> <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation type="unfinished">មានបញ្ហាក្នុងការព្យាយាម រក្សាទុកទិន្ន័យកាបូបអេឡិចត្រូនិច %1។</translation> + </message> + <message> <source>Backup Successful</source> <translation type="unfinished">ចំម្លងទុកដោយជោគជ័យ</translation> </message> <message> + <source>The wallet data was successfully saved to %1.</source> + <translation type="unfinished">ទិន្ន័យកាបូបអេឡិចត្រូនិច ត្រូវបានរក្សាទុកដោយជោគជ័យ %1។</translation> + </message> + <message> <source>Cancel</source> <translation type="unfinished">ចាកចេញ</translation> </message> diff --git a/src/qt/locale/bitcoin_ko.ts b/src/qt/locale/bitcoin_ko.ts index ebf24eb372..9649183026 100644 --- a/src/qt/locale/bitcoin_ko.ts +++ b/src/qt/locale/bitcoin_ko.ts @@ -184,6 +184,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">지갑의 이전 비밀번호와 새로운 비밀번호를 입력하세요.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">계속하기</translation> + </message> + <message> + <source>Back</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> @@ -421,6 +429,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 기가바이트</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">기본 지갑</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -730,10 +742,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -1088,10 +1096,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -2499,6 +2503,10 @@ BIP70의 광범위한 보안 결함으로 인해 모든 가맹점에서는 지 <translation type="unfinished">네트워크 활동이 정지되었습니다.</translation> </message> <message> + <source>None</source> + <translation type="unfinished">없음</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">지갑 없이 명령 실행</translation> </message> @@ -2520,8 +2528,7 @@ For more information on using this console, type %6. 3%3과 4%4을 사용하여 글꼴 크기 증가 또는 감소하세요 사용 가능한 명령의 개요를 보려면 5%5를 입력하십시오. 이 콘솔 사용에 대한 자세한 내용을 보려면 6%6을 입력하십시오. -7%7 경고: 사기꾼들은 사용자들에게 여기에 명령을 입력하라고 말하고 활발히 금품을 훔칩니다. 완전히 이해하지 않고 이 콘솔을 사용하지 마십시오. 8%8 -</translation> +7%7 경고: 사기꾼들은 사용자들에게 여기에 명령을 입력하라고 말하고 활발히 금품을 훔칩니다. 완전히 이해하지 않고 이 콘솔을 사용하지 마십시오. 8%8</translation> </message> <message> <source>Executing…</source> @@ -3178,10 +3185,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">메시지 서명(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">당신이 해당 주소로 비트코인을 받을 수 있다는 것을 증명하기 위해 메시지/합의문을 그 주소로 서명할 수 있습니다. 피싱 공격이 당신을 속일 수 있으므로 임의의 내용이나 모호한 내용에 서명하지 않도록 주의하세요. 당신이 동의하는 명확한 조항들에만 서명하세요.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">메세지를 서명할 비트코인 주소</translation> </message> @@ -3266,10 +3269,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">주소를 확인하고 다시 시도하십시오.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">입력한 주소는 지갑내 키를 참조하지 않습니다.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">지갑 잠금 해제를 취소했습니다.</translation> </message> @@ -3828,11 +3827,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT 복사됨</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">클립보드로 복사됨</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">거래에 서명 할 수 없습니다.</translation> </message> @@ -3844,10 +3838,6 @@ Go to File > Open Wallet to load a wallet. <source>Can't display address</source> <translation type="unfinished">주소를 표시할 수 없습니다.</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">기본 지갑</translation> - </message> </context> <context> <name>WalletView</name> @@ -3960,10 +3950,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">shshhdchb bdfjj fb rciivfjb doffbfbdjdj</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">컴퓨터의 날짜와 시간이 올바른지 확인하십시오! 시간이 잘못되면 %s은 제대로 동작하지 않습니다.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">%s가 유용하다고 생각한다면 프로젝트에 공헌해주세요. 이 소프트웨어에 대한 보다 자세한 정보는 %s를 방문해 주십시오.</translation> </message> @@ -4036,10 +4022,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool은 최소한 %d MB 이어야 합니다</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">치명적 내부 오류 발생. 상세한 내용을 debug.log 에서 확인하십시오</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">%s 주소를 확인할 수 없습니다: '%s'</translation> </message> @@ -4085,13 +4067,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Dump file %s does not exist.</source> - <translation type="unfinished">파일 버리기 1%s 존재 안함 -</translation> + <translation type="unfinished">파일 버리기 %s 존재 안함</translation> </message> <message> <source>Error creating %s</source> - <translation type="unfinished">만들기 오류 1%s -</translation> + <translation type="unfinished">만들기 오류 %s</translation> </message> <message> <source>Error initializing block database</source> @@ -4162,6 +4142,14 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">데이터베이스를 검증 실패</translation> </message> <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation type="unfinished">수수료율 (%s)이 최소 수수료율 설정 (%s)보다 낮습니다.</translation> + </message> + <message> + <source>Ignoring duplicate -wallet %s.</source> + <translation type="unfinished">중복 -지갑 %s를 무시합니다.</translation> + </message> + <message> <source>Importing…</source> <translation type="unfinished">불러오는 중...</translation> </message> @@ -4258,6 +4246,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">에스큐엘라이트 데이터베이스 : 데이터베이스를 확인하는 실행문 준비에 실패하였습니다 : %s.</translation> </message> <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation type="unfinished">에스큐엘라이트 데이터베이스 : 데이터베이스 읽기를 실패하였습니다: %s</translation> + </message> + <message> <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> <translation type="unfinished">에스큐엘라이트 데이터베이스 : 예상 못한 어플리케이션 아이디. 예정: %u, 받음: %u</translation> </message> @@ -4362,6 +4354,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">알 수 없는 -blockfileterindex 값 %s.</translation> </message> <message> + <source>Unknown address type '%s'</source> + <translation type="unfinished">알 수 없는 주소 형식 '%s'</translation> + </message> + <message> <source>Unknown change type '%s'</source> <translation type="unfinished">알 수 없는 변경 형식 '%s'</translation> </message> diff --git a/src/qt/locale/bitcoin_ku.ts b/src/qt/locale/bitcoin_ku.ts index f8738fd9dc..9dc3995fa0 100644 --- a/src/qt/locale/bitcoin_ku.ts +++ b/src/qt/locale/bitcoin_ku.ts @@ -236,11 +236,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&File</source> - <translation type="unfinished">&فایل</translation> + <translation type="unfinished">&پەرگە</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">&ڕێکخستنەکان</translation> + <translation type="unfinished">&سازکارییەکان</translation> </message> <message> <source>&Help</source> @@ -263,7 +263,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Information</source> - <translation type="unfinished">زانیاری</translation> + <translation type="unfinished">Agahî</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -612,7 +612,9 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(no label)</source> - <translation type="unfinished">(etîket tune)</translation> + <translation type="unfinished">(بێ ناونیشان) + +</translation> </message> </context> <context> @@ -660,7 +662,9 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(no label)</source> - <translation type="unfinished">(etîket tune)</translation> + <translation type="unfinished">(بێ ناونیشان) + +</translation> </message> </context> <context> @@ -755,7 +759,9 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(no label)</source> - <translation type="unfinished">(etîket tune)</translation> + <translation type="unfinished">(بێ ناونیشان) + +</translation> </message> </context> <context> @@ -814,10 +820,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>bitcoin-core</name> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">تکایە بپشکنە کە بەروار و کاتی کۆمپیوتەرەکەت ڕاستە! ئەگەر کاژێرەکەت هەڵە بوو، %s بە دروستی کار ناکات.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">تکایە بەشداری بکە ئەگەر %s بەسوودت دۆزیەوە. سەردانی %s بکە بۆ زانیاری زیاتر دەربارەی نەرمواڵەکە.</translation> </message> diff --git a/src/qt/locale/bitcoin_ku_IQ.ts b/src/qt/locale/bitcoin_ku_IQ.ts index adbdec36fb..3bec55511b 100644 --- a/src/qt/locale/bitcoin_ku_IQ.ts +++ b/src/qt/locale/bitcoin_ku_IQ.ts @@ -236,11 +236,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&File</source> - <translation type="unfinished">&فایل</translation> + <translation type="unfinished">&پەرگە</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">&ڕێکخستنەکان</translation> + <translation type="unfinished">&سازکارییەکان</translation> </message> <message> <source>&Help</source> @@ -612,7 +612,9 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(no label)</source> - <translation type="unfinished">(ناونیشان نییە)</translation> + <translation type="unfinished">(بێ ناونیشان) + +</translation> </message> </context> <context> @@ -660,7 +662,9 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(no label)</source> - <translation type="unfinished">(ناونیشان نییە)</translation> + <translation type="unfinished">(بێ ناونیشان) + +</translation> </message> </context> <context> @@ -755,7 +759,9 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(no label)</source> - <translation type="unfinished">(ناونیشان نییە)</translation> + <translation type="unfinished">(بێ ناونیشان) + +</translation> </message> </context> <context> @@ -814,10 +820,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>bitcoin-core</name> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">تکایە بپشکنە کە بەروار و کاتی کۆمپیوتەرەکەت ڕاستە! ئەگەر کاژێرەکەت هەڵە بوو، %s بە دروستی کار ناکات.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">تکایە بەشداری بکە ئەگەر %s بەسوودت دۆزیەوە. سەردانی %s بکە بۆ زانیاری زیاتر دەربارەی نەرمواڵەکە.</translation> </message> diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index eaf3c35f2d..8a564fcd2a 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -1,230 +1,50 @@ <TS version="2.1" language="la"> <context> - <name>AddressBookPage</name> - <message> - <source>Create a new address</source> - <translation type="unfinished">Crea novam inscriptionem</translation> - </message> - <message> - <source>&New</source> - <translation type="unfinished">&Novus</translation> - </message> - <message> - <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Copia inscriptionem iam selectam in latibulum systematis</translation> - </message> - <message> - <source>&Copy</source> - <translation type="unfinished">&Transcribe</translation> - </message> - <message> - <source>C&lose</source> - <translation type="unfinished">C&laude</translation> - </message> - <message> - <source>Delete the currently selected address from the list</source> - <translation type="unfinished">Dele active selectam inscriptionem ex enumeratione</translation> - </message> - <message> - <source>Enter address or label to search</source> - <translation type="unfinished">Insere inscriptionem vel titulum ut quaeras</translation> - </message> - <message> - <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exporta data in hac tabella in plicam</translation> - </message> - <message> - <source>&Export</source> - <translation type="unfinished">&Exporta</translation> - </message> - <message> - <source>&Delete</source> - <translation type="unfinished">&Dele</translation> - </message> - <message> - <source>Choose the address to send coins to</source> - <translation type="unfinished">Elige quam peram mittere pecuniam</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">Hae sunt inscriptiones mittendi pensitationes. Semper inspice quantitatem et inscriptionem accipiendi antequam nummos mittis.</translation> - </message> - <message> - <source>&Copy Address</source> - <translation type="unfinished">&Copia Inscriptionem</translation> - </message> - <message> - <source>Copy &Label</source> - <translation type="unfinished">Copia &Titulum</translation> - </message> - <message> - <source>&Edit</source> - <translation type="unfinished">&Muta</translation> - </message> - <message> - <source>Export Address List</source> - <translation type="unfinished">Exporta Index Inscriptionum</translation> - </message> - </context> -<context> - <name>AddressTableModel</name> - <message> - <source>Label</source> - <translation type="unfinished">Titulus</translation> - </message> - <message> - <source>Address</source> - <translation type="unfinished">Inscriptio</translation> - </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(nullus titulus)</translation> - </message> -</context> -<context> - <name>AskPassphraseDialog</name> - <message> - <source>Passphrase Dialog</source> - <translation type="unfinished">Dialogus Tesserae</translation> - </message> - <message> - <source>Enter passphrase</source> - <translation type="unfinished">Insere tesseram</translation> - </message> - <message> - <source>New passphrase</source> - <translation type="unfinished">Nova tessera</translation> - </message> - <message> - <source>Repeat new passphrase</source> - <translation type="unfinished">Itera novam tesseram</translation> - </message> - <message> - <source>Show passphrase</source> - <translation type="unfinished">Ostende tesseram</translation> - </message> - <message> - <source>Encrypt wallet</source> - <translation type="unfinished">Cifra cassidile</translation> - </message> - <message> - <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">Huic operationi necesse est tessera cassidili tuo ut cassidile reseret.</translation> - </message> - <message> - <source>Unlock wallet</source> - <translation type="unfinished">Resera cassidile</translation> - </message> - <message> - <source>Change passphrase</source> - <translation type="unfinished">Muta tesseram</translation> - </message> - <message> - <source>Confirm wallet encryption</source> - <translation type="unfinished">Confirma cifrationem cassidilis</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">Monitio: Si cassidile tuum cifras et tesseram amittis, tu <b>AMITTES OMNES TUOS NUMMOS BITOS</b>!</translation> - </message> - <message> - <source>Are you sure you wish to encrypt your wallet?</source> - <translation type="unfinished">Certusne es te velle tuum cassidile cifrare?</translation> - </message> - <message> - <source>Wallet encrypted</source> - <translation type="unfinished">Cassidile cifratum</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">GRAVE: Oportet ulla prioria conservata quae fecisti de plica tui cassidilis reponi a nove generata cifrata plica cassidilis. Propter securitatem, prioria conservata de plica non cifrata cassidilis inutilia fiet simul atque incipis uti novo cifrato cassidili.</translation> - </message> - <message> - <source>Wallet encryption failed</source> - <translation type="unfinished">Cassidile cifrare abortum est</translation> - </message> - <message> - <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">Cassidile cifrare abortum est propter internum errorem. Tuum cassidile cifratum non est.</translation> - </message> - <message> - <source>The supplied passphrases do not match.</source> - <translation type="unfinished">Tesserae datae non eaedem sunt.</translation> - </message> - <message> - <source>Wallet unlock failed</source> - <translation type="unfinished">Cassidile reserare abortum est.</translation> - </message> - <message> - <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">Tessera inserta pro cassidilis decifrando prava erat.</translation> - </message> - <message> - <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">Tessera cassidilis successa est in mutando.</translation> - </message> - <message> - <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished">Monitio: Litterae ut capitales seratae sunt!</translation> - </message> -</context> -<context> - <name>BanTableModel</name> - <message> - <source>Banned Until</source> - <translation type="unfinished">Interdictum usque ad</translation> - </message> -</context> -<context> <name>QObject</name> <message> - <source>unknown</source> - <translation type="unfinished">ignotum</translation> - </message> - <message> <source>Amount</source> <translation type="unfinished">Quantitas</translation> </message> <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 +145,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,38 +181,14 @@ <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> - <source>Sent transaction</source> - <translation type="unfinished">Transactio missa</translation> - </message> - <message> - <source>Incoming transaction</source> - <translation type="unfinished">Transactio incipiens</translation> - </message> - <message> - <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">Cassidile <b>cifratum</b> est et iam nunc <b>reseratum</b></translation> - </message> - <message> - <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">Cassidile <b>cifratum</b> est et iam nunc <b>seratum</b></translation> - </message> </context> <context> <name>CoinControlDialog</name> <message> - <source>Bytes:</source> - <translation type="unfinished">Octecti:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">Quantitas:</translation> - </message> - <message> <source>Amount</source> <translation type="unfinished">Quantitas</translation> </message> @@ -414,124 +210,40 @@ </message> </context> <context> - <name>CreateWalletDialog</name> - <message> - <source>Wallet</source> - <translation type="unfinished">Cassidile</translation> - </message> - </context> -<context> - <name>EditAddressDialog</name> - <message> - <source>Edit Address</source> - <translation type="unfinished">Muta Inscriptionem</translation> - </message> - <message> - <source>&Label</source> - <translation type="unfinished">&Titulus</translation> - </message> - <message> - <source>&Address</source> - <translation type="unfinished">&Inscriptio</translation> - </message> - <message> - <source>New sending address</source> - <translation type="unfinished">Nova inscriptio mittendi</translation> - </message> - <message> - <source>Edit receiving address</source> - <translation type="unfinished">Muta inscriptionem accipiendi</translation> - </message> - <message> - <source>Edit sending address</source> - <translation type="unfinished">Muta inscriptionem mittendi</translation> - </message> - <message> - <source>The entered address "%1" is not a valid Bitcoin address.</source> - <translation type="unfinished">Inscriptio inserta "%1" non valida inscriptio Bitcoin est.</translation> - </message> - <message> - <source>Could not unlock wallet.</source> - <translation type="unfinished">Non potuisse cassidile reserare</translation> - </message> - <message> - <source>New key generation failed.</source> - <translation type="unfinished">Generare novam clavem abortum est.</translation> - </message> -</context> -<context> <name>Intro</name> <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> <context> - <name>HelpMessageDialog</name> - <message> - <source>version</source> - <translation type="unfinished">versio</translation> - </message> - <message> - <source>Command-line options</source> - <translation type="unfinished">Optiones mandati initiantis</translation> - </message> -</context> -<context> - <name>ModalOverlay</name> - <message> - <source>Form</source> - <translation type="unfinished">Schema</translation> - </message> - <message> - <source>Last block time</source> - <translation type="unfinished">Hora postremi frusti</translation> - </message> - </context> -<context> - <name>OpenURIDialog</name> - <message> - <source>Paste address from clipboard</source> - <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">Glutina inscriptionem ex latibulo</translation> - </message> -</context> -<context> <name>OptionsDialog</name> <message> - <source>Options</source> - <translation type="unfinished">Optiones</translation> - </message> - <message> - <source>&Main</source> - <translation type="unfinished">&Princeps</translation> - </message> - <message> <source>Reset all client options to default.</source> <translation type="unfinished">Reconstitue omnes optiones clientis ad praedefinita.</translation> </message> @@ -673,207 +385,19 @@ </message> </context> <context> - <name>QRImageWidget</name> - <message> - <source>Resulting URI too long, try to reduce the text for label / message.</source> - <translation type="unfinished">Resultato URI nimis longo, conare minuere verba pro titulo / nuntio.</translation> - </message> - <message> - <source>Error encoding URI into QR Code.</source> - <translation type="unfinished">Error codificandi URI in codicem QR.</translation> - </message> - <message> - <source>Save QR Code</source> - <translation type="unfinished">Salva codicem QR</translation> - </message> - </context> -<context> - <name>RPCConsole</name> - <message> - <source>Client version</source> - <translation type="unfinished">Versio clientis</translation> - </message> - <message> - <source>&Information</source> - <translation type="unfinished">&Informatio</translation> - </message> - <message> - <source>Startup time</source> - <translation type="unfinished">Tempus initiandi</translation> - </message> - <message> - <source>Network</source> - <translation type="unfinished">Rete</translation> - </message> - <message> - <source>Number of connections</source> - <translation type="unfinished">Numerus conexionum</translation> - </message> - <message> - <source>Block chain</source> - <translation type="unfinished">Catena frustorum</translation> - </message> - <message> - <source>Last block time</source> - <translation type="unfinished">Hora postremi frusti</translation> - </message> - <message> - <source>&Open</source> - <translation type="unfinished">&Aperi</translation> - </message> - <message> - <source>&Console</source> - <translation type="unfinished">&Terminale</translation> - </message> - <message> - <source>Debug log file</source> - <translation type="unfinished">Debug catalogi plica</translation> - </message> - <message> - <source>Clear console</source> - <translation type="unfinished">Vacuefac terminale</translation> - </message> - <message> - <source>To</source> - <translation type="unfinished">Ad</translation> - </message> - <message> - <source>From</source> - <translation type="unfinished">Ab</translation> - </message> - </context> -<context> - <name>ReceiveCoinsDialog</name> - <message> - <source>&Amount:</source> - <translation type="unfinished">Quantitas:</translation> - </message> - <message> - <source>&Label:</source> - <translation type="unfinished">&Titulus:</translation> - </message> - <message> - <source>&Message:</source> - <translation type="unfinished">Nuntius:</translation> - </message> - <message> - <source>Could not unlock wallet.</source> - <translation type="unfinished">Non potuisse cassidile reserare</translation> - </message> - </context> -<context> - <name>ReceiveRequestDialog</name> - <message> - <source>Amount:</source> - <translation type="unfinished">Quantitas:</translation> - </message> - <message> - <source>Label:</source> - <translation type="unfinished">Titulus:</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">Nuntius:</translation> - </message> - <message> - <source>Copy &Address</source> - <translation type="unfinished">&Copia Inscriptionem</translation> - </message> - </context> -<context> <name>RecentRequestsTableModel</name> <message> - <source>Date</source> - <translation type="unfinished">Dies</translation> - </message> - <message> - <source>Label</source> - <translation type="unfinished">Titulus</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">Nuntius</translation> - </message> - <message> <source>(no label)</source> <translation type="unfinished">(nullus titulus)</translation> </message> </context> <context> <name>SendCoinsDialog</name> - <message> - <source>Send Coins</source> - <translation type="unfinished">Mitte Nummos</translation> - </message> - <message> - <source>Insufficient funds!</source> - <translation type="unfinished">Inopia nummorum</translation> - </message> - <message> - <source>Bytes:</source> - <translation type="unfinished">Octecti:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">Quantitas:</translation> - </message> - <message> - <source>Transaction Fee:</source> - <translation type="unfinished">Transactionis merces:</translation> - </message> - <message> - <source>Send to multiple recipients at once</source> - <translation type="unfinished">Mitte pluribus accipientibus simul</translation> - </message> - <message> - <source>Add &Recipient</source> - <translation type="unfinished">Adde &Accipientem</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">Vacuefac &Omnia</translation> - </message> - <message> - <source>Balance:</source> - <translation type="unfinished">Pendendum:</translation> - </message> - <message> - <source>Confirm the send action</source> - <translation type="unfinished">Confirma actionem mittendi</translation> - </message> - <message> - <source>S&end</source> - <translation type="unfinished">&Mitte</translation> - </message> - <message> - <source>Copy amount</source> - <translation type="unfinished">Copia quantitatem</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">Transactionis merces</translation> - </message> - <message> - <source>Confirm send coins</source> - <translation type="unfinished">Confirma mittendum nummorum</translation> - </message> - <message> - <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">Oportet quantitatem ad pensandum maiorem quam 0 esse.</translation> - </message> - <message> - <source>The amount exceeds your balance.</source> - <translation type="unfinished">Quantitas est ultra quod habes.</translation> - </message> - <message> - <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation type="unfinished">Quantitas est ultra quod habes cum merces transactionis %1 includitur.</translation> - </message> <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> @@ -882,388 +406,37 @@ </message> </context> <context> - <name>SendCoinsEntry</name> - <message> - <source>A&mount:</source> - <translation type="unfinished">&Quantitas:</translation> - </message> - <message> - <source>Pay &To:</source> - <translation type="unfinished">Pensa &Ad:</translation> - </message> - <message> - <source>&Label:</source> - <translation type="unfinished">&Titulus:</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">Glutina inscriptionem ex latibulo</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">Nuntius:</translation> - </message> - </context> -<context> - <name>SignVerifyMessageDialog</name> - <message> - <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">Signationes - Signa / Verifica nuntium</translation> - </message> - <message> - <source>&Sign Message</source> - <translation type="unfinished">&Signa Nuntium</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">Glutina inscriptionem ex latibulo</translation> - </message> - <message> - <source>Enter the message you want to sign here</source> - <translation type="unfinished">Insere hic nuntium quod vis signare</translation> - </message> - <message> - <source>Signature</source> - <translation type="unfinished">Signatio</translation> - </message> - <message> - <source>Copy the current signature to the system clipboard</source> - <translation type="unfinished">Copia signationem in latibulum systematis</translation> - </message> - <message> - <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">Signa nuntium ut demonstres hanc inscriptionem Bitcoin a te possessa esse</translation> - </message> - <message> - <source>Sign &Message</source> - <translation type="unfinished">Signa &Nuntium</translation> - </message> - <message> - <source>Reset all sign message fields</source> - <translation type="unfinished">Reconstitue omnes campos signandi nuntii</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">Vacuefac &Omnia</translation> - </message> - <message> - <source>&Verify Message</source> - <translation type="unfinished">&Verifica Nuntium</translation> - </message> - <message> - <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation type="unfinished">Verifica nuntium ut cures signatum esse cum specifica inscriptione Bitcoin</translation> - </message> - <message> - <source>Verify &Message</source> - <translation type="unfinished">Verifica &Nuntium</translation> - </message> - <message> - <source>Reset all verify message fields</source> - <translation type="unfinished">Reconstitue omnes campos verificandi nuntii</translation> - </message> - <message> - <source>Click "Sign Message" to generate signature</source> - <translation type="unfinished">Clicca "Signa Nuntium" ut signatio generetur</translation> - </message> - <message> - <source>The entered address is invalid.</source> - <translation type="unfinished">Inscriptio inserta non valida est.</translation> - </message> - <message> - <source>Please check the address and try again.</source> - <translation type="unfinished">Sodes inscriptionem proba et rursus conare.</translation> - </message> - <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Inserta inscriptio clavem non refert.</translation> - </message> - <message> - <source>Wallet unlock was cancelled.</source> - <translation type="unfinished">Cassidilis reserare cancellatum est.</translation> - </message> - <message> - <source>Private key for the entered address is not available.</source> - <translation type="unfinished">Clavis privata absens est pro inserta inscriptione.</translation> - </message> - <message> - <source>Message signing failed.</source> - <translation type="unfinished">Nuntium signare abortum est.</translation> - </message> - <message> - <source>Message signed.</source> - <translation type="unfinished">Nuntius signatus.</translation> - </message> - <message> - <source>The signature could not be decoded.</source> - <translation type="unfinished">Signatio decodificari non potuit.</translation> - </message> - <message> - <source>Please check the signature and try again.</source> - <translation type="unfinished">Sodes signationem proba et rursus conare.</translation> - </message> - <message> - <source>The signature did not match the message digest.</source> - <translation type="unfinished">Signatio non convenit digesto nuntii</translation> - </message> - <message> - <source>Message verification failed.</source> - <translation type="unfinished">Nuntium verificare abortum est.</translation> - </message> - <message> - <source>Message verified.</source> - <translation type="unfinished">Nuntius verificatus.</translation> - </message> -</context> -<context> <name>TransactionDesc</name> - <message> - <source>%1/unconfirmed</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment> - <translation type="unfinished">%1/non confirmata</translation> - </message> - <message> - <source>%1 confirmations</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment> - <translation type="unfinished">%1 confirmationes</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">Dies</translation> - </message> - <message> - <source>Source</source> - <translation type="unfinished">Fons</translation> - </message> - <message> - <source>Generated</source> - <translation type="unfinished">Generatum</translation> - </message> - <message> - <source>From</source> - <translation type="unfinished">Ab</translation> - </message> - <message> - <source>unknown</source> - <translation type="unfinished">ignotum</translation> - </message> - <message> - <source>To</source> - <translation type="unfinished">Ad</translation> - </message> - <message> - <source>own address</source> - <translation type="unfinished">inscriptio propria</translation> - </message> - <message> - <source>label</source> - <translation type="unfinished">titulus</translation> - </message> - <message> - <source>Credit</source> - <translation type="unfinished">Creditum</translation> - </message> <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> - <source>not accepted</source> - <translation type="unfinished">non acceptum</translation> - </message> - <message> - <source>Debit</source> - <translation type="unfinished">Debitum</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">Transactionis merces</translation> - </message> - <message> - <source>Net amount</source> - <translation type="unfinished">Cuncta quantitas</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">Nuntius</translation> - </message> - <message> - <source>Comment</source> - <translation type="unfinished">Annotatio</translation> - </message> - <message> - <source>Transaction ID</source> - <translation type="unfinished">ID transactionis</translation> - </message> - <message> - <source>Debug information</source> - <translation type="unfinished">Informatio de debug</translation> - </message> - <message> - <source>Transaction</source> - <translation type="unfinished">Transactio</translation> - </message> - <message> - <source>Inputs</source> - <translation type="unfinished">Lectenda</translation> - </message> - <message> <source>Amount</source> <translation type="unfinished">Quantitas</translation> </message> - <message> - <source>true</source> - <translation type="unfinished">verum</translation> - </message> - <message> - <source>false</source> - <translation type="unfinished">falsum</translation> - </message> -</context> -<context> - <name>TransactionDescDialog</name> - <message> - <source>This pane shows a detailed description of the transaction</source> - <translation type="unfinished">Haec tabula monstrat descriptionem verbosam transactionis</translation> - </message> </context> <context> <name>TransactionTableModel</name> <message> - <source>Date</source> - <translation type="unfinished">Dies</translation> - </message> - <message> <source>Type</source> <translation type="unfinished">Typus</translation> </message> <message> - <source>Label</source> - <translation type="unfinished">Titulus</translation> - </message> - <message> - <source>Confirmed (%1 confirmations)</source> - <translation type="unfinished">Confirmatum (%1 confirmationes)</translation> - </message> - <message> - <source>Generated but not accepted</source> - <translation type="unfinished">Generatum sed non acceptum</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">Acceptum cum</translation> - </message> - <message> - <source>Received from</source> - <translation type="unfinished">Acceptum ab</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">Missum ad</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">Fossa</translation> - </message> - <message> <source>(no label)</source> <translation type="unfinished">(nullus titulus)</translation> </message> - <message> - <source>Transaction status. Hover over this field to show number of confirmations.</source> - <translation type="unfinished">Status transactionis. Supervola cum mure ut monstretur numerus confirmationum.</translation> - </message> - <message> - <source>Date and time that the transaction was received.</source> - <translation type="unfinished">Dies et tempus quando transactio accepta est.</translation> - </message> - <message> - <source>Type of transaction.</source> - <translation type="unfinished">Typus transactionis.</translation> - </message> - <message> - <source>Amount removed from or added to balance.</source> - <translation type="unfinished">Quantitas remota ex pendendo aut addita ei.</translation> - </message> -</context> + </context> <context> <name>TransactionView</name> <message> - <source>All</source> - <translation type="unfinished">Omne</translation> - </message> - <message> - <source>Today</source> - <translation type="unfinished">Hodie</translation> - </message> - <message> - <source>This week</source> - <translation type="unfinished">Hac hebdomade</translation> - </message> - <message> - <source>This month</source> - <translation type="unfinished">Hoc mense</translation> - </message> - <message> - <source>Last month</source> - <translation type="unfinished">Postremo mense</translation> - </message> - <message> - <source>This year</source> - <translation type="unfinished">Hoc anno</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">Acceptum cum</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">Missum ad</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">Fossa</translation> - </message> - <message> - <source>Other</source> - <translation type="unfinished">Alia</translation> - </message> - <message> - <source>Min amount</source> - <translation type="unfinished">Quantitas minima</translation> - </message> - <message> - <source>Confirmed</source> - <translation type="unfinished">Confirmatum</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">Dies</translation> - </message> - <message> <source>Type</source> <translation type="unfinished">Typus</translation> </message> - <message> - <source>Label</source> - <translation type="unfinished">Titulus</translation> - </message> - <message> - <source>Address</source> - <translation type="unfinished">Inscriptio</translation> - </message> - <message> - <source>Range:</source> - <translation type="unfinished">Intervallum:</translation> - </message> - <message> - <source>to</source> - <translation type="unfinished">ad</translation> - </message> -</context> + </context> <context> <name>WalletFrame</name> <message> @@ -1271,97 +444,4 @@ <translation type="unfinished">Creare novum cassidilium</translation> </message> </context> -<context> - <name>WalletModel</name> - <message> - <source>Send Coins</source> - <translation type="unfinished">Mitte Nummos</translation> - </message> - </context> -<context> - <name>WalletView</name> - <message> - <source>&Export</source> - <translation type="unfinished">&Exporta</translation> - </message> - <message> - <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exporta data in hac tabella in plicam</translation> - </message> - <message> - <source>Backup Wallet</source> - <translation type="unfinished">Conserva cassidile</translation> - </message> - <message> - <source>Backup Failed</source> - <translation type="unfinished">Conservare abortum est.</translation> - </message> - <message> - <source>Backup Successful</source> - <translation type="unfinished">Successum in conservando</translation> - </message> - </context> -<context> - <name>bitcoin-core</name> - <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">Hoc est prae-dimittum experimentala aedes - utere eo periculo tuo proprio - nolite utere fodendo vel applicationibus mercatoriis</translation> - </message> - <message> - <source>Corrupted block database detected</source> - <translation type="unfinished">Corruptum databasum frustorum invenitur</translation> - </message> - <message> - <source>Do you want to rebuild the block database now?</source> - <translation type="unfinished">Visne reficere databasum frustorum iam?</translation> - </message> - <message> - <source>Done loading</source> - <translation type="unfinished">Completo lengendi</translation> - </message> - <message> - <source>Error initializing block database</source> - <translation type="unfinished">Error initiando databasem frustorum</translation> - </message> - <message> - <source>Error initializing wallet database environment %s!</source> - <translation type="unfinished">Error initiando systematem databasi cassidilis %s!</translation> - </message> - <message> - <source>Error loading block database</source> - <translation type="unfinished">Error legendo frustorum databasem</translation> - </message> - <message> - <source>Error opening block database</source> - <translation type="unfinished">Error aperiendo databasum frustorum</translation> - </message> - <message> - <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation type="unfinished">Non potuisse auscultare in ulla porta. Utere -listen=0 si hoc vis.</translation> - </message> - <message> - <source>Insufficient funds</source> - <translation type="unfinished">Inopia nummorum</translation> - </message> - <message> - <source>Not enough file descriptors available.</source> - <translation type="unfinished">Inopia descriptorum plicarum.</translation> - </message> - <message> - <source>Signing transaction failed</source> - <translation type="unfinished">Signandum transactionis abortum est</translation> - </message> - <message> - <source>Transaction amount too small</source> - <translation type="unfinished">Magnitudo transactionis nimis parva</translation> - </message> - <message> - <source>Transaction too large</source> - <translation type="unfinished">Transactio nimis magna</translation> - </message> - <message> - <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">Ignotum rete specificatum in -onlynet: '%s'</translation> - </message> - </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 0df3a165aa..d589420a97 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -94,6 +94,14 @@ 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>Sending addresses - %1</source> + <translation type="unfinished">Siunčiami adresai -%1</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> @@ -335,7 +343,11 @@ Pasirašymas galimas tik su 'legacy' tipo adresais.</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">numatyta piniginė</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -548,10 +560,6 @@ Pasirašymas galimas tik su 'legacy' tipo adresais.</translation> <translation type="unfinished">Rodyti %1 pagalbos žinutę su Bitcoin pasirinkimo komandomis</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">numatyta piniginė</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Piniginių nėra</translation> </message> @@ -822,10 +830,6 @@ Pasirašymas galimas tik su 'legacy' tipo adresais.</translation> <translation type="unfinished">Piniginės atidarymo įspėjimas</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">numatyta piniginė</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Atidaryti Piniginę</translation> @@ -1793,6 +1797,10 @@ Pasirašymas galimas tik su 'legacy' tipo adresais.</translation> <translation type="unfinished">Tinklo veikla išjungta</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Nė vienas</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Vykdyti komandą be jokios piniginės</translation> </message> @@ -2355,10 +2363,6 @@ Pasirašymas galimas tik su 'legacy' tipo adresais.</translation> <translation type="unfinished">Patikrinkite adresą ir bandykite dar kartą.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Įvestas adresas nėra susijęs su raktu.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Piniginės atrakinimas buvo atšauktas.</translation> </message> @@ -2802,11 +2806,7 @@ Pasirašymas galimas tik su 'legacy' tipo adresais.</translation> <source>Could not commit transaction</source> <translation type="unfinished">Nepavyko įvykdyti sandorio</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">numatyta piniginė</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_lv.ts b/src/qt/locale/bitcoin_lv.ts index 6cea8ba1aa..467811a0e3 100644 --- a/src/qt/locale/bitcoin_lv.ts +++ b/src/qt/locale/bitcoin_lv.ts @@ -287,6 +287,10 @@ <translation type="unfinished">&Par %1</translation> </message> <message> + <source>Show information about %1</source> + <translation type="unfinished">Rādīt informāciju par %1</translation> + </message> + <message> <source>About &Qt</source> <translation type="unfinished">Par &Qt</translation> </message> diff --git a/src/qt/locale/bitcoin_mi.ts b/src/qt/locale/bitcoin_mi.ts index 8dc535cd68..92ac490e8e 100644 --- a/src/qt/locale/bitcoin_mi.ts +++ b/src/qt/locale/bitcoin_mi.ts @@ -244,7 +244,7 @@ Ko te whakakī i ēnei whakaaronga e taea ana anake ki ngā whakararuraru o te m </message> <message> <source>Runaway exception</source> - <translation type="unfinished"><text_to_translate>Tūkino whakawhiti</text_to_translate></translation> + <translation type="unfinished">Tūkino whakawhiti</translation> </message> <message> <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> @@ -632,10 +632,6 @@ Ko te whakakī i ēnei whakaaronga e taea ana anake ki ngā whakararuraru o te m <translation type="unfinished">He whakawhitiwhitinga nui rawa te whakapau kaha</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Kāore e taea te whakararuraru i te mahere mō te -maxsigcachesize: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Kāore e taea te whakakōtuitui ki %s i tēnei rorohiko (kua whakahoki te whakakōtuitui i te hapa %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_mk.ts b/src/qt/locale/bitcoin_mk.ts index 9fd41c2646..805cd3bfd2 100644 --- a/src/qt/locale/bitcoin_mk.ts +++ b/src/qt/locale/bitcoin_mk.ts @@ -365,6 +365,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 ГБ</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">Паричник по подразбирање</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -463,7 +467,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">Шифрирање на личните клучеви што припаѓаат на вашиот паричник</translation> + <translation type="unfinished">Криптирај ги приватните клучеви кои припаѓаат на твојот паричник</translation> </message> <message> <source>&Backup Wallet…</source> @@ -515,7 +519,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Settings</source> - <translation type="unfinished">&Поставки</translation> + <translation type="unfinished">&Подесувања</translation> </message> <message> <source>&Help</source> @@ -571,7 +575,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 зад</translation> + <translation type="unfinished">%1 позади</translation> </message> <message> <source>Catching up…</source> @@ -591,7 +595,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Warning</source> - <translation type="unfinished">Внимание</translation> + <translation type="unfinished">Предупредување</translation> </message> <message> <source>Information</source> @@ -635,7 +639,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Отвори го паричникот</translation> + <translation type="unfinished">Отвори паричник</translation> </message> <message> <source>Open a wallet</source> @@ -672,10 +676,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -894,10 +894,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>OpenWalletActivity</name> <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> @@ -1343,11 +1339,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Send Coins</source> <translation type="unfinished">Испраќање</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">Паричник по подразбирање</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_ml.ts b/src/qt/locale/bitcoin_ml.ts index 2bb0d996df..15cb5e8cfa 100644 --- a/src/qt/locale/bitcoin_ml.ts +++ b/src/qt/locale/bitcoin_ml.ts @@ -89,6 +89,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">കോമയാൽ വേർതിരിച്ച ഫയൽ (* .csv)</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> @@ -265,6 +273,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> @@ -328,7 +346,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">സ്ഥിരം ആയ വാലറ്റ്</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -380,8 +402,12 @@ 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> + <translation type="unfinished">വാലറ്റ്:</translation> </message> <message> <source>Network activity disabled.</source> @@ -417,18 +443,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 +499,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 +590,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> @@ -548,14 +611,15 @@ Signing is only possible with addresses of the type 'legacy'.</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>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 +654,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> @@ -796,10 +865,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>OpenWalletActivity</name> <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> @@ -1416,13 +1481,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> </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> diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts index 222018e036..ac0b17d952 100644 --- a/src/qt/locale/bitcoin_mn.ts +++ b/src/qt/locale/bitcoin_mn.ts @@ -243,6 +243,10 @@ <translation type="unfinished">Програмаас Гарах</translation> </message> <message> + <source>&About %1</source> + <translation type="unfinished">&Тухай %1</translation> + </message> + <message> <source>About &Qt</source> <translation type="unfinished">&Клиентийн тухай</translation> </message> diff --git a/src/qt/locale/bitcoin_ms.ts b/src/qt/locale/bitcoin_ms.ts index 9d20510264..7dfe4c38e7 100644 --- a/src/qt/locale/bitcoin_ms.ts +++ b/src/qt/locale/bitcoin_ms.ts @@ -36,8 +36,7 @@ </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished"> -Alihkan fail data ke dalam tab semasa</translation> + <translation type="unfinished">Alihkan fail data ke dalam tab semasa</translation> </message> <message> <source>&Export</source> @@ -81,6 +80,14 @@ 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>Sending addresses - %1</source> + <translation type="unfinished">Alamat Kirim - %1</translation> + </message> + <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">Alamat Penerima - %1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">Mengeksport Gagal</translation> </message> @@ -224,7 +231,12 @@ Alihkan fail data ke dalam tab semasa</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">dompet lalai +</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -369,11 +381,6 @@ Alihkan fail data ke dalam tab semasa</translation> <source>Close wallet</source> <translation type="unfinished">Tutup Wallet</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">dompet lalai -</translation> - </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> @@ -392,11 +399,6 @@ Alihkan fail data ke dalam tab semasa</translation> <context> <name>OpenWalletActivity</name> <message> - <source>default wallet</source> - <translation type="unfinished">dompet lalai -</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Buka Wallet</translation> @@ -544,14 +546,6 @@ Alihkan fail data ke dalam tab semasa</translation> </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">dompet lalai -</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> @@ -559,8 +553,7 @@ Alihkan fail data ke dalam tab semasa</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished"> -Alihkan fail data ke dalam tab semasa</translation> + <translation type="unfinished">Alihkan fail data ke dalam tab semasa</translation> </message> </context> <context> diff --git a/src/qt/locale/bitcoin_mt.ts b/src/qt/locale/bitcoin_mt.ts index e26087fe80..45e55cab45 100644 --- a/src/qt/locale/bitcoin_mt.ts +++ b/src/qt/locale/bitcoin_mt.ts @@ -340,7 +340,11 @@ L-iffirmar huwa possibbli biss b'indirizzi tat-tip 'legacy'.</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">kartiera default</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -640,10 +644,6 @@ L-iffirmar huwa possibbli biss b'indirizzi tat-tip 'legacy'.</translation> <translation type="unfinished">Maskra l-valuri fit-tab Ħarsa ġenerali</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">kartiera default</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Ebda kartieri disponibbli</translation> </message> @@ -839,10 +839,6 @@ L-iffirmar huwa possibbli biss b'indirizzi tat-tip 'legacy'.</translation> <context> <name>OpenWalletActivity</name> <message> - <source>default wallet</source> - <translation type="unfinished">kartiera default</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Iftaħ Kartiera</translation> @@ -1057,13 +1053,6 @@ L-iffirmar huwa possibbli biss b'indirizzi tat-tip 'legacy'.</translation> </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">kartiera default</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> 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_nb.ts b/src/qt/locale/bitcoin_nb.ts index 015496d587..06b99f7d5b 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -175,6 +175,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Skriv inn den gamle passordfrasen og den nye passordfrasen for lommeboken.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Fortsett</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">Husk at å kryptere lommeboken ikke vil beskytte dine bitcoins fullstendig fra å bli stjålet av skadevare som infiserer datamaskinen din.</translation> </message> @@ -382,7 +386,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n år</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">standard lommebok</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -434,6 +442,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Lag en ny lommebok</translation> </message> <message> + <source>&Minimize</source> + <translation type="unfinished">&Minimer</translation> + </message> + <message> <source>Wallet:</source> <translation type="unfinished">Lommebok:</translation> </message> @@ -456,7 +468,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Endre passordfrasen for kryptering av lommeboken</translation> + <translation type="unfinished">Endre passordsetningen for kryptering av lommeboken</translation> </message> <message> <source>&Send</source> @@ -680,10 +692,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Masker verdiene i oversiktstabben</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standard lommebok</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Ingen lommebøker tilgjengelig</translation> </message> @@ -1005,10 +1013,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Advasel om åpen lommebok.</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standard lommebok</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Åpne Lommebok</translation> @@ -1981,6 +1985,14 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k <translation type="unfinished">Datamappe</translation> </message> <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation type="unfinished">For å spesifisere en ikke-standardplassering av datakatalogen, bruk alternativet '%1'.</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation type="unfinished">For å spesifisere en ikke-standardplassering for blokkeringsmappen bruker du alternativet '%1'.</translation> + </message> + <message> <source>Startup time</source> <translation type="unfinished">Oppstartstidspunkt</translation> </message> @@ -2282,6 +2294,10 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k <translation type="unfinished">Nettverksaktivitet avskrudd</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ingen</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Utfør kommando uten noen lommebok</translation> </message> @@ -2684,6 +2700,14 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k <translation type="unfinished">Cr & eate Usignert</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">Oppretter en delvis signert Bitcoin-transaksjon (PSBT) for bruk med f.eks. en offline%1 lommebok eller en PSBT-kompatibel maskinvarelommebok.</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation type="unfinished">%1 til '%2'</translation> + </message> + <message> <source>%1 to %2</source> <translation type="unfinished">%1 til %2</translation> </message> @@ -2895,10 +2919,6 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k <translation type="unfinished">&Signer Melding</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">Du kan signere meldinger/avtaler med adresser for å bevise at du kan motta bitcoins sendt til dem. Vær forsiktig med å signere noe vagt eller tilfeldig, siden phishing-angrep kan prøve å lure deg til å signere din identitet over til dem. Bare signer fullt detaljerte utsagn som du er enig i.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin-adressen meldingen skal signeres med</translation> </message> @@ -2983,10 +3003,6 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k <translation type="unfinished">Sjekk adressen og prøv igjen.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Innskrevet adresse refererer ikke til noen nøkkel.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Opplåsning av lommebok ble avbrutt.</translation> </message> @@ -3520,10 +3536,6 @@ Gå til Fil > Åpne lommebok for å laste en lommebok. <source>Can't display address</source> <translation type="unfinished">Kan ikke vise adresse</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">standard lommebok</translation> - </message> </context> <context> <name>WalletView</name> @@ -3612,10 +3624,6 @@ Gå til Fil > Åpne lommebok for å laste en lommebok. <translation type="unfinished">Mer enn en onion adresse har blitt gitt. Bruker %s for den automatisk lagde Tor onion tjenesten.</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">Sjekk at din datamaskins dato og klokke er stilt rett! Hvis klokka er feil, vil ikke %s fungere ordentlig.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Bidra hvis du finner %s nyttig. Besøk %s for mer informasjon om programvaren.</translation> </message> @@ -3672,6 +3680,10 @@ Gå til Fil > Åpne lommebok for å laste en lommebok. <translation type="unfinished">Advarsel: Dumpfil lommebokformat "%s" stemmer ikke med format "%s" spesifisert i kommandolinje.</translation> </message> <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation type="unfinished">Advarsel: Private nøkler oppdaget i lommeboken {%s} med deaktiverte private nøkler</translation> + </message> + <message> <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> <translation type="unfinished">Advarsel: Vi ser ikke ut til å være i full overenstemmelse med våre likemenn! Du kan trenge å oppgradere, eller andre noder kan trenge å oppgradere.</translation> </message> @@ -3688,10 +3700,6 @@ Gå til Fil > Åpne lommebok for å laste en lommebok. <translation type="unfinished">-maxmempool må være minst %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">En fatal intern feil oppstod, se debug.log for detaljer.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Kunne ikke slå opp -%s-adresse: "%s"</translation> </message> @@ -3706,6 +3714,10 @@ Unable to restore backup of wallet.</source> Kunne ikke gjenopprette sikkerhetskopi av lommebok.</translation> </message> <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation type="unfinished">Konfigurasjonsinnstilling for%s brukes bare på%s nettverk når du er i delen [%s].</translation> + </message> + <message> <source>Copyright (C) %i-%i</source> <translation type="unfinished">Kopirett © %i-%i</translation> </message> @@ -3754,6 +3766,10 @@ Kunne ikke gjenopprette sikkerhetskopi av lommebok.</translation> <translation type="unfinished">Feil ved lasting av %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation type="unfinished">Feil ved lasting av%s: Private nøkler kan bare deaktiveres under opprettelsen</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation type="unfinished">Feil under innlasting av %s: Skadet lommebok</translation> </message> @@ -3858,6 +3874,10 @@ Kunne ikke gjenopprette sikkerhetskopi av lommebok.</translation> <translation type="unfinished">Ugyldig -mellomtjeneradresse eller vertsnavn: "%s"</translation> </message> <message> + <source>Invalid P2P permission: '%s'</source> + <translation type="unfinished">Ugyldig P2P-tillatelse: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished">Ugyldig beløp for -%s=<amount>: "%s"</translation> </message> @@ -4023,6 +4043,10 @@ Mangler løsningsdata for å estimere transaksjonsstørrelse</translation> <translation type="unfinished">Kan ikke binde til %s på denne datamaskinen. Sannsynligvis kjører %s allerede.</translation> </message> <message> + <source>Unable to create the PID file '%s': %s</source> + <translation type="unfinished">Kan ikke opprette PID-filen '%s':%s</translation> + </message> + <message> <source>Unable to generate initial keys</source> <translation type="unfinished">Klarte ikke lage første nøkkel</translation> </message> diff --git a/src/qt/locale/bitcoin_ne.ts b/src/qt/locale/bitcoin_ne.ts index c54fb40a37..268520f062 100644 --- a/src/qt/locale/bitcoin_ne.ts +++ b/src/qt/locale/bitcoin_ne.ts @@ -849,10 +849,6 @@ <context> <name>SignVerifyMessageDialog</name> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">आफ्नो ठेगानामा पठाइएको बिटकोइन प्राप्त गर्न सकिन्छ भनेर प्रमाणित गर्न तपाईंले ती ठेगानाले सन्देश/सम्झौताहरूमा हस्ताक्षर गर्न सक्नुहुन्छ । फिसिङ आक्रमणले तपाईंलाई छक्याएर अरूका लागि तपाईंको परिचयमा हस्ताक्षर गराउने प्रयास गर्न सक्ने भएकाले अस्पष्ट वा जथाभावीमा हस्ताक्षर गर्दा ध्यान दिनुहोस् । आफू सहमत भएको पूर्ण विस्तृत-कथनमा मात्र हस्ताक्षर गर्नुहोस् ।</translation> - </message> - <message> <source>Choose previously used address</source> <translation type="unfinished">पहिला प्रयोग गरिएको ठेगाना प्रयोग गर्नुहोस्</translation> </message> diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index e0e3e3a138..b8a2c4fe1f 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -180,6 +180,10 @@ Ondertekenen is alleen mogelijk met adressen van het type 'legacy'.</translation <translation type="unfinished">Voer de oude wachtwoordzin en de nieuwe wachtwoordzin in voor de portemonnee.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Doorgaan</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">Onthoud dat het versleutelen van uw portemonnee uw bitcoins niet volledig kan beschermen tegen diefstal, bijvoorbeeld door malware die uw computer infecteert.</translation> </message> @@ -299,6 +303,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> @@ -407,6 +423,10 @@ Ondertekenen is alleen mogelijk met adressen van het type 'legacy'.</translation <source>%1 GB</source> <translation type="unfinished">%1 Gb</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">standaard portemonnee</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -721,10 +741,6 @@ Ondertekenen is alleen mogelijk met adressen van het type 'legacy'.</translation <translation type="unfinished">Maskeer de waarden op het tabblad Overzicht</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standaard portemonnee</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Geen portefeuilles beschikbaar</translation> </message> @@ -1105,10 +1121,6 @@ Het migratieproces maakt voorafgaand aan het migreren een backup van de wallet. <translation type="unfinished">Wallet openen waarschuwing</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standaard portemonnee</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Portemonnee Openen</translation> @@ -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> @@ -2261,10 +2277,6 @@ Als je deze fout ziet zou je de aanbieder moeten verzoeken om een BIP21-compatib <translation type="unfinished">De transport layer versie: %1</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">De BIP324 sessie ID string in hex, indien aanwezig.</translation> - </message> - <message> <source>Session ID</source> <translation type="unfinished">Sessie ID</translation> </message> @@ -2367,6 +2379,10 @@ Als je deze fout ziet zou je de aanbieder moeten verzoeken om een BIP21-compatib <translation type="unfinished">Richting/Type</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">De BIP324 sessie ID string in hex.</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">Het netwerkprotocol waarmee deze peer verbonden is: IPv4, IPv6, Onion, I2P, of CJDNS.</translation> </message> @@ -2539,10 +2555,18 @@ Als je deze fout ziet zou je de aanbieder moeten verzoeken om een BIP21-compatib <translation type="unfinished">Netwerkactiviteit uitgeschakeld</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Geen</translation> + </message> + <message> <source>Executing command without any wallet</source> <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> @@ -3217,10 +3241,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation type="unfinished">&Onderteken bericht</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">U kunt berichten/overeenkomsten ondertekenen met uw adres om te bewijzen dat u Bitcoins kunt versturen. Wees voorzichtig met het ondertekenen van iets vaags of willekeurigs, omdat phishingaanvallen u kunnen proberen te misleiden tot het ondertekenen van overeenkomsten om uw identiteit aan hen toe te vertrouwen. Onderteken alleen volledig gedetailleerde verklaringen voordat u akkoord gaat.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Het Bitcoin adres om bericht mee te ondertekenen</translation> </message> @@ -3305,10 +3325,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation type="unfinished">Controleer het adres en probeer het opnieuw.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Het opgegeven adres verwijst niet naar een sleutel.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Wallet ontsleutelen werd geannuleerd.</translation> </message> @@ -3842,11 +3858,6 @@ Ga naar Bestand > Wallet openen om een wallet te laden. <translation type="unfinished">PSBT is gekopieerd</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Gekopieerd naar het klembord</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">Kan transactie niet ondertekenen.</translation> </message> @@ -3858,10 +3869,6 @@ Ga naar Bestand > Wallet openen om een wallet te laden. <source>Can't display address</source> <translation type="unfinished">Adres kan niet weergegeven worden</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">standaard portemonnee</translation> - </message> </context> <context> <name>WalletView</name> @@ -3994,10 +4001,6 @@ Ga naar Bestand > Wallet openen om een wallet te laden. <translation type="unfinished">Geen walletbestandsformaat opgegeven. Om createfromdump te gebruiken, moet -format=<format> opgegeven worden.</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">Waarschuwing: Controleer dat de datum en tijd van uw computer correct zijn ingesteld! Bij een onjuist ingestelde klok zal %s niet goed werken.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Gelieve bij te dragen als je %s nuttig vindt. Bezoek %s voor meer informatie over de software.</translation> </message> @@ -4106,10 +4109,6 @@ Ga naar Bestand > Wallet openen om een wallet te laden. <translation type="unfinished">-maxmempool moet minstens %d MB zijn</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Een fatale interne fout heeft zich voor gedaan, zie debug.log voor details</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Kan -%s adres niet herleiden: '%s'</translation> </message> @@ -4278,6 +4277,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 +4329,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 +4417,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 +4441,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 +4665,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> @@ -4670,10 +4693,6 @@ Kan mislukte migratie niet opschonen</translation> <translation type="unfinished">Transactie te groot</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Kan geen geheugen toekennen voor -maxsigcachesize: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Niet in staat om aan %s te binden op deze computer (bind gaf error %s)</translation> </message> @@ -4754,6 +4773,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_pam.ts b/src/qt/locale/bitcoin_pam.ts index e5675cda24..8e402e4c18 100644 --- a/src/qt/locale/bitcoin_pam.ts +++ b/src/qt/locale/bitcoin_pam.ts @@ -803,10 +803,6 @@ <translation type="unfinished">Maliaring pakilawe pasibayu ing address at pasibayuan ya iti.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Ing milub a address ali ya mag-refer king metung a key.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Me-kansela ya ing pamag-unlock king wallet.</translation> </message> diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index f1aab64ad2..94d87252d0 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -46,6 +46,14 @@ <translation type="unfinished">&Usuń</translation> </message> <message> + <source>Choose the address to send coins to</source> + <translation type="unfinished">Wybierz adres, na który chcesz wysłać monety</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation type="unfinished">Wybierz adres, na który chcesz otrzymywać monety</translation> + </message> + <message> <source>C&hoose</source> <translation type="unfinished">Wybierz</translation> </message> @@ -138,6 +146,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation> <translation type="unfinished">Wprowadź stare i nowe hasło portfela. </translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Kontynuuj</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">Pamiętaj, że zaszyfrowanie portfela nie pomoże w zapobiegnięciu kradzieży twoich bitcoinów jeśli komputer zostanie zainfekowany przez złośliwe oprogramowanie.</translation> </message> @@ -257,6 +269,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> @@ -363,7 +387,11 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation> <numerusform>%n lata</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">domyślny portfel</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -678,10 +706,6 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation> <translation type="unfinished">Schowaj wartości w zakładce Podsumowanie</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">domyślny portfel</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Brak dostępnych portfeli</translation> </message> @@ -1062,6 +1086,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> @@ -1081,10 +1113,6 @@ Proces migracji utworzy kopię zapasową portfela przed migracją. Plik kopii za <translation type="unfinished">Ostrzeżenie przy otworzeniu potrfela</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">domyślny portfel</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Otwórz Portfel</translation> @@ -1157,6 +1185,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 +1576,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 +2301,14 @@ 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>Session ID</source> + <translation type="unfinished">ID sesji</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Wersja</translation> </message> @@ -2359,6 +2403,10 @@ Jeśli pojawia się ten błąd, poproś sprzedawcę o podanie URI zgodnego z BIP <translation type="unfinished">Uprawnienia</translation> </message> <message> + <source>The direction and type of peer connection: %1</source> + <translation type="unfinished">Kierunek i typ połączenia równorzędnego: %1</translation> + </message> + <message> <source>Direction/Type</source> <translation type="unfinished">Kierunek/Rodzaj</translation> </message> @@ -2555,14 +2603,39 @@ Jeśli pojawia się ten błąd, poproś sprzedawcę o podanie URI zgodnego z BIP <translation type="unfinished">Aktywność sieciowa wyłączona</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Żaden</translation> + </message> + <message> <source>Executing command without any wallet</source> <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> <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">Witaj w %1 konsoli RPC. +Użyj strzałek do góry oraz w dół, aby nawigować po historii oraz %2 w celu wyczyszczenia ekranu. +Użyj %3 oraz %4 aby zwiększyć lub zmniejszyć rozmiar czcionki. +Wpisz %5 w celu wyświetlenia dostępnych komend. +Aby uzyskać więcej informacji na temat używania tej konsoli wpisz %6. + +%7UWAGA: Oszuści są wszędzie i potrafią namawiać użytkowników do wpisywania złych komend w celu wykradania zawartości ich porfeli. Nie używaj tej konsoli jeżeli nie znasz wszystkich konsekwencji danej komendy.%8</translation> + </message> + <message> <source>Executing…</source> <extracomment>A console message indicating an entered command is currently being executed.</extracomment> <translation type="unfinished">Wykonuję...</translation> @@ -3250,10 +3323,6 @@ Uwaga: Ponieważ opłata jest naliczana za każdy bajt, opłata "100 satoshi za <translation type="unfinished">Podpi&sz Wiadomość</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">Możesz podpisywać wiadomości swoimi adresami aby udowodnić, że jesteś ich właścicielem. Uważaj, aby nie podpisywać niczego co wzbudza Twoje podejrzenia, ponieważ ktoś może stosować phishing próbując nakłonić Cię do ich podpisania. Akceptuj i podpisuj tylko w pełni zrozumiałe komunikaty i wiadomości.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Adres Bitcoin, za pomocą którego podpisać wiadomość</translation> </message> @@ -3339,10 +3408,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation type="unfinished">Proszę sprawdzić adres i spróbować ponownie.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Wprowadzony adres nie odnosi się do klucza.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Odblokowanie portfela zostało anulowane.</translation> </message> @@ -3824,8 +3889,7 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Go to File > Open Wallet to load a wallet. - OR -</source> <translation type="unfinished">Portfel nie został wybrany. -Przejdź do Plik > Otwórz Portfel aby wgrać portfel. -</translation> +Przejdź do Plik > Otwórz Portfel aby wgrać portfel.</translation> </message> <message> <source>Create a new wallet</source> @@ -3904,11 +3968,6 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Skopiowano PSBT</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Skopiowane do schowka</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">Nie można podpisać transakcji.</translation> </message> @@ -3920,10 +3979,6 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <source>Can't display address</source> <translation type="unfinished">Nie można wyświetlić adresu</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">domyślny portfel</translation> - </message> </context> <context> <name>WalletView</name> @@ -4012,6 +4067,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> @@ -4021,7 +4080,7 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. </message> <message> <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> - <translation type="unfinished">Nie dostarczono pliku zrzutu. Aby użyć funkcji createfromdump, należy podać -dumpfile=1.</translation> + <translation type="unfinished">Nie dostarczono pliku zrzutu. Aby użyć funkcji createfromdump, należy podać -dumpfile=<filename>.</translation> </message> <message> <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> @@ -4029,11 +4088,7 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. </message> <message> <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> - <translation type="unfinished">Nie dostarczono pliku zrzutu. Aby użyć funkcji createfromdump, należy podać -dumpfile=1.</translation> - </message> - <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Proszę sprawdzić czy data i czas na Twoim komputerze są poprawne! Jeżeli ustawienia zegara będą złe, %s nie będzie działał prawidłowo.</translation> + <translation type="unfinished">Nie dostarczono pliku zrzutu. Aby użyć funkcji createfromdump, należy podać -dumpfile=<format>.</translation> </message> <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> @@ -4096,6 +4151,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> @@ -4116,14 +4183,14 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">-maxmempool musi być przynajmniej %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Błąd: Wystąpił fatalny błąd wewnętrzny, sprawdź szczegóły w debug.log</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <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 +4199,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 +4219,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 +4287,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 +4327,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 +4339,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 +4355,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 +4383,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 +4423,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 +4459,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 +4483,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 +4499,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 +4543,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> @@ -4421,8 +4608,11 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. </message> <message> <source>Specified blocks directory "%s" does not exist.</source> - <translation type="unfinished">Podany folder bloków "%s" nie istnieje. -</translation> + <translation type="unfinished">Podany folder bloków "%s" nie istnieje.</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> @@ -4433,6 +4623,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 +4647,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> @@ -4477,10 +4675,6 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Transakcja zbyt duża</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Nie mogę zalokować pamięci dla -maxsigcachesize: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Nie można przywiązać do %s na tym komputerze (bind zwrócił błąd %s)</translation> </message> @@ -4541,10 +4735,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..56fe047bba 100644 --- a/src/qt/locale/bitcoin_pt.ts +++ b/src/qt/locale/bitcoin_pt.ts @@ -3,11 +3,11 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">Clique com o botão direito para editar o endereço ou etiqueta</translation> + <translation type="unfinished">Clique com o botão direito do rato para editar o endereço ou a etiqueta</translation> </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,11 +149,11 @@ 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> - <translation type="unfinished">Desbloquear carteira</translation> + <translation type="unfinished">Desbloquear a carteira</translation> </message> <message> <source>Change passphrase</source> @@ -177,15 +177,23 @@ 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>Continue</source> + <translation type="unfinished">Continuar</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Voltar</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 +213,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 +225,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 +233,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 +241,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 +271,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 +296,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 +304,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 +312,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 +352,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> @@ -410,7 +418,11 @@ Assinar só é possível com endereços do tipo "legado".</translation> <numerusform>%n anos </numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">carteira predefinida</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -431,7 +443,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 +467,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 +488,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 +496,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> @@ -536,7 +548,7 @@ Assinar só é possível com endereços do tipo "legado".</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> @@ -724,10 +736,6 @@ Assinar só é possível com endereços do tipo "legado".</translation> <translation type="unfinished">Mascare os valores na aba de visão geral</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">carteira predefinida</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Sem carteiras disponíveis</translation> </message> @@ -786,12 +794,12 @@ Assinar só é possível com endereços do tipo "legado".</translation> <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 de pares</translation> </message> <message> <source>Disable network activity</source> @@ -801,7 +809,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 +840,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 +877,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 +904,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> @@ -1052,7 +1060,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> @@ -1088,11 +1096,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 +1108,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> @@ -1116,7 +1128,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Migration Successful</source> - <translation type="unfinished">Êxito na migração</translation> + <translation type="unfinished">Migração bem sucedida</translation> </message> </context> <context> @@ -1127,16 +1139,12 @@ 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> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">carteira predefinida</translation> + <translation type="unfinished">Aviso de carteira aberta</translation> </message> <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 +1172,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 +1184,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 +1219,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 +1227,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 +1239,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 +1259,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 +1268,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 +1283,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 +1303,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 +1374,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 +1402,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 +1422,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 +1461,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 +1483,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 +1511,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 +1566,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 +1577,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 com Bitcoin Core (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 +1625,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 +1659,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 +1690,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,19 +1710,19 @@ 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> - <translation type="unfinished">Mapear porta usando &NAT-PMP</translation> + <translation type="unfinished">Mapear porta usando NA&T-PMP</translation> </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 +1730,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 +1758,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 +1778,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 +1794,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 +1806,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 +1819,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 +1842,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 +1877,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 +1888,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 +1899,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 +1927,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 +1939,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 +1994,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 +2010,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 +2023,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 +2035,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 +2052,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 +2064,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 +2072,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 +2096,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 +2111,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 +2126,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 +2158,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 +2209,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 +2217,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 o 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 +2241,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 +2252,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 +2281,15 @@ 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>Local Addresses</source> + <translation type="unfinished">Endereços locais</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Endereços de rede que seu nó Bitcoin está usando atualmente para se comunicar com outros nós.</translation> </message> <message> <source>Block chain</source> @@ -2272,7 +2297,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 +2305,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 +2317,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> @@ -2315,6 +2340,10 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <translation type="unfinished">Selecione um par para ver informação detalhada.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalhes dos pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versão da camada de transporte: %1</translation> </message> @@ -2323,12 +2352,8 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <translation type="unfinished">Transporte</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">A string do ID da sessão BIP324 em hexadecimal, se houver.</translation> - </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 +2361,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 +2369,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 +2389,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 +2404,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 +2435,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 +2455,11 @@ 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 BIP324 session ID string in hex.</source> + <translation type="unfinished">A cadeia de ID da sessão BIP324 em hexadecimal.</translation> </message> <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> @@ -2437,12 +2470,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 +2492,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 +2512,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 +2536,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 +2561,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">Saída manual: 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 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 +2630,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 +2643,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> @@ -2592,6 +2654,10 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <translation type="unfinished">Atividade de rede desativada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Nenhum</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">A executar o comando sem qualquer carteira</translation> </message> @@ -2612,18 +2678,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 +2740,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 +2748,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 +2776,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 +2815,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 +2832,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 +2859,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 +2875,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 +2883,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 +2891,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 +2933,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 +2961,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 +2985,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 +3009,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 +3017,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 +3033,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 +3069,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 +3081,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> @@ -3036,11 +3106,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 +3119,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 +3135,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 +3144,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 +3175,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 sua proposta de transação. Isto irá produzir uma Transação de Bitcoin parcialmente assinada (PSBT, sigla em inglês) a qual pode guardar ou copiar e então assinar com por exemplo uma carteira %1 offine ou uma PSBT compatível com carteira de hardware.</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 +3194,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 +3207,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 +3233,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 +3261,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 +3284,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 +3295,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 +3311,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 +3323,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 +3347,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 +3365,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> + <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">Você pode assinar mensagens com seus endereços legados (P2PKH) para provar que pode receber bitcoins enviados a eles. Tenha cuidado para não assinar nada vago ou aleatório, pois ataques de phishing podem tentar enganá-lo para assinar sua identidade para eles. Assine apenas declarações totalmente detalhadas com as quais você 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 +3385,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 +3401,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 +3413,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 +3441,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 +3449,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 "Assinar mensagem" para gerar a assinatura</translation> </message> <message> <source>The entered address is invalid.</source> @@ -3390,8 +3460,8 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <translation type="unfinished">Por favor, verifique o endereço e tente novamente.</translation> </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> + <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">O endereço inserido não se refere a uma chave legada (P2PKH). A assinatura de mensagens para SegWit e outros tipos de endereço não P2PKH não são suportadas nesta versão do %1. Por favor, verifique o endereço e tente novamente.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3399,7 +3469,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 +3477,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 +3493,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 +3508,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 +3520,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 +3540,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 +3561,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 +3577,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 +3594,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 +3620,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 +3632,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 +3644,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 +3656,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 +3722,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 +3754,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 +3778,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 +3833,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ínima</translation> </message> <message> <source>Range…</source> @@ -3788,15 +3857,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 +3890,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 +3899,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 +3922,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 +3931,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 +3939,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 +3952,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 +3966,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 +3978,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 +3997,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 +4017,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> @@ -3964,9 +4033,8 @@ Ir para o arquivo > Abrir carteira para carregar a carteira <translation type="unfinished">PSBT copiado</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiado para a área de transferência</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Fee-bump PSBT copiado para a área de transferência</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3974,30 +4042,30 @@ 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> + <source>Signer error</source> + <translation type="unfinished">Erro do signatário</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">carteira predefinida</translation> + <source>Can't display address</source> + <translation type="unfinished">Não é possível visualizar o endereço</translation> </message> </context> <context> <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 +4074,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 +4082,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,64 +4101,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 utilizar a ferramenta de carteira bitcoin-wallet para recuperar 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 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> + <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>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Por favor verifique que a data e hora do seu computador estão certos! Se o relógio não estiver certo, o %s não funcionará corretamente.</translation> + <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">Não foi fornecido nenhum formato de ficheiro de carteira. Para usar createfromdump, é necessário fornecer -format=<format>.</translation> </message> <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> @@ -4098,47 +4189,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">Falha ao renomear '%s' -> '%s'. Deve resolver este problema manualmente movendo ou removendo o diretório de cópia inválido %s, caso contrário ocorrerá novamente o mesmo erro na próxima inicialização.</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 +4237,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 +4277,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 +4289,147 @@ 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> - </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">-maxmempool tem de ser pelo menos %d MB</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> </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 %s! Todas as chaves são lidas corretamente, mas os dados de transação ou os metadados de 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 remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Falha ao remover o diretório do snapshot chainstate (%s). Remova-o manualmente antes de reiniciar. +</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>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falha ao transferir o ficheiro de bloco para o disco. Isto é provavelmente o resultado de um erro de E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falha ao transferir o ficheiro undo para o disco. Isto é provavelmente o resultado de um erro de E/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>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">O peso máximo da transação é inferior ao peso da transação sem entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">O peso máximo da transação é demasiado baixo, não pode acomodar a saída de mudança</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>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Renomear de '%s' -> '%s'falhou. Não é possível limpar o diretório leveldb do chainstate em segundo plano.</translation> + </message> + <message> + <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">A combinação das entradas pré-selecionadas e a seleção automática de entradas da carteira excede o peso máximo da transação. Tente enviar uma quantia menor ou consolidar manualmente os UTXOs da sua carteira</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,51 +4437,75 @@ 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> <message> + <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">A data e a hora do seu computador parecem estar mais de %d minutos fora de sincronia com a rede, isso pode levar a uma falha de consenso. Depois de confirmar o relógio do seu computador, essa mensagem não deve mais aparecer quando você reiniciar seu nó. Sem uma reinicialização, ela deve parar de aparecer automaticamente depois que você se conectar a um número suficiente de novos pares de saída, o que pode levar algum tempo. Você pode inspecionar o campo `timeoffset` dos métodos RPC `getpeerinfo` e `getnetworkinfo` para obter mais informações.</translation> + </message> + <message> <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>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind só pode ser utilizado para conexões de entrada ("out" foi passado)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ocorreu um fatal internal error, consulte debug.log para obter detalhes:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Não foram encontrados os dados assumeutxo para o blockhash em causa '%s'.</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>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Bloco corrompido encontrado indicando possível falha de hardware.</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 +4513,23 @@ 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>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Falha na verificação de integridade da criptografia de curva elíptica. %s está sendo desligado.</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 +4553,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 +4573,143 @@ 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 foi 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 connect best block (%s).</source> + <translation type="unfinished">Falha ao conectar o melhor bloco (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Falha ao desconectar o bloco.</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 read block.</source> + <translation type="unfinished">Falha ao ler o bloco.</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>Failed to write block.</source> + <translation type="unfinished">Falha ao escrever bloco.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Falha ao escrever na base de dados de índices de blocos.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Falha ao escrever na base de dados de moedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Falha ao escrever dados de anulação.</translation> </message> <message> <source>Failure removing transaction: %s</source> @@ -4470,11 +4717,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 +4733,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,37 +4761,57 @@ 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> <translation type="unfinished">A carregar a carteira…</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">O peso máximo da transação deve estar entre %d e %d</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Falta a quantia</translation> </message> @@ -4550,7 +4821,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,55 +4829,80 @@ 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>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Apenas a direção foi definida, sem permissões: '%s'</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> <translation type="unfinished">A secção [%s] não é reconhecida.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">O signatário não fez eco do endereço</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">O signatário fez eco de um endereço inesperado +%s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">O signatário retornou erro: %s</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 +4918,55 @@ 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>System error while flushing: %s</source> + <translation type="unfinished">Erro de sistema durante a transferência: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Erro do sistema ao carregar arquivo de bloco externo: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Erro do sistema ao salvar bloco no disco: %s</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>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Não há ScriptPubKeyManager para este endereç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 +4974,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 +4994,19 @@ 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> - </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">Transação demasiado grande</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 +5014,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 +5034,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> @@ -4751,12 +5061,16 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation type="unfinished">Ativadas novas regras desconhecidas (versionbit %i)</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opção não reconhecida "%s" fornecido em -test=<option>.</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished">Nível de registo global não suportado %s=%s. Valores válidos: %s.</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 +5078,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 +5102,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 +5110,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..6c2c515066 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -7,7 +7,7 @@ </message> <message> <source>Create a new address</source> - <translation type="unfinished">Criar um novo endereço.</translation> + <translation type="unfinished">Criar um novo endereço</translation> </message> <message> <source>&New</source> @@ -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> @@ -184,6 +184,10 @@ Só é possível assinar com endereços do tipo 'legado'.</translation> <translation type="unfinished">Digite a antiga e a nova senha da carteira</translation> </message> <message> + <source>Back</source> + <translation type="unfinished">Voltar</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">Lembre-se que sua carteira criptografada não poderá proteger totalmente os seus bitcoins de serem roubados por softwares maldosos que infectem seu computador.</translation> </message> @@ -382,7 +386,11 @@ Só é possível assinar com endereços do tipo 'legado'.</translation> <numerusform>%nanos </numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">carteira padrão</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -496,7 +504,7 @@ Só é possível assinar com endereços do tipo 'legado'.</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Assine mensagens com seus endereços Bitcoin para provar que você é dono deles</translation> + <translation type="unfinished">Assine mensagens com seus endereços Bitcoin para provar que você é dono delas</translation> </message> <message> <source>&Verify message…</source> @@ -504,11 +512,11 @@ Só é possível assinar 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 se assegurar que elas foram assinadas pelo dono de Endereços Bitcoin específicos</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Carregar PSBT do arquivo...</translation> + <translation type="unfinished">&Carregar 'PSBT' do arquivo...</translation> </message> <message> <source>Open &URI…</source> @@ -619,7 +627,7 @@ Só é possível assinar com endereços do tipo 'legado'.</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">Carregar Transação de Bitcoin Parcialmente Assinada</translation> + <translation type="unfinished">Carregar</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -693,11 +701,7 @@ Só é possível assinar com endereços do tipo 'legado'.</translation> </message> <message> <source>Mask the values in the Overview tab</source> - <translation type="unfinished">Mascarar os valores na barra Resumo</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">carteira padrão</translation> + <translation type="unfinished">Mascarar os valores na aba de visão geral</translation> </message> <message> <source>No wallets available</source> @@ -966,7 +970,7 @@ Só é possível assinar com endereços do tipo 'legado'.</translation> </message> <message> <source>Copy change</source> - <translation type="unfinished">Copiar troco</translation> + <translation type="unfinished">Copiar alteração</translation> </message> <message> <source>(%1 locked)</source> @@ -1055,7 +1059,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Migrate Wallet</source> - <translation type="unfinished">Migrar Carteira</translation> + <translation type="unfinished">Migrar carteira</translation> </message> <message> <source>Migrating Wallet <b>%1</b>…</source> @@ -1089,10 +1093,6 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Abrir carteira alerta</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">carteira padrão</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Abrir carteira</translation> @@ -2156,6 +2156,14 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Número de conexões</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Endereços locais</translation> + </message> + <message> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished">Endereços de rede que seu nó Bitcoin está usando atualmente para se comunicar com outros nós.</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Corrente de blocos</translation> </message> @@ -2204,6 +2212,10 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Selecione um nó para ver informações detalhadas.</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Ocultar detalhes dos pares</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Versão da camada de transporte: %1</translation> </message> @@ -2212,10 +2224,6 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Transporte</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">A string do ID da sessão BIP324 em hexadecimal, se houver.</translation> - </message> - <message> <source>Session ID</source> <translation type="unfinished">ID de sessão</translation> </message> @@ -2253,7 +2261,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> @@ -2310,6 +2318,10 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Permissões</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">A cadeia de ID da sessão BIP324 em hexadecimal.</translation> + </message> + <message> <source>Services</source> <translation type="unfinished">Serviços</translation> </message> @@ -2427,6 +2439,10 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Atividade da rede desativada</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Nenhum</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Executando comando sem nenhuma carteira</translation> </message> @@ -2469,7 +2485,7 @@ Utilize %3 e %4 para aumentar ou diminuir a tamanho da fonte. Digite %5 para ver os comandos disponíveis. Para mais informações sobre a utilização desse console. digite %6. -%7 AVISO: Scammers estão ativamente influenciando usuário a digitarem comandos aqui e roubando os conteúdos de suas carteiras; Não use este terminal sem pleno conhecimento dos efeitos de cada comando.%8</translation> +%7 AVISO: Scammers estão ativamente influenciando usuário a digitarem comandos aqui, roubando os conteúdos de suas carteiras. Não use este terminal sem pleno conhecimento dos efeitos de cada comando.%8</translation> </message> <message> <source>Executing…</source> @@ -2862,7 +2878,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Copy change</source> - <translation type="unfinished">Copiar troco</translation> + <translation type="unfinished">Copiar alteração</translation> </message> <message> <source>%1 (%2 blocks)</source> @@ -3104,8 +3120,8 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <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">Você pode assinar mensagens com seus endereços para provar que você pode receber bitcoins enviados por alguém. Cuidado para não assinar nada vago ou aleatório, pois ataques phishing podem tentar te enganar para assinar coisas para eles como se fosse você. Somente assine termos bem detalhados que você concorde.</translation> + <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">Você pode assinar mensagens com seus endereços legados (P2PKH) para provar que pode receber bitcoins enviados a eles. Tenha cuidado para não assinar nada vago ou aleatório, pois ataques de phishing podem tentar enganá-lo para assinar sua identidade para eles. Assine apenas declarações totalmente detalhadas com as quais você concorda.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3192,8 +3208,8 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <translation type="unfinished">Por gentileza, cheque o endereço e tente novamente.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">O endereço fornecido não se refere a uma chave.</translation> + <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">O endereço inserido não se refere a uma chave legada (P2PKH). A assinatura de mensagens para SegWit e outros tipos de endereço não P2PKH não são suportadas nesta versão do %1. Por favor, verifique o endereço e tente novamente.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3724,9 +3740,8 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT copiado</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Copiado para a área de transferência</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Fee-bump PSBT copiado para a área de transferência</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3737,10 +3752,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Não foi possível mandar a transação</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">carteira padrão</translation> + <source>Signer error</source> + <translation type="unfinished">Erro do signatário</translation> </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -3827,10 +3842,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Mais de um endereço onion associado é fornecido. Usando %s para automaticamento criar serviço onion Tor.</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Por favor verifique se a data e o horário de seu computador estão corretos. Se o relógio de seu computador estiver incorreto, %s não funcionará corretamente.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Por favor contribua se você entender que %s é útil. Visite %s para mais informações sobre o software.</translation> </message> @@ -3931,10 +3942,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool deve ser pelo menos %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Aconteceu um erro interno fatal, veja os detalhes em debug.log</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Não foi possível encontrar o endereço de -%s: '%s'</translation> </message> @@ -3948,7 +3955,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">Não foi possível escrever no diretório '%s': verifique as permissões.</translation> + <translation type="unfinished">Não foi possível escrever no diretório 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> @@ -3983,6 +3990,12 @@ Go to File > Open Wallet to load a wallet. <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> </message> <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Falha ao remover o diretório do snapshot chainstate (%s). Remova-o manualmente antes de reiniciar. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">Impossível renomear o arquivo peers.dat (inválido). Por favor mova-o ou delete-o e tente novamente.</translation> </message> @@ -3991,6 +4004,14 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Falha na estimativa de taxa. Fallbackfee desativada. Espere alguns blocos ou ative %s.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falha ao transferir o ficheiro de bloco para o disco. Isto é provavelmente o resultado de um erro de E/S.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Falha ao transferir o ficheiro undo para o disco. Isto é provavelmente o resultado de um erro de E/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> </message> @@ -3999,6 +4020,14 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Montante inválido para %s=<amount>: '%s' (precisa ser pelo menos a taxa de minrelay de %s para prevenir que a transação nunca seja confirmada)</translation> </message> <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">O peso máximo da transação é inferior ao peso da transação sem entradas</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">O peso máximo da transação é demasiado baixo, não pode acomodar a saída de mudança</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 limitadas a rede CJDNS (-onlynet=cjdns), mas -cjdnsreachable não foi configurado</translation> </message> @@ -4015,6 +4044,14 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Conexões de saída limitadas a rede i2p (-onlynet=i2p), mas -i2psam não foi configurado</translation> </message> <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">Renomear de '%s' -> '%s'falhou. Não é possível limpar o diretório leveldb do chainstate em segundo plano.</translation> + </message> + <message> + <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">A combinação das entradas pré-selecionadas e a seleção automática de entradas da carteira excede o peso máximo da transação. Tente enviar uma quantia menor ou consolidar manualmente os UTXOs da sua carteira</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> @@ -4057,6 +4094,10 @@ Por favor tente atualizar o software para a última versão. </translation> </message> <message> + <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">A data e a hora do seu computador parecem estar mais de %d minutos fora de sincronia com a rede, isso pode levar a uma falha de consenso. Depois de confirmar o relógio do seu computador, essa mensagem não deve mais aparecer quando você reiniciar seu nó. Sem uma reinicialização, ela deve parar de aparecer automaticamente depois que você se conectar a um número suficiente de novos pares de saída, o que pode levar algum tempo. Você pode inspecionar o campo `timeoffset` dos métodos RPC `getpeerinfo` e `getnetworkinfo` para obter mais informações.</translation> + </message> + <message> <source> Unable to cleanup failed migration</source> <translation type="unfinished"> @@ -4069,6 +4110,18 @@ Unable to restore backup of wallet.</source> Impossível restaurar backup da carteira.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind só pode ser utilizado para conexões de entrada ("out" foi passado)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Ocorreu um fatal internal error, consulte debug.log para obter detalhes:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Não foram encontrados os dados assumeutxo para o blockhash em causa '%s'.</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">A verificação dos blocos foi interrompida</translation> </message> @@ -4077,6 +4130,10 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">A configuração %s somente é aplicada na rede %s quando na sessão [%s].</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Bloco corrompido encontrado indicando possível falha de hardware.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Detectado Banco de dados de blocos corrompido</translation> </message> @@ -4101,6 +4158,10 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Carregamento terminado!</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Falha na verificação de integridade da criptografia de curva elíptica. %s está sendo desligado.</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> </message> @@ -4213,10 +4274,22 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Erro: a transação do banco de dados não pode ser executada para a carteira %s</translation> </message> <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">Falha ao conectar o melhor bloco (%s).</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Falha ao desconectar o bloco.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Falha ao escutar em qualquer porta. Use -listen=0 se você quiser isso.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Falha ao ler o bloco.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Falha ao escanear novamente a carteira durante a inicialização</translation> </message> @@ -4229,6 +4302,22 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Falha ao verificar a base de dados</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">Falha ao escrever bloco.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Falha ao escrever na base de dados de índices de blocos.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Falha ao escrever na base de dados de moedas.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Falha ao escrever dados de anulação.</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">Falha ao remover a transação: %s</translation> </message> @@ -4321,6 +4410,10 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Carregando carteira...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">O peso máximo da transação deve estar entre %d e %d</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Faltando quantia</translation> </message> @@ -4349,6 +4442,10 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Não há solução para entrada pré-selecionada %s</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">Apenas a direção foi definida, sem permissões: '%s'</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">O modo prune não pode ser configurado com um valor negativo.</translation> </message> @@ -4393,6 +4490,19 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Sessão [%s] não reconhecida.</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">O signatário não fez eco do endereço</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">O signatário fez eco de um endereço inesperado +%s</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">O signatário retornou erro: %s</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">Assinatura de transação falhou</translation> </message> @@ -4421,6 +4531,18 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Iniciando atividades da rede...</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Erro de sistema durante a transferência: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">Erro do sistema ao carregar arquivo de bloco externo: %s</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">Erro do sistema ao salvar bloco no disco: %s</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> </message> @@ -4433,6 +4555,10 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">A carteira irá evitar pagar menos que a taxa mínima de retransmissão.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Não há ScriptPubKeyManager para este endereço</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Este é um software experimental.</translation> </message> @@ -4473,10 +4599,6 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Transação muito grande</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Impossível alocar memória para a opção "-maxsigcachesize: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Erro ao vincular em %s neste computador (bind retornou erro %s)</translation> </message> @@ -4529,6 +4651,10 @@ Impossível restaurar backup da carteira.</translation> <translation type="unfinished">Rede desconhecida especificada em -onlynet: '%s'</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Opção não reconhecida "%s" fornecido em -test=<option>.</translation> + </message> + <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished">Nível de registo global não suportado %s=%s. Valores válidos: %s.</translation> </message> diff --git a/src/qt/locale/bitcoin_ro.ts b/src/qt/locale/bitcoin_ro.ts index 059436329d..33a478d217 100644 --- a/src/qt/locale/bitcoin_ro.ts +++ b/src/qt/locale/bitcoin_ro.ts @@ -181,6 +181,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> </translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continua</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">Reţineti: criptarea portofelului dvs. nu vă poate proteja în totalitate bitcoin-urile împotriva furtului de malware care vă infectează computerul.</translation> </message> @@ -225,6 +229,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,7 +373,15 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>%1 kB</source> + <translation type="unfinished">%1kB</translation> + </message> + <message> + <source>default wallet</source> + <translation type="unfinished">portofel implicit</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -417,6 +433,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 +618,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 +666,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> @@ -654,10 +700,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Mascați valorile din fila Prezentare generală</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">portofel implicit</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Niciun portofel disponibil</translation> </message> @@ -686,6 +728,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 +739,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 +762,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 +920,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 +984,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 +1011,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> @@ -942,15 +1044,16 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Atenționare la deschiderea portofelului</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">portofel implicit</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Deschide portofel</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">Deschidere Portofel<b>%1</b></translation> + </message> +</context> <context> <name>RestoreWalletActivity</name> <message> @@ -959,6 +1062,11 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Restaurare portofel</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">Restabilirea Portofelului<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">Restaurarea portofelului nereusita</translation> @@ -1004,6 +1112,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 +1360,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 +1670,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 +1758,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 +1774,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 +1829,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 +1877,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 +1900,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 +1989,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 +2009,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 +2033,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 +2109,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> @@ -1960,10 +2134,18 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Activitatea retelei a fost oprita.</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Niciuna</translation> + </message> + <message> <source>Executing command without any wallet</source> <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 +2170,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 +2241,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 +2284,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 +2422,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 +2486,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> @@ -2438,10 +2652,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">&Semnează mesaj</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">Puteţi semna mesaje/contracte cu adresele dvs. pentru a demostra ca puteti primi bitcoini trimisi la ele. Aveţi grijă să nu semnaţi nimic vag sau aleator, deoarece atacurile de tip phishing vă pot păcăli să le transferaţi identitatea. Semnaţi numai declaraţiile detaliate cu care sînteti de acord.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Adresa cu care semnaţi mesajul</translation> </message> @@ -2518,10 +2728,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Vă rugăm verificaţi adresa şi încercaţi din nou.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Adresa introdusă nu se referă la o cheie.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Deblocarea portofelului a fost anulata.</translation> </message> @@ -2858,6 +3064,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 +3149,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 +3164,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> @@ -2970,8 +3213,8 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Tranzactia nu a putut fi consemnata.</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">portofel implicit</translation> + <source>Can't display address</source> + <translation type="unfinished">Nu se poate afisa adresa</translation> </message> </context> <context> @@ -3025,10 +3268,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Distribuit sub licenţa de programe MIT, vezi fişierul însoţitor %s sau %s</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">Vă rugăm verificaţi dacă data/timpul calculatorului dvs. sînt corecte! Dacă ceasul calcultorului este gresit, %s nu va funcţiona corect.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Va rugam sa contribuiti daca apreciati ca %s va este util. Vizitati %s pentru mai multe informatii despre software.</translation> </message> diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index c7ac89b746..7a54b45768 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">Щелкните правой кнопкой мыши, чтобы отредактировать адрес или этикетку</translation> + <translation type="unfinished">Нажмите правую кнопку мыши, чтобы изменить адрес или метку</translation> </message> <message> <source>Create a new address</source> @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Копирование выбранного адреса в системный буфер обмена</translation> + <translation type="unfinished">Скопировать выбранные адреса в буфер обмена</translation> </message> <message> <source>&Copy</source> @@ -86,12 +86,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <source>Comma separated file</source> <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment> - <translation type="unfinished">Файл, разделенный запятыми</translation> + <translation type="unfinished">Текст, разделённый запятыми (*.csv)</translation> </message> <message> <source>There was an error trying to save the address list to %1. Please try again.</source> <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment> - <translation type="unfinished">Произошла ошибка при попытке сохранить список адресов в %1. Пожалуйста, попробуйте еще раз.</translation> + <translation type="unfinished">Произошла ошибка при сохранении списка адресов в %1. Пожалуйста, попробуйте еще раз.</translation> </message> <message> <source>Sending addresses - %1</source> @@ -125,23 +125,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> <name>AskPassphraseDialog</name> <message> <source>Passphrase Dialog</source> - <translation type="unfinished">Парольная фраза</translation> + <translation type="unfinished">Пароль</translation> </message> <message> <source>Enter passphrase</source> - <translation type="unfinished">Введите парольную фразу</translation> + <translation type="unfinished">Введите пароль</translation> </message> <message> <source>New passphrase</source> - <translation type="unfinished">Новая парольная фраза</translation> + <translation type="unfinished">Новый пароль</translation> </message> <message> <source>Repeat new passphrase</source> - <translation type="unfinished">Повторите новую парольную фразу</translation> + <translation type="unfinished">Повторите новый пароль</translation> </message> <message> <source>Show passphrase</source> - <translation type="unfinished">Показать парольную фразу</translation> + <translation type="unfinished">Показать пароль</translation> </message> <message> <source>Encrypt wallet</source> @@ -149,7 +149,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">Данная операция требует введения парольной фразы для разблокировки вашего кошелька.</translation> + <translation type="unfinished">Данная операция требует введения пароля для разблокировки вашего кошелька.</translation> </message> <message> <source>Unlock wallet</source> @@ -157,7 +157,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change passphrase</source> - <translation type="unfinished">Изменить парольную фразу</translation> + <translation type="unfinished">Изменить пароль</translation> </message> <message> <source>Confirm wallet encryption</source> @@ -165,7 +165,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> - <translation type="unfinished">Предупреждение: если вы зашифруете кошелёк и потеряете парольную фразу, вы <b>ПОТЕРЯЕТЕ ВСЕ ВАШИ БИТКОИНЫ</b>!</translation> + <translation type="unfinished">Предупреждение: Если вы зашифруете кошелёк и потеряете пароль, вы <b>ПОТЕРЯЕТЕ ВСЕ ВАШИ БИТКОЙНЫ</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> @@ -177,11 +177,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </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">Введите новую парольную фразу для кошелька.<br/>Пожалуйста, используйте парольную фразу из <b>десяти или более случайных символов</b>, либо <b>восьми или более слов</b>.</translation> + <translation type="unfinished">Введите новый пароль для кошелька.<br/>Используйте пароль, состоящий из <b>десяти или более случайных символов</b> или <b>восьми или более слов</b>.</translation> </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation type="unfinished">Введите старую и новую парольные фразы для кошелька.</translation> + <translation type="unfinished">Введите старый и новый пароли для кошелька.</translation> + </message> + <message> + <source>Continue</source> + <translation type="unfinished">Продолжить</translation> + </message> + <message> + <source>Back</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> @@ -189,7 +197,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Wallet to be encrypted</source> - <translation type="unfinished">Кошелёк должен быть зашифрован</translation> + <translation type="unfinished">Кошелёк, который будет зашифрован</translation> </message> <message> <source>Your wallet is about to be encrypted. </source> @@ -197,7 +205,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Your wallet is now encrypted. </source> - <translation type="unfinished">Сейчас ваш кошелёк зашифрован. </translation> + <translation type="unfinished">Сейчас ваш кошелёк зашифрован.</translation> </message> <message> <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> @@ -205,15 +213,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Wallet encryption failed</source> - <translation type="unfinished">Шифрование кошелька не удалось</translation> + <translation type="unfinished">Не удалось зашифровать кошелёк</translation> </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">Шифрование кошелька не удалось из-за внутренней ошибки. Ваш кошелек не был зашифрован.</translation> + <translation type="unfinished">Сбой шифрования кошелька из-за внутренней ошибки. Ваш кошелёк не был зашифрован.</translation> </message> <message> <source>The supplied passphrases do not match.</source> - <translation type="unfinished">Введенные пароли не совпадают.</translation> + <translation type="unfinished">Введённые пароли не совпадают.</translation> </message> <message> <source>Wallet unlock failed</source> @@ -221,7 +229,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">Парольная фраза, введённая для расшифровки кошелька, неверна.</translation> + <translation type="unfinished">Пароль, введенный при шифровании кошелька, некорректен.</translation> </message> <message> <source>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,15 +237,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">Парольная фраза кошелька успешно изменена.</translation> + <translation type="unfinished">Пароль кошелька успешно изменён.</translation> </message> <message> <source>Passphrase change failed</source> - <translation type="unfinished">Не удалось сменить парольную фразу</translation> + <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> + <translation type="unfinished">Текущий пароль, введенный для расшифрования кошелька, не подходит. Он содержит нулевой байт. Если пароль была задан в программе версии ниже 25.0, пожалуйста, попробуйте ввести только символы до первого нулевого байта, не включая его.</translation> </message> <message> <source>Warning: The Caps Lock key is on!</source> @@ -303,147 +311,60 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">неизвестно</translation> </message> <message> - <source>Amount</source> - <translation type="unfinished">Сумма</translation> - </message> - <message> - <source>Enter a Bitcoin address (e.g. %1)</source> - <translation type="unfinished">Введите биткоин-адрес (например,%1)</translation> - </message> - <message> - <source>Unroutable</source> - <translation type="unfinished">Немаршрутизируемый</translation> - </message> - <message> - <source>Inbound</source> - <extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment> - <translation type="unfinished">Входящий</translation> - </message> - <message> - <source>Outbound</source> - <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment> - <translation type="unfinished">Исходящий</translation> - </message> - <message> - <source>Full Relay</source> - <extracomment>Peer connection type that relays all network information.</extracomment> - <translation type="unfinished">Полный ретранслятор</translation> - </message> - <message> - <source>Block Relay</source> - <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment> - <translation type="unfinished">Ретранслятор блоков</translation> - </message> - <message> - <source>Manual</source> - <extracomment>Peer connection type established manually through one of several methods.</extracomment> - <translation type="unfinished">Вручную</translation> - </message> - <message> - <source>Feeler</source> - <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment> - <translation type="unfinished">Пробный</translation> - </message> - <message> - <source>Address Fetch</source> - <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment> - <translation type="unfinished">Получение адресов</translation> - </message> - <message> - <source>%1 d</source> - <translation type="unfinished">%1 д</translation> - </message> - <message> - <source>%1 h</source> - <translation type="unfinished">%1 ч</translation> - </message> - <message> - <source>%1 m</source> - <translation type="unfinished">%1 м</translation> - </message> - <message> - <source>%1 s</source> - <translation type="unfinished">%1 с</translation> - </message> - <message> - <source>None</source> - <translation type="unfinished">Нет</translation> - </message> - <message> - <source>N/A</source> - <translation type="unfinished">Н/д</translation> - </message> - <message> - <source>%1 ms</source> - <translation type="unfinished">%1 мс</translation> + <source>Default system font "%1"</source> + <translation type="unfinished">Системный шрифт по умолчанию "%1"</translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation type="unfinished"> - <numerusform>%n секунда</numerusform> - <numerusform>%n секунды</numerusform> - <numerusform>%n секунд</numerusform> + <numerusform>%n second(s)</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>%n минута</numerusform> - <numerusform>%n минуты</numerusform> - <numerusform>%n минут</numerusform> + <numerusform>%n minute(s)</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>%n час</numerusform> - <numerusform>%n часа</numerusform> - <numerusform>%n часов</numerusform> + <numerusform>%n hour(s)</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>%n день</numerusform> - <numerusform>%n дня</numerusform> - <numerusform>%n дней</numerusform> + <numerusform>%n day(s)</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>%n неделя</numerusform> - <numerusform>%n недели</numerusform> - <numerusform>%n недель</numerusform> + <numerusform>%n week(s)</numerusform> + <numerusform>%n week(s)</numerusform> + <numerusform>%n week(s)</numerusform> </translation> </message> - <message> - <source>%1 and %2</source> - <translation type="unfinished">%1 и %2</translation> - </message> <message numerus="yes"> <source>%n year(s)</source> <translation type="unfinished"> - <numerusform>%n год</numerusform> - <numerusform>%n года</numerusform> - <numerusform>%n лет</numerusform> + <numerusform>%n year(s)</numerusform> + <numerusform>%n year(s)</numerusform> + <numerusform>%n year(s)</numerusform> </translation> </message> <message> - <source>%1 B</source> - <translation type="unfinished">%1 Б</translation> - </message> - <message> - <source>%1 kB</source> - <translation type="unfinished">%1 КБ</translation> - </message> - <message> - <source>%1 MB</source> - <translation type="unfinished">%1 МБ</translation> - </message> - <message> - <source>%1 GB</source> - <translation type="unfinished">%1 ГБ</translation> + <source>default wallet</source> + <translation type="unfinished">кошелёк по умолчанию</translation> </message> </context> <context> @@ -523,7 +444,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Изменить пароль используемый для шифрования кошелька</translation> + <translation type="unfinished">Изменить пароль, используемый для шифрования кошелька</translation> </message> <message> <source>&Send</source> @@ -539,7 +460,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">&Зашифровать Кошелёк…</translation> + <translation type="unfinished">&Зашифровать Кошелёк...</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -547,15 +468,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&Создать резервную копию кошелька…</translation> + <translation type="unfinished">&Создать резервную копию кошелька...</translation> </message> <message> <source>&Change Passphrase…</source> - <translation type="unfinished">&Изменить пароль…</translation> + <translation type="unfinished">&Изменить пароль...</translation> </message> <message> <source>Sign &message…</source> - <translation type="unfinished">Подписать &сообщение…</translation> + <translation type="unfinished">Подписать &сообщение...</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> @@ -563,7 +484,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Verify message…</source> - <translation type="unfinished">&Проверить сообщение…</translation> + <translation type="unfinished">&Проверить сообщение</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> @@ -571,23 +492,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Загрузить PSBT из файла…</translation> + <translation type="unfinished">&Загрузить PSBT из файла...</translation> </message> <message> <source>Open &URI…</source> - <translation type="unfinished">Открыть &URI…</translation> + <translation type="unfinished">Открыть &URI...</translation> </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">Закрыть кошелёк…</translation> + <translation type="unfinished">Закрыть кошелёк...</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Создать кошелёк…</translation> + <translation type="unfinished">Создать кошелёк...</translation> </message> <message> <source>Close All Wallets…</source> - <translation type="unfinished">Закрыть все кошельки…</translation> + <translation type="unfinished">Закрыть все кошельки...</translation> </message> <message> <source>&File</source> @@ -607,19 +528,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Синхронизация заголовков (%1%)…</translation> + <translation type="unfinished">Синхронизация заголовков (%1%)...</translation> </message> <message> <source>Synchronizing with network…</source> - <translation type="unfinished">Синхронизация с сетью…</translation> + <translation type="unfinished">Синхронизация с сетью...</translation> </message> <message> <source>Indexing blocks on disk…</source> - <translation type="unfinished">Индексация блоков на диске…</translation> + <translation type="unfinished">Индексация блоков на диске...</translation> </message> <message> <source>Processing blocks on disk…</source> - <translation type="unfinished">Обработка блоков на диске…</translation> + <translation type="unfinished">Обработка блоков на диске...</translation> </message> <message> <source>Connecting to peers…</source> @@ -631,15 +552,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Показать список использованных адресов и меток отправки</translation> + <translation type="unfinished">Показать список использованных адресов отправки и меток</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Показать список использованных адресов и меток получателей</translation> + <translation type="unfinished">Показать список использованных адресов получения и меток</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">Параметры командной строки</translation> + <translation type="unfinished">&Параметры командной строки</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -679,7 +600,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Up to date</source> - <translation type="unfinished">До настоящего времени</translation> + <translation type="unfinished">Синхронизированно</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> @@ -711,7 +632,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Открыть биткойн: URI</translation> + <translation type="unfinished">Открыть URI протокола bitcoin:</translation> </message> <message> <source>Open Wallet</source> @@ -733,7 +654,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <source>Restore a wallet from a backup file</source> <extracomment>Status tip for Restore Wallet menu item</extracomment> - <translation type="unfinished">Восстановить кошелёк из резервной копии</translation> + <translation type="unfinished">Восстановить кошелек из резервной копии</translation> </message> <message> <source>Close all wallets</source> @@ -760,10 +681,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -846,11 +763,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Error creating wallet</source> - <translation type="unfinished">Ошибка создания кошелька</translation> + <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> + <translation type="unfinished">Не удалось создать новый кошелёк, так как программа собрана без поддержки SQLite (необходим для дескрипторных кошельков)</translation> </message> <message> <source>Error: %1</source> @@ -898,7 +815,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Sent transaction</source> - <translation type="unfinished">Отправленная транзакция</translation> + <translation type="unfinished">Исходящая транзакция</translation> </message> <message> <source>Incoming transaction</source> @@ -906,11 +823,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>HD key generation is <b>enabled</b></source> - <translation type="unfinished">HD-генерация ключей <b>включена</b></translation> + <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> + <translation type="unfinished">Генерация HD-ключей <b>запрещена</b></translation> </message> <message> <source>Private key <b>disabled</b></source> @@ -948,7 +865,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Bytes:</source> - <translation type="unfinished">Байты:</translation> + <translation type="unfinished">Байтов:</translation> </message> <message> <source>Amount:</source> @@ -1137,7 +1054,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Migrate Wallet</source> - <translation type="unfinished">Перенести Кошелек</translation> + <translation type="unfinished">Перенести кошелек</translation> </message> <message> <source>Migrating Wallet <b>%1</b>…</source> @@ -1148,14 +1065,6 @@ The migration process will create a backup of the wallet before migrating. This <translation type="unfinished">Кошелек '%1' был успешно перенесён.</translation> </message> <message> - <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Скрипты Watchonly были перенесены в новый кошелек под названием '%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> @@ -1175,13 +1084,9 @@ The migration process will create a backup of the wallet before migrating. This <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> + <translation type="unfinished">Открытие кошелька</translation> </message> <message> <source>Opening Wallet <b>%1</b>…</source> @@ -1194,7 +1099,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <source>Restore Wallet</source> <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment> - <translation type="unfinished">Восстановить кошелёк</translation> + <translation type="unfinished">Восстановление кошелька</translation> </message> <message> <source>Restoring Wallet <b>%1</b>…</source> @@ -1204,7 +1109,7 @@ The migration process will create a backup of the wallet before migrating. This <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> + <translation type="unfinished">Не удалось восстановить кошелёк</translation> </message> <message> <source>Restore wallet warning</source> @@ -1251,7 +1156,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Wallet Name</source> - <translation type="unfinished">Название кошелька</translation> + <translation type="unfinished">Имя кошелька</translation> </message> <message> <source>Wallet</source> @@ -1271,7 +1176,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> - <translation type="unfinished">Отключить приватные ключи для этого кошелька. В кошельках с отключёнными приватными ключами не сохраняются приватные ключи, в них нельзя создать HD мастер-ключ или импортировать приватные ключи. Это удобно для наблюдающих кошельков.</translation> + <translation type="unfinished">Отключить приватные ключи для этого кошелька. В кошельках с отключёнными приватными ключами не сохраняются приватные ключи, в них нельзя создать HD мастер-ключ или импортировать приватные ключи. Это отличный вариант для кошельков для наблюдения за балансом.</translation> </message> <message> <source>Disable Private Keys</source> @@ -1291,7 +1196,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>External signer</source> - <translation type="unfinished">Внешняя подписывающая сторона</translation> + <translation type="unfinished">Внешний подписант</translation> </message> <message> <source>Create</source> @@ -1339,15 +1244,15 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>The entered address "%1" is not a valid Bitcoin address.</source> - <translation type="unfinished">Введенный адрес "%1" недействителен в сети Биткоин.</translation> + <translation type="unfinished">Введенный адрес "%1" не является действительным биткоин-адресом.</translation> </message> <message> <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> - <translation type="unfinished">Адрес "%1" уже существует как адрес получателя с именем "%2", и поэтому не может быть добавлен как адрес отправителя.</translation> + <translation type="unfinished">Адрес "%1" уже существует в качестве адреса для получения с меткой "%2" и поэтому не может быть добавлен в качестве адреса для отправки.</translation> </message> <message> <source>The entered address "%1" is already in the address book with label "%2".</source> - <translation type="unfinished">Введенный адрес "%1" уже существует в адресной книге под именем "%2".</translation> + <translation type="unfinished">Введённый адрес "%1" уже существует в адресной книге с меткой "%2".</translation> </message> <message> <source>Could not unlock wallet.</source> @@ -1365,10 +1270,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1386,7 +1287,7 @@ The migration process will create a backup of the wallet before migrating. This <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform>%n ГБ места доступен</numerusform> + <numerusform>%n ГБ места доступно</numerusform> <numerusform>%n ГБ места доступно</numerusform> <numerusform>%n ГБ места доступно</numerusform> </translation> @@ -1430,7 +1331,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>%1 will download and store a copy of the Bitcoin block chain.</source> - <translation type="unfinished">%1 загрузит и сохранит копию цепочки блоков Bitcoin.</translation> + <translation type="unfinished">%1 скачает и сохранит копию цепочки блоков Bitcoin.</translation> </message> <message> <source>The wallet will also be stored in this directory.</source> @@ -1438,7 +1339,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Error: Specified data directory "%1" cannot be created.</source> - <translation type="unfinished">Ошибка: невозможно создать указанный каталог данных "%1".</translation> + <translation type="unfinished">Ошибка: не удалось создать указанный каталог данных "%1".</translation> </message> <message> <source>Error</source> @@ -1482,7 +1383,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Use the default data directory</source> - <translation type="unfinished">Использовать стандартный каталог данных</translation> + <translation type="unfinished">Использовать каталог данных по умолчанию</translation> </message> <message> <source>Use a custom data directory:</source> @@ -1497,11 +1398,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>About %1</source> - <translation type="unfinished">О %1</translation> + <translation type="unfinished">О программе %1</translation> </message> <message> <source>Command-line options</source> - <translation type="unfinished">Опции командной строки</translation> + <translation type="unfinished">Параметры командной строки</translation> </message> </context> <context> @@ -1512,22 +1413,18 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">Не выключайте компьютер, пока это окно не пропадёт.</translation> + <translation type="unfinished">Не выключайте компьютер, пока это окно не исчезнет.</translation> </message> </context> <context> <name>ModalOverlay</name> <message> - <source>Form</source> - <translation type="unfinished">Форма</translation> - </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> + <translation type="unfinished">Попытка потратить средства, использованные в транзакциях, которые ещё не синхронизированы, будет отклонена сетью.</translation> </message> <message> <source>Number of blocks left</source> @@ -1562,16 +1459,12 @@ The migration process will create a backup of the wallet before migrating. This <translation type="unfinished">Скрыть</translation> </message> <message> - <source>Esc</source> - <translation type="unfinished">Выход</translation> - </message> - <message> <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> <translation type="unfinished">%1 в настоящий момент синхронизируется. Заголовки и блоки будут скачиваться с других узлов сети и проверяться до тех пор, пока не будет достигнут конец цепочки блоков.</translation> </message> <message> <source>Unknown. Syncing Headers (%1, %2%)…</source> - <translation type="unfinished">Неизвестно. Синхронизируются заголовки (%1, %2%)…</translation> + <translation type="unfinished">Неизвестно. Синхронизация заголовков (%1, %2%)…</translation> </message> <message> <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> @@ -1602,7 +1495,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">Автоматически запускать %1после входа в систему.</translation> + <translation type="unfinished">Автоматически запускать %1 после входа в систему.</translation> </message> <message> <source>&Start %1 on system login</source> @@ -1626,7 +1519,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> - <translation type="unfinished">IP-адрес прокси (к примеру, IPv4: 127.0.0.1 / IPv6: ::1)</translation> + <translation type="unfinished">IP-адрес прокси-сервера (к примеру, IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> <message> <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> @@ -1637,6 +1530,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> @@ -1719,10 +1616,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1866,7 +1759,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>&Cancel</source> - <translation type="unfinished">О&тмена</translation> + <translation type="unfinished">&Отмена</translation> </message> <message> <source>Compiled without external signing support (required for external signing)</source> @@ -1889,7 +1782,7 @@ The migration process will create a backup of the wallet before migrating. This <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> + <translation type="unfinished">Для применения изменений требуется перезапуск клиента.</translation> </message> <message> <source>Client will be shut down. Do you want to proceed?</source> @@ -1941,10 +1834,6 @@ The migration process will create a backup of the wallet before migrating. This <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">Отображаемая информация может быть устаревшей. Ваш кошелёк автоматически синхронизируется с сетью Bitcoin после подключения, и этот процесс пока не завершён.</translation> </message> @@ -2008,1104 +1897,35 @@ The migration process will create a backup of the wallet before migrating. This <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">Подписать транзакцию</translation> - </message> - <message> - <source>Broadcast Tx</source> - <translation type="unfinished">Отправить транзакцию</translation> - </message> - <message> - <source>Copy to Clipboard</source> - <translation type="unfinished">Скопировать в буфер обмена</translation> - </message> - <message> - <source>Save…</source> - <translation type="unfinished">Сохранить…</translation> - </message> - <message> - <source>Close</source> - <translation type="unfinished">Закрыть</translation> - </message> - <message> - <source>Failed to load transaction: %1</source> - <translation type="unfinished">Не удалось загрузить транзакцию: %1</translation> - </message> - <message> - <source>Failed to sign transaction: %1</source> - <translation type="unfinished">Не удалось подписать транзакцию: %1</translation> - </message> - <message> - <source>Cannot sign inputs while wallet is locked.</source> - <translation type="unfinished">Невозможно подписать входы пока кошелёк заблокирован.</translation> - </message> - <message> - <source>Could not sign any more inputs.</source> - <translation type="unfinished">Не удалось подписать оставшиеся входы.</translation> - </message> - <message> - <source>Signed %1 inputs, but more signatures are still required.</source> - <translation type="unfinished">Подписано %1 входов, но требуется больше подписей.</translation> - </message> - <message> - <source>Signed transaction successfully. Transaction is ready to broadcast.</source> - <translation type="unfinished">Транзакция успешно подписана. Транзакция готова к отправке.</translation> - </message> - <message> - <source>Unknown error processing transaction.</source> - <translation type="unfinished">Неизвестная ошибка во время обработки транзакции.</translation> - </message> - <message> - <source>Transaction broadcast successfully! Transaction ID: %1</source> - <translation type="unfinished">Транзакция успешно отправлена! Идентификатор транзакции: %1</translation> - </message> - <message> - <source>Transaction broadcast failed: %1</source> - <translation type="unfinished">Отправка транзакции не удалась: %1</translation> - </message> - <message> - <source>PSBT copied to clipboard.</source> - <translation type="unfinished">PSBT скопирована в буфер обмена.</translation> - </message> - <message> - <source>Save Transaction Data</source> - <translation type="unfinished">Сохранить данные о транзакции</translation> - </message> - <message> - <source>Partially Signed Transaction (Binary)</source> - <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment> - <translation type="unfinished">Частично подписанная транзакция (двоичный файл)</translation> - </message> - <message> - <source>PSBT saved to disk.</source> - <translation type="unfinished">PSBT сохранена на диск.</translation> - </message> - <message> - <source>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">Не удаётся запустить обработчик click-to-pay для протокола bitcoin</translation> - </message> - <message> - <source>URI handling</source> - <translation type="unfinished">Обработка URI</translation> - </message> - <message> - <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> - <translation type="unfinished">"bitcoin://" — это неверный URI. Используйте вместо него "bitcoin:".</translation> - </message> - <message> - <source>Cannot process payment request because BIP70 is not supported. -Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored. -If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> - <translation type="unfinished">Не удалось обработать транзакцию, потому что BIP70 не поддерживается. -Из-за широко распространённых уязвимостей в BIP70, настоятельно рекомендуется игнорировать любые инструкции продавцов сменить кошелёк. -Если вы получили эту ошибку, вам следует попросить у продавца URI, совместимый с BIP21.</translation> - </message> - <message> - <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> - <translation type="unfinished">Не удалось обработать URI! Это может быть вызвано тем, что биткоин-адрес неверен или параметры URI сформированы неправильно.</translation> - </message> - <message> - <source>Payment request file handling</source> - <translation type="unfinished">Обработка файла с запросом платежа</translation> - </message> -</context> -<context> - <name>PeerTableModel</name> - <message> - <source>User Agent</source> - <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment> - <translation type="unfinished">Пользовательский агент</translation> - </message> - <message> - <source>Ping</source> - <extracomment>Title of Peers Table column which indicates the current latency of the connection with the peer.</extracomment> - <translation type="unfinished">Пинг</translation> - </message> - <message> - <source>Peer</source> - <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment> - <translation type="unfinished">Узел</translation> - </message> - <message> - <source>Age</source> - <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment> - <translation type="unfinished">Возраст</translation> - </message> - <message> - <source>Direction</source> - <extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment> - <translation type="unfinished">Направление</translation> - </message> - <message> - <source>Sent</source> - <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment> - <translation type="unfinished">Отправлено</translation> - </message> - <message> - <source>Received</source> - <extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment> - <translation type="unfinished">Получено</translation> - </message> - <message> - <source>Address</source> - <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment> - <translation type="unfinished">Адрес</translation> - </message> - <message> - <source>Type</source> - <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment> - <translation type="unfinished">Тип</translation> - </message> - <message> - <source>Network</source> - <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment> - <translation type="unfinished">Сеть</translation> - </message> - <message> - <source>Inbound</source> - <extracomment>An Inbound Connection from a Peer.</extracomment> - <translation type="unfinished">Входящий</translation> - </message> - <message> - <source>Outbound</source> - <extracomment>An Outbound Connection to a Peer.</extracomment> - <translation type="unfinished">Исходящий</translation> - </message> -</context> -<context> - <name>QRImageWidget</name> - <message> - <source>&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">Ошибка преобразования URI в QR-код.</translation> - </message> - <message> - <source>QR code support not available.</source> - <translation type="unfinished">Поддержка QR-кодов недоступна.</translation> - </message> - <message> - <source>Save QR Code</source> - <translation type="unfinished">Сохранить QR-код</translation> - </message> - <message> - <source>PNG Image</source> - <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment> - <translation type="unfinished">Изображение PNG</translation> - </message> -</context> + </context> <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> - <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 в шестнадцатеричном формате, если таковой имеется.</translation> - </message> - <message> - <source>Session ID</source> - <translation type="unfinished">ID сессии</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">Подключённая АС</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> + <source>Node window - [%1]</source> + <translation type="unfinished">Окно ноды - [%1]</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</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">Время с момента принятия новой транзакции в наш mempool от этого узла.</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>&Open</source> - <translation type="unfinished">&Открыть</translation> - </message> - <message> - <source>&Console</source> - <translation type="unfinished">&Консоль</translation> - </message> - <message> - <source>&Network Traffic</source> - <translation type="unfinished">&Сетевой трафик</translation> - </message> - <message> - <source>Totals</source> - <translation type="unfinished">Всего</translation> - </message> - <message> - <source>Debug log file</source> - <translation type="unfinished">Файл журнала отладки</translation> - </message> - <message> - <source>Clear console</source> - <translation type="unfinished">Очистить консоль</translation> - </message> - <message> - <source>In:</source> - <translation type="unfinished">Вход:</translation> - </message> - <message> - <source>Out:</source> - <translation type="unfinished">Выход:</translation> - </message> - <message> - <source>Inbound: initiated by peer</source> - <extracomment>Explanatory text for an inbound peer connection.</extracomment> - <translation type="unfinished">Входящее: инициировано узлом</translation> - </message> - <message> - <source>Outbound Full Relay: default</source> - <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment> - <translation type="unfinished">Исходящий полный ретранслятор: по умолчанию</translation> - </message> - <message> - <source>Outbound Block Relay: does not relay transactions or addresses</source> - <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment> - <translation type="unfinished">Исходящий ретранслятор блоков: не ретранслирует транзакции или адреса</translation> - </message> - <message> - <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> - <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment> - <translation type="unfinished">Исходящий ручной: добавлен через RPC %1 или опции конфигурации %2/%3</translation> - </message> - <message> - <source>Outbound Feeler: short-lived, for testing addresses</source> - <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment> - <translation type="unfinished">Исходящий пробный: короткое время жизни, для тестирования адресов</translation> - </message> - <message> - <source>Outbound Address Fetch: short-lived, for soliciting addresses</source> - <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment> - <translation type="unfinished">Исходящий для получения адресов: короткое время жизни, для запроса адресов</translation> - </message> - <message> - <source>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> - </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 или маску подсети</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>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">Добро пожаловать в RPC-консоль %1. -Используйте стрелки вверх и вниз, чтобы перемещаться по истории и %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>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> - <message> - <source>Could not generate new %1 address</source> - <translation type="unfinished">Не удалось сгенерировать новый %1 адрес</translation> - </message> -</context> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Request payment to …</source> - <translation type="unfinished">Запросить платёж на …</translation> - </message> - <message> - <source>Address:</source> - <translation type="unfinished">Адрес:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">Сумма:</translation> - </message> - <message> - <source>Label:</source> - <translation type="unfinished">Метка:</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">Сообщение:</translation> - </message> - <message> <source>Wallet:</source> <translation type="unfinished">Кошелёк:</translation> </message> - <message> - <source>Copy &URI</source> - <translation type="unfinished">Копировать &URI</translation> - </message> - <message> - <source>Copy &Address</source> - <translation type="unfinished">Копировать &адрес</translation> - </message> - <message> - <source>&Verify</source> - <translation type="unfinished">&Проверить</translation> - </message> - <message> - <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">Проверьте адрес на, к примеру, экране аппаратного кошелька</translation> - </message> - <message> - <source>&Save Image…</source> - <translation type="unfinished">&Сохранить изображение…</translation> - </message> - <message> - <source>Payment information</source> - <translation type="unfinished">Информация о платеже</translation> - </message> - <message> - <source>Request payment to %1</source> - <translation type="unfinished">Запросить платёж на %1</translation> - </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> - <source>Date</source> - <translation type="unfinished">Дата</translation> - </message> - <message> - <source>Label</source> - <translation type="unfinished">Метка</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">Сообщение</translation> - </message> - <message> <source>(no label)</source> <translation type="unfinished">(нет метки)</translation> </message> - <message> - <source>(no message)</source> - <translation type="unfinished">(нет сообщения)</translation> - </message> - <message> - <source>(no amount requested)</source> - <translation type="unfinished">(сумма не указана)</translation> - </message> - <message> - <source>Requested</source> - <translation type="unfinished">Запрошено</translation> - </message> -</context> + </context> <context> <name>SendCoinsDialog</name> <message> - <source>Send Coins</source> - <translation type="unfinished">Отправить монеты</translation> - </message> - <message> - <source>Coin Control Features</source> - <translation type="unfinished">Функции управления монетами</translation> - </message> - <message> - <source>automatically selected</source> - <translation type="unfinished">выбираются автоматически</translation> - </message> - <message> - <source>Insufficient funds!</source> - <translation type="unfinished">Недостаточно средств!</translation> - </message> - <message> - <source>Quantity:</source> - <translation type="unfinished">Количество:</translation> - </message> - <message> - <source>Bytes:</source> - <translation type="unfinished">Байтов:</translation> - </message> - <message> - <source>Amount:</source> - <translation type="unfinished">Сумма:</translation> - </message> - <message> - <source>Fee:</source> - <translation type="unfinished">Комиссия:</translation> - </message> - <message> - <source>After Fee:</source> - <translation type="unfinished">После комиссии:</translation> - </message> - <message> - <source>Change:</source> - <translation type="unfinished">Сдача:</translation> - </message> - <message> - <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> - <translation type="unfinished">Если это выбрано, но адрес для сдачи пустой или неверный, сдача будет отправлена на новый сгенерированный адрес.</translation> - </message> - <message> - <source>Custom change address</source> - <translation type="unfinished">Указать адрес для сдачи</translation> - </message> - <message> - <source>Transaction Fee:</source> - <translation type="unfinished">Комиссия за транзакцию:</translation> - </message> - <message> - <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> - <translation type="unfinished">Использование комиссии по умолчанию может привести к отправке транзакции, для подтверждения которой потребуется несколько часов или дней (или которая никогда не подтвердится). Рекомендуется указать комиссию вручную или подождать, пока не закончится проверка всей цепочки блоков.</translation> - </message> - <message> - <source>Warning: Fee estimation is currently not possible.</source> - <translation type="unfinished">Предупреждение: расчёт комиссии в данный момент невозможен.</translation> - </message> - <message> - <source>per kilobyte</source> - <translation type="unfinished">за килобайт</translation> - </message> - <message> - <source>Hide</source> - <translation type="unfinished">Скрыть</translation> - </message> - <message> - <source>Recommended:</source> - <translation type="unfinished">Рекомендованное значение:</translation> - </message> - <message> - <source>Custom:</source> - <translation type="unfinished">Пользовательское значение:</translation> - </message> - <message> - <source>Send to multiple recipients at once</source> - <translation type="unfinished">Отправить нескольким получателям сразу</translation> - </message> - <message> - <source>Add &Recipient</source> - <translation type="unfinished">Добавить &получателя</translation> - </message> - <message> - <source>Clear all fields of the form.</source> - <translation type="unfinished">Очистить все поля формы.</translation> - </message> - <message> - <source>Inputs…</source> - <translation type="unfinished">Входы…</translation> - </message> - <message> - <source>Choose…</source> - <translation type="unfinished">Выбрать…</translation> - </message> - <message> - <source>Hide transaction fee settings</source> - <translation type="unfinished">Скрыть настройки комиссий</translation> - </message> - <message> - <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. - -Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">Укажите пользовательскую комиссию за КБ (1000 байт) виртуального размера транзакции. - -Примечание: комиссия рассчитывается пропорционально размеру в байтах. Так при комиссии "100 сатоши за kvB (виртуальный КБ)" для транзакции размером 500 виртуальных байт (половина 1 kvB) комиссия будет всего 50 сатоши.</translation> - </message> - <message> - <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> - <translation type="unfinished">Когда объём транзакций меньше, чем пространство в блоках, майнеры и ретранслирующие узлы могут устанавливать минимальную комиссию. Платить только эту минимальную комиссию вполне допустимо, но примите во внимание, что ваша транзакция может никогда не подтвердиться, если транзакций окажется больше, чем может обработать сеть.</translation> - </message> - <message> - <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation type="unfinished">Слишком низкая комиссия может привести к невозможности подтверждения транзакции (см. подсказку)</translation> - </message> - <message> - <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> - <translation type="unfinished">(Умная комиссия пока не инициализирована. Обычно для этого требуется несколько блоков…)</translation> - </message> - <message> - <source>Confirmation time target:</source> - <translation type="unfinished">Целевое время подтверждения:</translation> - </message> - <message> - <source>Enable Replace-By-Fee</source> - <translation type="unfinished">Включить Replace-By-Fee</translation> - </message> - <message> - <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> - <translation type="unfinished">С помощью Replace-By-Fee (BIP-125) вы можете увеличить комиссию после отправки транзакции. Если вы выключите эту опцию, рекомендуется увеличить комиссию перед отправкой, чтобы снизить риск задержки транзакции.</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">Очистить &всё</translation> - </message> - <message> - <source>Balance:</source> - <translation type="unfinished">Баланс:</translation> - </message> - <message> - <source>Confirm the send action</source> - <translation type="unfinished">Подтвердить отправку</translation> - </message> - <message> - <source>S&end</source> - <translation type="unfinished">&Отправить</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">Копировать количество</translation> </message> @@ -3114,833 +1934,70 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <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 (%2 blocks)</source> - <translation type="unfinished">%1 (%2 блоков)</translation> - </message> - <message> - <source>Sign on device</source> - <extracomment>"device" usually means a hardware wallet.</extracomment> - <translation type="unfinished">Подтвердите на устройстве</translation> - </message> - <message> - <source>Connect your hardware wallet first.</source> - <translation type="unfinished">Сначала подключите ваш аппаратный кошелёк.</translation> - </message> - <message> - <source>Set external signer script path in Options -> 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> - <message> - <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation type="unfinished">Создает частично подписанную биткоин-транзакцию (PSBT), чтобы использовать её, например, с офлайновым кошельком %1, или PSBT-совместимым аппаратным кошельком.</translation> - </message> - <message> - <source>%1 to '%2'</source> - <translation type="unfinished">%1 на "%2"</translation> - </message> - <message> - <source>%1 to %2</source> - <translation type="unfinished">%1 на %2</translation> - </message> - <message> - <source>To review recipient list click "Show Details…"</source> - <translation type="unfinished">Чтобы просмотреть список получателей, нажмите "Показать подробности…"</translation> - </message> - <message> - <source>Sign failed</source> - <translation type="unfinished">Не удалось подписать</translation> - </message> - <message> - <source>External signer not found</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Внешний скрипт подписи не найден</translation> - </message> - <message> - <source>External signer failure</source> - <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Внешний скрипта подписи вернул ошибку</translation> - </message> - <message> - <source>Save Transaction Data</source> - <translation type="unfinished">Сохранить данные о транзакции</translation> - </message> - <message> - <source>Partially Signed Transaction (Binary)</source> - <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment> - <translation type="unfinished">Частично подписанная транзакция (двоичный файл)</translation> - </message> - <message> - <source>PSBT saved</source> - <extracomment>Popup message when a PSBT has been saved to a file</extracomment> - <translation type="unfinished">PSBT сохранена</translation> - </message> - <message> - <source>External balance:</source> - <translation type="unfinished">Внешний баланс:</translation> - </message> - <message> - <source>or</source> - <translation type="unfinished">или</translation> - </message> - <message> - <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> - <translation type="unfinished">Вы можете увеличить комиссию позже (используется Replace-By-Fee, BIP-125).</translation> - </message> - <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> - <translation type="unfinished">Пожалуйста, проверьте черновик вашей транзакции. Будет создана частично подписанная биткоин-транзакция (PSBT), которую можно сохранить или скопировать, после чего подписать, например, офлайновым кошельком %1 или PSBT-совместимым аппаратным кошельком.</translation> - </message> - <message> - <source>Do you want to create this transaction?</source> - <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment> - <translation type="unfinished">Вы хотите создать эту транзакцию?</translation> - </message> - <message> - <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment> - <translation type="unfinished">Пожалуйста, проверьте вашу транзакцию. Вы можете создать и отправить эту транзакцию, либо создать частично подписанную биткоин-транзакцию (PSBT), которую можно сохранить или скопировать, после чего подписать, например, офлайновым кошельком %1 или PSBT-совместимым аппаратным кошельком.</translation> - </message> - <message> - <source>Please, review your transaction.</source> - <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment> - <translation type="unfinished">Пожалуйста, проверьте вашу транзакцию.</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">Комиссия за транзакцию</translation> - </message> - <message> - <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation type="unfinished">Не используется Replace-By-Fee, BIP-125.</translation> - </message> - <message> - <source>Total Amount</source> - <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> - <message> - <source>Watch-only balance:</source> - <translation type="unfinished">Баланс только для просмотра:</translation> - </message> - <message> - <source>The recipient address is not valid. Please recheck.</source> - <translation type="unfinished">Адрес получателя неверный. Пожалуйста, перепроверьте.</translation> - </message> - <message> - <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">Сумма оплаты должна быть больше 0.</translation> - </message> - <message> - <source>The amount exceeds your balance.</source> - <translation type="unfinished">Сумма превышает ваш баланс.</translation> - </message> - <message> - <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation type="unfinished">Итоговая сумма с учётом комиссии %1 превышает ваш баланс.</translation> - </message> - <message> - <source>Duplicate address found: addresses should only be used once each.</source> - <translation type="unfinished">Обнаружен дублирующийся адрес: используйте каждый адрес только один раз.</translation> - </message> - <message> - <source>Transaction creation failed!</source> - <translation type="unfinished">Не удалось создать транзакцию!</translation> - </message> - <message> - <source>A fee higher than %1 is considered an absurdly high fee.</source> - <translation type="unfinished">Комиссия более %1 считается абсурдно высокой.</translation> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1из кошелька '%2'</translation> </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform>Подтверждение ожидается через %n блок.</numerusform> - <numerusform>Подтверждение ожидается через %n блока.</numerusform> - <numerusform>Подтверждение ожидается через %n блоков.</numerusform> + <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> + <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> + <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> </translation> </message> <message> - <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished">Внимание: неверный биткоин-адрес</translation> - </message> - <message> - <source>Warning: Unknown change address</source> - <translation type="unfinished">Внимание: неизвестный адрес сдачи</translation> - </message> - <message> - <source>Confirm custom change address</source> - <translation type="unfinished">Подтвердите указанный адрес для сдачи</translation> - </message> - <message> - <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> - <translation type="unfinished">Выбранный вами адрес для сдачи не принадлежит этому кошельку. Часть средств, а то и всё содержимое вашего кошелька будет отправлено на этот адрес. Вы уверены в своих действиях?</translation> - </message> - <message> <source>(no label)</source> <translation type="unfinished">(нет метки)</translation> </message> </context> <context> - <name>SendCoinsEntry</name> - <message> - <source>A&mount:</source> - <translation type="unfinished">&Сумма:</translation> - </message> - <message> - <source>Pay &To:</source> - <translation type="unfinished">&Отправить на:</translation> - </message> - <message> - <source>&Label:</source> - <translation type="unfinished">&Метка:</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">Выбрать ранее использованный адрес</translation> - </message> - <message> - <source>The Bitcoin address to send the payment to</source> - <translation type="unfinished">Биткоин-адрес, на который нужно отправить платёж</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">Вставить адрес из буфера обмена</translation> - </message> - <message> - <source>Remove this entry</source> - <translation type="unfinished">Удалить эту запись</translation> - </message> - <message> - <source>The amount to send in the selected unit</source> - <translation type="unfinished">Сумма к отправке в выбранных единицах</translation> - </message> - <message> - <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source> - <translation type="unfinished">Комиссия будет вычтена из отправляемой суммы. Получателю придёт меньше биткоинов, чем вы ввели в поле "Сумма". Если выбрано несколько получателей, комиссия распределится поровну.</translation> - </message> - <message> - <source>S&ubtract fee from amount</source> - <translation type="unfinished">В&ычесть комиссию из суммы</translation> - </message> - <message> - <source>Use available balance</source> - <translation type="unfinished">Весь доступный баланс</translation> - </message> - <message> - <source>Message:</source> - <translation type="unfinished">Сообщение:</translation> - </message> - <message> - <source>Enter a label for this address to add it to the list of used addresses</source> - <translation type="unfinished">Введите метку для этого адреса, чтобы добавить его в список использованных адресов</translation> - </message> - <message> - <source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source> - <translation type="unfinished">Сообщение, которое было прикреплено к URI. Оно будет сохранено вместе с транзакцией для вашего удобства. Обратите внимание: это сообщение не будет отправлено в сеть Bitcoin.</translation> - </message> -</context> -<context> - <name>SendConfirmationDialog</name> - <message> - <source>Send</source> - <translation type="unfinished">Отправить</translation> - </message> - <message> - <source>Create Unsigned</source> - <translation type="unfinished">Создать без подписи</translation> - </message> -</context> -<context> <name>SignVerifyMessageDialog</name> <message> - <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">Подписи - подписать / проверить сообщение</translation> - </message> - <message> - <source>&Sign Message</source> - <translation type="unfinished">&Подписать сообщение</translation> - </message> - <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">Вы можете подписывать сообщения/соглашения своими адресами, чтобы доказать, что вы можете получать биткоины на них. Будьте осторожны и не подписывайте непонятные или случайные сообщения, так как мошенники могут таким образом пытаться присвоить вашу личность. Подписывайте только такие сообщения, с которыми вы согласны вплоть до мелочей.</translation> - </message> - <message> - <source>The Bitcoin address to sign the message with</source> - <translation type="unfinished">Биткоин-адрес, которым подписать сообщение</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation type="unfinished">Выбрать ранее использованный адрес</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation type="unfinished">Вставить адрес из буфера обмена</translation> + <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">Вы можете подписывать сообщения/соглашения своими устаревшими (P2PKH) адресами, чтобы доказать, что вы можете получать биткоины на них. Будьте осторожны и не подписывайте непонятные или случайные сообщения, так как мошенники могут таким образом пытаться присвоить вашу личность. Подписывайте только такие сообщения, с которыми вы согласны вплоть до мелочей.</translation> </message> <message> - <source>Enter the message you want to sign here</source> - <translation type="unfinished">Введите здесь сообщение, которое вы хотите подписать</translation> + <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">Введенный адрес не относится к устаревшему (P2PKH) ключу. Подписывание сообщений для SegWit и других не--P2PKH типов адресов не поддерживается в этой версии %1. Пожалуйста, проверьте адрес и попробуйте ещё раз.</translation> </message> - <message> - <source>Signature</source> - <translation type="unfinished">Подпись</translation> - </message> - <message> - <source>Copy the current signature to the system clipboard</source> - <translation type="unfinished">Скопировать текущую подпись в буфер обмена</translation> - </message> - <message> - <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">Подписать сообщение, чтобы доказать владение биткоин-адресом</translation> - </message> - <message> - <source>Sign &Message</source> - <translation type="unfinished">Подписать &сообщение</translation> - </message> - <message> - <source>Reset all sign message fields</source> - <translation type="unfinished">Сбросить значения всех полей</translation> - </message> - <message> - <source>Clear &All</source> - <translation type="unfinished">Очистить &всё</translation> - </message> - <message> - <source>&Verify Message</source> - <translation type="unfinished">П&роверить сообщение</translation> - </message> - <message> - <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source> - <translation type="unfinished">Введите ниже адрес получателя, сообщение (убедитесь, что переводы строк, пробелы, знаки табуляции и т.п. скопированы в точности) и подпись, чтобы проверить сообщение. Не придавайте сообщению большего смысла, чем в нём содержится, чтобы не стать жертвой атаки "человек посередине". Обратите внимание, что подпись доказывает лишь то, что подписавший может получать биткоины на этот адрес, но никак не то, что он отправил какую-либо транзакцию!</translation> - </message> - <message> - <source>The Bitcoin address the message was signed with</source> - <translation type="unfinished">Биткоин-адрес, которым было подписано сообщение</translation> - </message> - <message> - <source>The signed message to verify</source> - <translation type="unfinished">Подписанное сообщение для проверки</translation> - </message> - <message> - <source>The signature given when the message was signed</source> - <translation type="unfinished">Подпись, созданная при подписании сообщения</translation> - </message> - <message> - <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation type="unfinished">Проверить сообщение, чтобы убедиться, что оно действительно подписано указанным биткоин-адресом</translation> - </message> - <message> - <source>Verify &Message</source> - <translation type="unfinished">Проверить &сообщение</translation> - </message> - <message> - <source>Reset all verify message fields</source> - <translation type="unfinished">Сбросить все поля проверки сообщения</translation> - </message> - <message> - <source>Click "Sign Message" to generate signature</source> - <translation type="unfinished">Нажмите "Подписать сообщение" для создания подписи</translation> - </message> - <message> - <source>The entered address is invalid.</source> - <translation type="unfinished">Введенный адрес недействителен.</translation> - </message> - <message> - <source>Please check the address and try again.</source> - <translation type="unfinished">Проверьте адрес и попробуйте ещё раз.</translation> - </message> - <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Введённый адрес не связан с ключом.</translation> - </message> - <message> - <source>Wallet unlock was cancelled.</source> - <translation type="unfinished">Разблокирование кошелька было отменено.</translation> - </message> - <message> - <source>No error</source> - <translation type="unfinished">Без ошибок</translation> - </message> - <message> - <source>Private key for the entered address is not available.</source> - <translation type="unfinished">Приватный ключ для введённого адреса недоступен.</translation> - </message> - <message> - <source>Message signing failed.</source> - <translation type="unfinished">Не удалось подписать сообщение.</translation> - </message> - <message> - <source>Message signed.</source> - <translation type="unfinished">Сообщение подписано.</translation> - </message> - <message> - <source>The signature could not be decoded.</source> - <translation type="unfinished">Невозможно декодировать подпись.</translation> - </message> - <message> - <source>Please check the signature and try again.</source> - <translation type="unfinished">Пожалуйста, проверьте подпись и попробуйте ещё раз.</translation> - </message> - <message> - <source>The signature did not match the message digest.</source> - <translation type="unfinished">Подпись не соответствует хэшу сообщения.</translation> - </message> - <message> - <source>Message verification failed.</source> - <translation type="unfinished">Сообщение не прошло проверку.</translation> - </message> - <message> - <source>Message verified.</source> - <translation type="unfinished">Сообщение проверено.</translation> - </message> -</context> -<context> - <name>SplashScreen</name> - <message> - <source>(press q to shutdown and continue later)</source> - <translation type="unfinished">(нажмите q, чтобы завершить работу и продолжить позже)</translation> - </message> - <message> - <source>press q to shutdown</source> - <translation type="unfinished">нажмите q для выключения</translation> - </message> -</context> -<context> - <name>TrafficGraphWidget</name> - <message> - <source>kB/s</source> - <translation type="unfinished">кБ/с</translation> - </message> -</context> + </context> <context> <name>TransactionDesc</name> - <message> - <source>conflicted with a transaction with %1 confirmations</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment> - <translation type="unfinished">конфликтует с транзакцией с %1 подтверждениями</translation> - </message> - <message> - <source>0/unconfirmed, in memory pool</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment> - <translation type="unfinished">0/нет подтверждений, в пуле памяти</translation> - </message> - <message> - <source>0/unconfirmed, not in memory pool</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment> - <translation type="unfinished">0/нет подтверждений, не в пуле памяти</translation> - </message> - <message> - <source>abandoned</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment> - <translation type="unfinished">отброшена</translation> - </message> - <message> - <source>%1/unconfirmed</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment> - <translation type="unfinished">%1/нет подтверждений</translation> - </message> - <message> - <source>%1 confirmations</source> - <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment> - <translation type="unfinished">%1 подтверждений</translation> - </message> - <message> - <source>Status</source> - <translation type="unfinished">Статус</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">Дата</translation> - </message> - <message> - <source>Source</source> - <translation type="unfinished">Источник</translation> - </message> - <message> - <source>Generated</source> - <translation type="unfinished">Сгенерировано</translation> - </message> - <message> - <source>From</source> - <translation type="unfinished">От кого</translation> - </message> - <message> - <source>unknown</source> - <translation type="unfinished">неизвестно</translation> - </message> - <message> - <source>To</source> - <translation type="unfinished">Кому</translation> - </message> - <message> - <source>own address</source> - <translation type="unfinished">свой адрес</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">наблюдаемый</translation> - </message> - <message> - <source>label</source> - <translation type="unfinished">метка</translation> - </message> - <message> - <source>Credit</source> - <translation type="unfinished">Кредит</translation> - </message> <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> - <numerusform>созреет через %n блок</numerusform> - <numerusform>созреет через %n блока</numerusform> - <numerusform>созреет через %n блоков</numerusform> + <numerusform>matures in %n more block(s)</numerusform> + <numerusform>matures in %n more block(s)</numerusform> + <numerusform>matures in %n more block(s)</numerusform> </translation> </message> <message> - <source>not accepted</source> - <translation type="unfinished">не принят</translation> - </message> - <message> - <source>Debit</source> - <translation type="unfinished">Дебет</translation> - </message> - <message> - <source>Total debit</source> - <translation type="unfinished">Итого дебет</translation> - </message> - <message> - <source>Total credit</source> - <translation type="unfinished">Итого кредит</translation> - </message> - <message> - <source>Transaction fee</source> - <translation type="unfinished">Комиссия за транзакцию</translation> - </message> - <message> - <source>Net amount</source> - <translation type="unfinished">Чистая сумма</translation> - </message> - <message> - <source>Message</source> - <translation type="unfinished">Сообщение</translation> - </message> - <message> - <source>Comment</source> - <translation type="unfinished">Комментарий</translation> - </message> - <message> - <source>Transaction ID</source> - <translation type="unfinished">Идентификатор транзакции</translation> - </message> - <message> - <source>Transaction total size</source> - <translation type="unfinished">Общий размер транзакции</translation> - </message> - <message> - <source>Transaction virtual size</source> - <translation type="unfinished">Виртуальный размер транзакции</translation> - </message> - <message> - <source>Output index</source> - <translation type="unfinished">Индекс выхода</translation> - </message> - <message> - <source>Merchant</source> - <translation type="unfinished">Продавец</translation> - </message> - <message> - <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> - <translation type="unfinished">Сгенерированные монеты должны созреть в течение %1 блоков, прежде чем смогут быть потрачены. Когда вы сгенерировали этот блок, он был отправлен в сеть для добавления в цепочку блоков. Если он не попадёт в цепочку, его статус изменится на "не принят", и монеты будут недействительны. Это иногда происходит в случае, если другой узел сгенерирует блок на несколько секунд раньше вас.</translation> - </message> - <message> - <source>Debug information</source> - <translation type="unfinished">Отладочная информация</translation> - </message> - <message> - <source>Transaction</source> - <translation type="unfinished">Транзакция</translation> - </message> - <message> - <source>Inputs</source> - <translation type="unfinished">Входы</translation> + <source>%1 (Certificate was not verified)</source> + <translation type="unfinished">%1 (Сертификат не был подтверждён)</translation> </message> <message> <source>Amount</source> <translation type="unfinished">Сумма</translation> </message> - <message> - <source>true</source> - <translation type="unfinished">истина</translation> - </message> - <message> - <source>false</source> - <translation type="unfinished">ложь</translation> - </message> -</context> -<context> - <name>TransactionDescDialog</name> - <message> - <source>This pane shows a detailed description of the transaction</source> - <translation type="unfinished">На этой панели показано подробное описание транзакции</translation> - </message> - <message> - <source>Details for %1</source> - <translation type="unfinished">Подробности по %1</translation> - </message> -</context> + </context> <context> <name>TransactionTableModel</name> <message> - <source>Date</source> - <translation type="unfinished">Дата</translation> - </message> - <message> - <source>Type</source> - <translation type="unfinished">Тип</translation> - </message> - <message> - <source>Label</source> - <translation type="unfinished">Метка</translation> - </message> - <message> - <source>Unconfirmed</source> - <translation type="unfinished">Не подтверждена</translation> - </message> - <message> - <source>Abandoned</source> - <translation type="unfinished">Отброшена</translation> - </message> - <message> - <source>Confirming (%1 of %2 recommended confirmations)</source> - <translation type="unfinished">Подтверждается (%1 из %2 рекомендуемых подтверждений)</translation> - </message> - <message> - <source>Confirmed (%1 confirmations)</source> - <translation type="unfinished">Подтверждена (%1 подтверждений)</translation> - </message> - <message> - <source>Conflicted</source> - <translation type="unfinished">Конфликтует</translation> - </message> - <message> - <source>Immature (%1 confirmations, will be available after %2)</source> - <translation type="unfinished">Незрелая (%1 подтверждений, будет доступно после %2)</translation> - </message> - <message> - <source>Generated but not accepted</source> - <translation type="unfinished">Сгенерирован, но не принят</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">Получено на</translation> - </message> - <message> - <source>Received from</source> - <translation type="unfinished">Получено от</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">Отправлено на</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">Добыто</translation> - </message> - <message> - <source>watch-only</source> - <translation type="unfinished">наблюдаемый</translation> - </message> - <message> - <source>(n/a)</source> - <translation type="unfinished">(н/д)</translation> - </message> - <message> <source>(no label)</source> <translation type="unfinished">(нет метки)</translation> </message> - <message> - <source>Transaction status. Hover over this field to show number of confirmations.</source> - <translation type="unfinished">Статус транзакции. Наведите курсор на это поле для отображения количества подтверждений.</translation> - </message> - <message> - <source>Date and time that the transaction was received.</source> - <translation type="unfinished">Дата и время получения транзакции.</translation> - </message> - <message> - <source>Type of transaction.</source> - <translation type="unfinished">Тип транзакции.</translation> - </message> - <message> - <source>Whether or not a watch-only address is involved in this transaction.</source> - <translation type="unfinished">Использовался ли в транзакции наблюдаемый адрес.</translation> - </message> - <message> - <source>User-defined intent/purpose of the transaction.</source> - <translation type="unfinished">Определяемое пользователем назначение/цель транзакции.</translation> - </message> - <message> - <source>Amount removed from or added to balance.</source> - <translation type="unfinished">Сумма, вычтенная из баланса или добавленная к нему.</translation> - </message> -</context> + </context> <context> <name>TransactionView</name> <message> - <source>All</source> - <translation type="unfinished">Все</translation> - </message> - <message> - <source>Today</source> - <translation type="unfinished">Сегодня</translation> - </message> - <message> - <source>This week</source> - <translation type="unfinished">На этой неделе</translation> - </message> - <message> - <source>This month</source> - <translation type="unfinished">В этом месяце</translation> - </message> - <message> - <source>Last month</source> - <translation type="unfinished">В прошлом месяце</translation> - </message> - <message> - <source>This year</source> - <translation type="unfinished">В этом году</translation> - </message> - <message> - <source>Received with</source> - <translation type="unfinished">Получено на</translation> - </message> - <message> - <source>Sent to</source> - <translation type="unfinished">Отправлено на</translation> - </message> - <message> - <source>Mined</source> - <translation type="unfinished">Добыто</translation> - </message> - <message> - <source>Other</source> - <translation type="unfinished">Другое</translation> - </message> - <message> - <source>Enter address, transaction id, or label to search</source> - <translation type="unfinished">Введите адрес, идентификатор транзакции, или метку для поиска</translation> - </message> - <message> - <source>Min amount</source> - <translation type="unfinished">Минимальная сумма</translation> - </message> - <message> - <source>Range…</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</source> - <translation type="unfinished">Копировать ID &транзакции</translation> - </message> - <message> - <source>Copy &raw transaction</source> - <translation type="unfinished">Копировать &исходный код транзакции</translation> - </message> - <message> - <source>Copy full transaction &details</source> - <translation type="unfinished">Копировать &все подробности транзакции</translation> - </message> - <message> - <source>&Show transaction details</source> - <translation type="unfinished">&Показать подробности транзакции</translation> - </message> - <message> - <source>Increase transaction &fee</source> - <translation type="unfinished">Увеличить комиссию</translation> - </message> - <message> - <source>A&bandon transaction</source> - <translation type="unfinished">&Отказ от транзакции</translation> - </message> - <message> - <source>&Edit address label</source> - <translation type="unfinished">&Изменить метку адреса</translation> - </message> - <message> - <source>Show in %1</source> - <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment> - <translation type="unfinished">Показать в %1</translation> - </message> - <message> - <source>Export Transaction History</source> - <translation type="unfinished">Экспортировать историю транзакций</translation> - </message> - <message> - <source>Comma separated file</source> - <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment> - <translation type="unfinished">Файл, разделенный запятыми</translation> - </message> - <message> - <source>Confirmed</source> - <translation type="unfinished">Подтверждена</translation> - </message> - <message> - <source>Watch-only</source> - <translation type="unfinished">Наблюдаемая</translation> - </message> - <message> - <source>Date</source> - <translation type="unfinished">Дата</translation> - </message> - <message> <source>Type</source> <translation type="unfinished">Тип</translation> </message> @@ -4068,9 +2125,8 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT скопирована</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Скопировано в буфер обмена</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">PSBT скопирована в буфер обмена.</translation> </message> <message> <source>Can't sign transaction.</source> @@ -4081,12 +2137,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Не удалось отправить транзакцию</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Не удалось отобразить адрес</translation> + <source>Signer error</source> + <translation type="unfinished">Ошибка подписи</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">кошелёк по умолчанию</translation> + <source>Can't display address</source> + <translation type="unfinished">Не удалось отобразить адрес</translation> </message> </context> <context> @@ -4110,7 +2166,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Backup Failed</source> - <translation type="unfinished">Резервное копирование не удалось</translation> + <translation type="unfinished">Создание резервной копии кошелька завершилось неудачей</translation> </message> <message> <source>There was an error trying to save the wallet data to %1.</source> @@ -4220,10 +2276,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Не указан формат файла кошелька. Чтобы использовать createfromdump, необходимо указать -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> - <translation type="unfinished">Пожалуйста, убедитесь, что на вашем компьютере верно установлены дата и время. Если ваши часы сбились, %s будет работать неправильно.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Пожалуйста, внесите свой вклад, если вы считаете %s полезным. Посетите %s для получения дополнительной информации о программном обеспечении.</translation> </message> @@ -4288,10 +2340,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Указан неизвестный формат файла кошелька "%s". Укажите "bdb" либо "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">Неподдерживаемый уровень регистрации по категориям %1$s=%2$s. Ожидается %1$s=<category>:<loglevel>. Допустимые категории: %3$s. Допустимые уровни регистрации: %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">Обнаружен неподдерживаемый формат базы данных состояния цепочки блоков. Пожалуйста, перезапустите программу с ключом -reindex-chainstate. Это перестроит базу данных состояния цепочки блоков.</translation> </message> @@ -4301,7 +2349,7 @@ Go to File > Open Wallet to load a wallet. </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">Кошелек успешно загружен. Устаревший тип кошелька, поддержка создания и открытия устаревших кошельков будет удалена в будущем. Устаревшие кошельки можно перенести на дескрипторный кошелек с помощью функции migratewallet.</translation> + <translation type="unfinished">Кошелёк успешно создан. Старый формат кошелька признан устаревшим. Поддержка создания кошелька в этом формате и его открытие в будущем будут удалены.</translation> </message> <message> <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> @@ -4332,10 +2380,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool должен быть минимум %d МБ</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Произошла критическая внутренняя ошибка, подробности в файле debug.log</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Не удается разрешить -%s адрес: "%s"</translation> </message> @@ -4349,7 +2393,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">Не удается выполнить запись в каталог данных "%s"; проверьте разрешения.</translation> + <translation type="unfinished">Не удается выполнить запись в каталог данных '%s'; проверьте разрешения.</translation> </message> <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> @@ -4388,10 +2432,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Не удалось переименовать файл peers.dat. Пожалуйста, переместите или удалите его и попробуйте снова.</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>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished">Несовместимые ключи: был явно указан -dnsseed=1, но -onlynet не разрешены соединения через IPv4/IPv6</translation> </message> @@ -4570,10 +2610,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">Ошибка: на диске недостаточно места для %s</translation> </message> <message> - <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> - <translation type="unfinished">Ошибка: контрольные суммы дамп-файла не совпадают. Вычислено %s, ожидалось %s</translation> - </message> - <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">Ошибка: не удалось создать кошелёк только на просмотр</translation> </message> @@ -4622,372 +2658,20 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">Ошибка: не удалось прочитать все записи из базе данных</translation> </message> <message> - <source>Error: Unable to remove watchonly address book data</source> - <translation type="unfinished">Ошибка: не удалось удалить данные из адресной книги только для наблюдения</translation> - </message> - <message> - <source>Error: Unable to write record to new wallet</source> - <translation type="unfinished">Ошибка: невозможно произвести запись в новый кошелёк</translation> - </message> - <message> - <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation type="unfinished">Не удалось открыть никакой порт на прослушивание. Используйте -listen=0, если вас это устроит.</translation> - </message> - <message> - <source>Failed to rescan the wallet during initialization</source> - <translation type="unfinished">Не удалось пересканировать кошелёк во время инициализации</translation> - </message> - <message> - <source>Failed to start indexes, shutting down..</source> - <translation type="unfinished">Не удалось запустить индексы, завершение работы...</translation> - </message> - <message> - <source>Failed to verify database</source> - <translation type="unfinished">Не удалось проверить базу данных</translation> - </message> - <message> - <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> - <translation type="unfinished">Уровень комиссии (%s) меньше, чем значение настройки минимального уровня комиссии (%s).</translation> - </message> - <message> - <source>Ignoring duplicate -wallet %s.</source> - <translation type="unfinished">Игнорируются повторные параметры -wallet %s.</translation> - </message> - <message> - <source>Importing…</source> - <translation type="unfinished">Импорт…</translation> - </message> - <message> - <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished">Неверный или отсутствующий начальный блок. Неверно указана директория данных для этой сети?</translation> - </message> - <message> - <source>Initialization sanity check failed. %s is shutting down.</source> - <translation type="unfinished">Начальная проверка исправности не удалась. %s завершает работу.</translation> - </message> - <message> - <source>Input not found or already spent</source> - <translation type="unfinished">Вход для тразакции не найден или уже использован</translation> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Не удалось отключить блок</translation> </message> <message> - <source>Insufficient dbcache for block verification</source> - <translation type="unfinished">Недостаточное значение dbcache для проверки блока</translation> + <source>Failed to read block.</source> + <translation type="unfinished">Не удалось прочитать блок</translation> </message> <message> - <source>Insufficient funds</source> - <translation type="unfinished">Недостаточно средств</translation> + <source>Failed to write block.</source> + <translation type="unfinished">Не удалось записать блок</translation> </message> <message> - <source>Invalid -i2psam address or hostname: '%s'</source> - <translation type="unfinished">Неверный адрес или имя хоста в -i2psam: "%s"</translation> + <source>Wallet file creation failed: %s</source> + <translation type="unfinished">Не удалось создать кошелёк 1%s</translation> </message> - <message> - <source>Invalid -onion address or hostname: '%s'</source> - <translation type="unfinished">Неверный -onion адрес или имя хоста: "%s"</translation> - </message> - <message> - <source>Invalid -proxy address or hostname: '%s'</source> - <translation type="unfinished">Неверный адрес -proxy или имя хоста: "%s"</translation> - </message> - <message> - <source>Invalid P2P permission: '%s'</source> - <translation type="unfinished">Неверные разрешения для P2P: "%s"</translation> - </message> - <message> - <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> - <translation type="unfinished">Неверное количество для %s=<amount>: '%s' (должно быть минимум %s)</translation> - </message> - <message> - <source>Invalid amount for %s=<amount>: '%s'</source> - <translation type="unfinished">Неверное количество для %s=<amount>: '%s'</translation> - </message> - <message> - <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation type="unfinished">Неверная сумма для -%s=<amount>: "%s"</translation> - </message> - <message> - <source>Invalid netmask specified in -whitelist: '%s'</source> - <translation type="unfinished">Указана неверная сетевая маска в -whitelist: "%s"</translation> - </message> - <message> - <source>Invalid port specified in %s: '%s'</source> - <translation type="unfinished">Неверный порт указан в %s: '%s'</translation> - </message> - <message> - <source>Invalid pre-selected input %s</source> - <translation type="unfinished">Недопустимый предварительно выбранный ввод %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> - <message> - <source>Loading banlist…</source> - <translation type="unfinished">Загрузка черного списка…</translation> - </message> - <message> - <source>Loading block index…</source> - <translation type="unfinished">Загрузка индекса блоков…</translation> - </message> - <message> - <source>Loading wallet…</source> - <translation type="unfinished">Загрузка кошелька…</translation> - </message> - <message> - <source>Missing amount</source> - <translation type="unfinished">Отсутствует сумма</translation> - </message> - <message> - <source>Missing solving data for estimating transaction size</source> - <translation type="unfinished">Недостаточно данных для оценки размера транзакции</translation> - </message> - <message> - <source>Need to specify a port with -whitebind: '%s'</source> - <translation type="unfinished">Необходимо указать порт с -whitebind: "%s"</translation> - </message> - <message> - <source>No addresses available</source> - <translation type="unfinished">Нет доступных адресов</translation> - </message> - <message> - <source>Not enough file descriptors available.</source> - <translation type="unfinished">Недостаточно доступных файловых дескрипторов.</translation> - </message> - <message> - <source>Not found pre-selected input %s</source> - <translation type="unfinished">Не найден предварительно выбранный ввод %s</translation> - </message> - <message> - <source>Not solvable pre-selected input %s</source> - <translation type="unfinished">Не решаемый заранее выбранный ввод %s</translation> - </message> - <message> - <source>Prune cannot be configured with a negative value.</source> - <translation type="unfinished">Обрезка блоков не может использовать отрицательное значение.</translation> - </message> - <message> - <source>Prune mode is incompatible with -txindex.</source> - <translation type="unfinished">Режим обрезки несовместим с -txindex.</translation> - </message> - <message> - <source>Pruning blockstore…</source> - <translation type="unfinished">Сокращение хранилища блоков…</translation> - </message> - <message> - <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> - <translation type="unfinished">Уменьшение -maxconnections с %d до %d из-за ограничений системы.</translation> - </message> - <message> - <source>Replaying blocks…</source> - <translation type="unfinished">Пересборка блоков…</translation> - </message> - <message> - <source>Rescanning…</source> - <translation type="unfinished">Повторное сканирование…</translation> - </message> - <message> - <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> - <translation type="unfinished">SQLiteDatabase: не удалось выполнить запрос для проверки базы данных: %s</translation> - </message> - <message> - <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> - <translation type="unfinished">SQLiteDatabase: не удалось подготовить запрос для проверки базы данных: %s</translation> - </message> - <message> - <source>SQLiteDatabase: Failed to read database verification error: %s</source> - <translation type="unfinished">SQLiteDatabase: ошибка при проверке базы данных: %s</translation> - </message> - <message> - <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> - <translation type="unfinished">SQLiteDatabase: неожиданный id приложения. Ожидалось %u, но получено %u</translation> - </message> - <message> - <source>Section [%s] is not recognized.</source> - <translation type="unfinished">Секция [%s] не распознана.</translation> - </message> - <message> - <source>Signing transaction failed</source> - <translation type="unfinished">Подписание транзакции не удалось</translation> - </message> - <message> - <source>Specified -walletdir "%s" does not exist</source> - <translation type="unfinished">Указанный -walletdir "%s" не существует</translation> - </message> - <message> - <source>Specified -walletdir "%s" is a relative path</source> - <translation type="unfinished">Указанный -walletdir "%s" является относительным путем</translation> - </message> - <message> - <source>Specified -walletdir "%s" is not a directory</source> - <translation type="unfinished">Указанный -walletdir "%s" не является каталогом</translation> - </message> - <message> - <source>Specified blocks directory "%s" does not exist.</source> - <translation type="unfinished">Указанный каталог блоков "%s" не существует.</translation> - </message> - <message> - <source>Specified data directory "%s" does not exist.</source> - <translation type="unfinished">Указанный каталог данных "%s" не существует.</translation> - </message> - <message> - <source>Starting network threads…</source> - <translation type="unfinished">Запуск сетевых потоков…</translation> - </message> - <message> - <source>The source code is available from %s.</source> - <translation type="unfinished">Исходный код доступен по адресу %s.</translation> - </message> - <message> - <source>The specified config file %s does not exist</source> - <translation type="unfinished">Указанный конфигурационный файл %s не существует</translation> - </message> - <message> - <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">Сумма транзакции слишком мала для уплаты комиссии</translation> - </message> - <message> - <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation type="unfinished">Кошелёк будет стараться платить не меньше минимальной комиссии для ретрансляции.</translation> - </message> - <message> - <source>This is experimental software.</source> - <translation type="unfinished">Это экспериментальное программное обеспечение.</translation> - </message> - <message> - <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation type="unfinished">Это минимальная комиссия, которую вы платите для любой транзакции.</translation> - </message> - <message> - <source>This is the transaction fee you will pay if you send a transaction.</source> - <translation type="unfinished">Это размер комиссии, которую вы заплатите при отправке транзакции.</translation> - </message> - <message> - <source>Transaction amount too small</source> - <translation type="unfinished">Размер транзакции слишком мал</translation> - </message> - <message> - <source>Transaction amounts must not be negative</source> - <translation type="unfinished">Сумма транзакции не должна быть отрицательной</translation> - </message> - <message> - <source>Transaction change output index out of range</source> - <translation type="unfinished">Индекс получателя адреса сдачи вне диапазона</translation> - </message> - <message> - <source>Transaction must have at least one recipient</source> - <translation type="unfinished">Транзакция должна иметь хотя бы одного получателя</translation> - </message> - <message> - <source>Transaction needs a change address, but we can't generate it.</source> - <translation type="unfinished">Для транзакции требуется адрес сдачи, но сгенерировать его не удалось.</translation> - </message> - <message> - <source>Transaction too large</source> - <translation type="unfinished">Транзакция слишком большая</translation> - </message> - <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Не удалось выделить память для -maxsigcachesize: "%s" МиБ</translation> - </message> - <message> - <source>Unable to bind to %s on this computer (bind returned error %s)</source> - <translation type="unfinished">Невозможно привязаться (bind) к %s на этом компьютере (ошибка %s)</translation> - </message> - <message> - <source>Unable to bind to %s on this computer. %s is probably already running.</source> - <translation type="unfinished">Невозможно привязаться (bind) к %s на этом компьютере. Возможно, %s уже запущен.</translation> - </message> - <message> - <source>Unable to create the PID file '%s': %s</source> - <translation type="unfinished">Не удалось создать PID-файл "%s": %s</translation> - </message> - <message> - <source>Unable to find UTXO for external input</source> - <translation type="unfinished">Не удалось найти UTXO для внешнего входа</translation> - </message> - <message> - <source>Unable to generate initial keys</source> - <translation type="unfinished">Невозможно сгенерировать начальные ключи</translation> - </message> - <message> - <source>Unable to generate keys</source> - <translation type="unfinished">Невозможно сгенерировать ключи</translation> - </message> - <message> - <source>Unable to open %s for writing</source> - <translation type="unfinished">Не удается открыть %s для записи</translation> - </message> - <message> - <source>Unable to parse -maxuploadtarget: '%s'</source> - <translation type="unfinished">Ошибка при разборе параметра -maxuploadtarget: "%s"</translation> - </message> - <message> - <source>Unable to start HTTP server. See debug log for details.</source> - <translation type="unfinished">Невозможно запустить HTTP-сервер. Подробности в файле debug.log.</translation> - </message> - <message> - <source>Unable to unload the wallet before migrating</source> - <translation type="unfinished">Не удалось выгрузить кошелёк перед миграцией</translation> - </message> - <message> - <source>Unknown -blockfilterindex value %s.</source> - <translation type="unfinished">Неизвестное значение -blockfilterindex %s.</translation> - </message> - <message> - <source>Unknown address type '%s'</source> - <translation type="unfinished">Неизвестный тип адреса "%s"</translation> - </message> - <message> - <source>Unknown change type '%s'</source> - <translation type="unfinished">Неизвестный тип сдачи "%s"</translation> - </message> - <message> - <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">В -onlynet указана неизвестная сеть: "%s"</translation> - </message> - <message> - <source>Unknown new rules activated (versionbit %i)</source> - <translation type="unfinished">В силу вступили неизвестные правила (versionbit %i)</translation> - </message> - <message> - <source>Unsupported global logging level %s=%s. Valid values: %s.</source> - <translation type="unfinished">Неподдерживаемый уровень глобального протоколирования %s=%s. Допустимые значения: %s.</translation> - </message> - <message> - <source>acceptstalefeeestimates is not supported on %s chain.</source> - <translation type="unfinished">acceptstalefeeestimates не поддерживается в цепочке %s.</translation> - </message> - <message> - <source>Unsupported logging category %s=%s.</source> - <translation type="unfinished">Неподдерживаемый уровень ведения журнала %s=%s.</translation> - </message> - <message> - <source>User Agent comment (%s) contains unsafe characters.</source> - <translation type="unfinished">Комментарий User Agent (%s) содержит небезопасные символы.</translation> - </message> - <message> - <source>Verifying blocks…</source> - <translation type="unfinished">Проверка блоков…</translation> - </message> - <message> - <source>Verifying wallet(s)…</source> - <translation type="unfinished">Проверка кошелька(ов)…</translation> - </message> - <message> - <source>Wallet needed to be rewritten: restart %s to complete</source> - <translation type="unfinished">Необходимо перезаписать кошелёк. Перезапустите %s для завершения операции</translation> - </message> - <message> - <source>Settings file could not be read</source> - <translation type="unfinished">Файл настроек не может быть прочитан</translation> - </message> - <message> - <source>Settings file could not be written</source> - <translation type="unfinished">Файл настроек не может быть записан</translation> - </message> -</context> + </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_si.ts b/src/qt/locale/bitcoin_si.ts index 5206b23486..cc6b40c945 100644 --- a/src/qt/locale/bitcoin_si.ts +++ b/src/qt/locale/bitcoin_si.ts @@ -294,7 +294,11 @@ <numerusform>%n year(s)</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">පෙරනිමි පසුම්බිය</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -368,7 +372,7 @@ </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&පසුම්බිය උපස්ථය…</translation> + <translation type="unfinished">&පසුම්බිය උපස්ථකරන්න…</translation> </message> <message> <source>Close Wallet…</source> @@ -396,7 +400,7 @@ </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">(%1%) ශ්රීර්ෂ සමමුහූර්ත වෙමින්…</translation> + <translation type="unfinished">(%1%) ශීර්ෂ සමමුහූර්ත වෙමින්…</translation> </message> <message> <source>Synchronizing with network…</source> @@ -422,6 +426,10 @@ <translation type="unfinished">තොරතුර</translation> </message> <message> + <source>Up to date</source> + <translation type="unfinished">යාවත්කාලීනයි</translation> + </message> + <message> <source>&Sending addresses</source> <translation type="unfinished">&යවන ලිපින</translation> </message> @@ -431,11 +439,11 @@ </message> <message> <source>Open Wallet</source> - <translation type="unfinished">පසුම්බිය බලන්න</translation> + <translation type="unfinished">පසුම්බිය විවෘත කරන්න</translation> </message> <message> <source>Open a wallet</source> - <translation type="unfinished">පසුම්බියක් බලන්න</translation> + <translation type="unfinished">පසුම්බියක් විවෘත කරන්න</translation> </message> <message> <source>Close wallet</source> @@ -451,10 +459,6 @@ <translation type="unfinished">සියළු පසුම්බි වසන්න</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">පෙරනිමි පසුම්බිය</translation> - </message> - <message> <source>Wallet Data</source> <extracomment>Name of the wallet data file format.</extracomment> <translation type="unfinished">පසුම්බියේ දත්ත</translation> @@ -631,10 +635,6 @@ <context> <name>OpenWalletActivity</name> <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> @@ -1231,11 +1231,7 @@ <source>Send Coins</source> <translation type="unfinished">කාසි යවන්න</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">පෙරනිමි පසුම්බිය</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index d0e8b11fe8..855bfd371d 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -167,6 +167,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Zadajte starú a novú frázu pre túto peňaženku.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Pokračovať</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">Pamätajte, že zašifrovanie peňaženky neochráni úplne vaše bitcoiny pred ukradnutím škodlivými programami vo vašom počítači.</translation> </message> @@ -387,7 +391,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n rokov</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">predvolená peňaženka</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -637,7 +645,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Node window</source> - <translation type="unfinished">Okno uzlov</translation> + <translation type="unfinished">Uzlové okno</translation> </message> <message> <source>Open node debugging and diagnostic console</source> @@ -694,10 +702,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Skryť hodnoty v karte "Prehľad"</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">predvolená peňaženka</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Nie je dostupná žiadna peňaženka</translation> </message> @@ -1050,10 +1054,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Varovanie otvárania peňaženky</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">predvolená peňaženka</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Otvoriť peňaženku</translation> @@ -2253,7 +2253,7 @@ Ak ste dostali túto chybu mali by ste požiadať obchodníka o URI kompatibiln </message> <message> <source>Node window</source> - <translation type="unfinished">Okno uzlov</translation> + <translation type="unfinished">Uzlové okno</translation> </message> <message> <source>Current block height</source> @@ -2461,6 +2461,10 @@ Ak ste dostali túto chybu mali by ste požiadať obchodníka o URI kompatibiln <translation type="unfinished">Sieťová aktivita zakázaná</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Žiadne</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Príkaz sa vykonáva bez peňaženky</translation> </message> @@ -3146,10 +3150,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok pri sadzbe "100 sat <translation type="unfinished">&Podpísať Správu</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">Môžete podpísať správy svojou adresou a dokázať, že viete prijímať mince zaslané na túto adresu. Buďte však opatrní a podpíšte len podrobné prehlásenia, s ktorými plne súhlasíte, nakoľko útoky typu "phishing" Vás môžu lákať k podpísaniu nejasných alebo príliš všeobecných tvrdení čím prevezmú vašu identitu.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin adresa pre podpísanie správy s</translation> </message> @@ -3234,10 +3234,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok pri sadzbe "100 sat <translation type="unfinished">Prosím skontrolujte adresu a skúste znova.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Vložená adresa nezodpovedá žiadnemu kľúču.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Odomknutie peňaženky bolo zrušené.</translation> </message> @@ -3801,10 +3797,6 @@ Choďte do Súbor > Otvoriť Peňaženku, pre načítanie peňaženky. <source>Can't display address</source> <translation type="unfinished">Nemôžem zobraziť adresu</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">predvolená peňaženka</translation> - </message> </context> <context> <name>WalletView</name> @@ -3925,10 +3917,6 @@ Choďte do Súbor > Otvoriť Peňaženku, pre načítanie peňaženky. <translation type="unfinished">Nezadaný formát súboru peňaženky. Pre použitie createfromdump musíte zadať -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> - <translation type="unfinished">Prosím skontrolujte systémový čas a dátum. Keď je váš čas nesprávny, %s nebude fungovať správne.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Keď si myslíte, že %s je užitočný, podporte nás. Pre viac informácií o software navštívte %s.</translation> </message> @@ -4021,10 +4009,6 @@ Choďte do Súbor > Otvoriť Peňaženku, pre načítanie peňaženky. <translation type="unfinished">-maxmempool musí byť najmenej %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Nastala fatálna interná chyba, pre viac informácií pozrite debug.log</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Nedá preložiť -%s adresu: '%s'</translation> </message> diff --git a/src/qt/locale/bitcoin_sl.ts b/src/qt/locale/bitcoin_sl.ts index ceae34b731..5dea2adaaa 100644 --- a/src/qt/locale/bitcoin_sl.ts +++ b/src/qt/locale/bitcoin_sl.ts @@ -176,6 +176,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <translation type="unfinished">Vnesite staro geslo in novo geslo za denarnico.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Nadaljuj</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">Pomnite, da šifriranje denarnice ne more preprečiti morebitnim virusom na vašem računalniku, da bi ukradli vaše bitcoine.</translation> </message> @@ -271,8 +275,7 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <message> <source>Do you want to reset settings to default values, or to abort without making changes?</source> <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment> - <translation type="unfinished">Želite ponastaviti nastavitve na privzete vrednosti ali prekiniti urejanje brez sprememb? -</translation> + <translation type="unfinished">Želite ponastaviti nastavitve na privzete vrednosti ali prekiniti urejanje brez sprememb?</translation> </message> <message> <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source> @@ -400,7 +403,11 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <numerusform>%n let</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">privzeta denarnica</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -529,65 +536,73 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <translation type="unfinished">&Naloži DPBT iz datoteke...</translation> </message> <message> - <source>Connecting to peers…</source> - <translation type="unfinished">Povezujem se s soležniki...</translation> + <source>Open &URI…</source> + <translation type="unfinished">Odpri &URI...</translation> </message> <message> - <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Zahtevajte plačilo (ustvarite zahtevek s QR-kodo in URI tipa bitcoin:)</translation> + <source>Close Wallet…</source> + <translation type="unfinished">Zapri denarnico...</translation> </message> <message> - <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Prikaži seznam naslovov in oznak, na katere ste kdaj poslali plačila</translation> + <source>Create Wallet…</source> + <translation type="unfinished">Ustvari denarnico...</translation> </message> <message> - <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Prikaži seznam naslovov in oznak, na katere ste kdaj prejeli plačila</translation> + <source>Close All Wallets…</source> + <translation type="unfinished">Zapri vse denarnice...</translation> </message> <message> - <source>&Command-line options</source> - <translation type="unfinished">Možnosti &ukazne vrstice</translation> + <source>&File</source> + <translation type="unfinished">&Datoteka</translation> </message> - <message numerus="yes"> - <source>Processed %n block(s) of transaction history.</source> - <translation type="unfinished"> - <numerusform>Obdelan %n blok zgodovine transakcij.</numerusform> - <numerusform>Obdelana %n bloka zgodovine transakcij.</numerusform> - <numerusform>Obdelani %n bloki zgodovine transakcij.</numerusform> - <numerusform>Obdelanih %n blokov zgodovine transakcij.</numerusform> - </translation> + <message> + <source>&Settings</source> + <translation type="unfinished">&Nastavitve</translation> </message> <message> - <source>%1 behind</source> - <translation type="unfinished">%1 zaostanka</translation> + <source>&Help</source> + <translation type="unfinished">&Pomoč</translation> </message> <message> - <source>Catching up…</source> - <translation type="unfinished">Dohitevam...</translation> + <source>Tabs toolbar</source> + <translation type="unfinished">Orodna vrstica zavihkov</translation> </message> <message> - <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">Zadnji prejeti blok je star %1.</translation> + <source>Syncing Headers (%1%)…</source> + <translation type="unfinished">Sinhroniziram zaglavja (%1%)...</translation> </message> <message> - <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Novejše transakcije še ne bodo vidne.</translation> + <source>Synchronizing with network…</source> + <translation type="unfinished">Dohitevam omrežje ...</translation> </message> <message> - <source>Error</source> - <translation type="unfinished">Napaka</translation> + <source>Indexing blocks on disk…</source> + <translation type="unfinished">Izdelujem kazalo blokov na disku...</translation> </message> <message> - <source>Warning</source> - <translation type="unfinished">Opozorilo</translation> + <source>Processing blocks on disk…</source> + <translation type="unfinished">Procesiram bloke na disku...</translation> </message> <message> - <source>Information</source> - <translation type="unfinished">Informacije</translation> + <source>Connecting to peers…</source> + <translation type="unfinished">Povezujem se s soležniki…</translation> </message> <message> - <source>Up to date</source> - <translation type="unfinished">Ažurno</translation> + <source>&Command-line options</source> + <translation type="unfinished">&Možnosti iz ukazne vrstice</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation type="unfinished"> + <numerusform>Obdelan %n blok zgodovine transakcij.</numerusform> + <numerusform>Obdelana %n bloka zgodovine transakcij.</numerusform> + <numerusform>Obdelani %n bloki zgodovine transakcij.</numerusform> + <numerusform>Obdelanih %n blokov zgodovine transakcij.</numerusform> + </translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation type="unfinished">Naloži delno podpisano bitcoin-transakcijo</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -656,10 +671,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <translation type="unfinished">Zamaskiraj vrednosti v zavihku Pregled</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">privzeta denarnica</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Ni denarnic na voljo</translation> </message> @@ -688,6 +699,18 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <translation type="unfinished">O&kno</translation> </message> <message> + <source>Zoom</source> + <translation type="unfinished">Povečava</translation> + </message> + <message> + <source>Main Window</source> + <translation type="unfinished">Glavno okno</translation> + </message> + <message> + <source>%1 client</source> + <translation type="unfinished">Odjemalec %1</translation> + </message> + <message> <source>&Hide</source> <translation type="unfinished">&Skrij</translation> </message> @@ -730,6 +753,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> @@ -928,6 +955,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <translation type="unfinished">Kopiraj vračilo</translation> </message> <message> + <source>(%1 locked)</source> + <translation type="unfinished">(%1 zaklenjeno)</translation> + </message> + <message> <source>Can vary +/- %1 satoshi(s) per input.</source> <translation type="unfinished">Lahko se razlikuje za +/- %1 sat na vhod.</translation> </message> @@ -997,10 +1028,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <translation type="unfinished">Opozorilo pri odpiranju denarnice</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">privzeta denarnica</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Odpri denarnico</translation> @@ -2469,6 +2496,10 @@ Svetujemo, da prodajalca prosite, naj vam priskrbi URI na podlagi BIP21.</transl <translation type="unfinished">Omrežna aktivnost onemogočena.</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Jih ni</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Izvajam ukaz brez denarnice</translation> </message> @@ -3185,10 +3216,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kvB" <translation type="unfinished">&Podpiši sporočilo</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">S svojimi naslovi lahko podpisujete sporočila ali dogovore in s tem dokazujete, da na teh naslovih lahko prejemate kovance. Bodite previdni in ne podpisujte ničesar nejasnega ali naključnega, ker vas zlikovci preko ribarjenja (phishing) lahko prelisičijo, da na njih prepišete svojo identiteto. Podpisujte samo podrobno opisane izjave, s katerimi se strinjate.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin-naslov, s katerim podpisujete sporočilo</translation> </message> @@ -3273,10 +3300,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kvB" <translation type="unfinished">Prosimo, preverite naslov in poskusite znova.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Vnešeni naslov se ne nanaša na ključ.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Odklepanje denarnice je bilo preklicano.</translation> </message> @@ -3844,11 +3867,6 @@ Za odpiranje denarnice kliknite Datoteka > Odpri denarnico <translation type="unfinished">DPBT kopirana</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Kopirano na odložišče</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">Ne morem podpisati transakcije.</translation> </message> @@ -3860,10 +3878,6 @@ Za odpiranje denarnice kliknite Datoteka > Odpri denarnico <source>Can't display address</source> <translation type="unfinished">Ne morem prikazati naslova</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">privzeta denarnica</translation> - </message> </context> <context> <name>WalletView</name> @@ -3984,10 +3998,6 @@ Za odpiranje denarnice kliknite Datoteka > Odpri denarnico <translation type="unfinished">Potrebno je določiti obliko izvozne (dump) datoteke. Z ukazom createfromdump morate uporabiti možnost -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> - <translation type="unfinished">Opozorilo: Preverite, če sta datum in ura na vašem računalniku točna! %s ne bo deloval pravilno, če je nastavljeni čas nepravilen.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Prosimo, prispevajte, če se vam zdi %s uporaben. Za dodatne informacije o programski opremi obiščite %s.</translation> </message> @@ -4084,10 +4094,6 @@ Za odpiranje denarnice kliknite Datoteka > Odpri denarnico <translation type="unfinished">-maxmempool mora biti vsaj %d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Prišlo je do usodne notranje napake. Za podrobnosti glejte datoteko debug.log.</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Naslova -%s ni mogoče razrešiti: '%s'</translation> </message> @@ -4100,6 +4106,10 @@ Za odpiranje denarnice kliknite Datoteka > Odpri denarnico <translation type="unfinished">Nastavitev -peerblockfilters ni veljavna brez nastavitve -blockfilterindex.</translation> </message> <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation type="unfinished">Nimam dostopa za pisanje v podatkovni mapi '%s'; preveri dovoljenja.</translation> + </message> + <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> <translation type="unfinished">Nezdružljivi nastavitvi: navedene so specifične povezave in hkrati se uporablja addrman za iskanje izhodnih povezav.</translation> </message> @@ -4212,6 +4222,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: %s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation type="unfinished">Napaka pri branju iz podarkovne baze, zapiram.</translation> </message> @@ -4508,10 +4522,6 @@ Obnovitev varnostne kopije denarnice ni bila mogoča.</translation> <translation type="unfinished">Transkacija je prevelika</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Spodletelo je dodeljevanje pomnilnika za -maxsigcachesize: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Na tem računalniku ni bilo mogoče vezati naslova %s (vrnjena napaka: %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_sn.ts b/src/qt/locale/bitcoin_sn.ts index bfdb6c951b..634e27c1a1 100644 --- a/src/qt/locale/bitcoin_sn.ts +++ b/src/qt/locale/bitcoin_sn.ts @@ -247,6 +247,10 @@ <source>N/A</source> <translation type="unfinished">Hapana</translation> </message> + <message> + <source>None</source> + <translation type="unfinished">Hapana</translation> + </message> </context> <context> <name>RecentRequestsTableModel</name> diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index 5646cf7938..b366aa3b9c 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -184,6 +184,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Унеси стару лозинку и нову лозинку новчаника.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Nastavi</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Упамти, шифрирање новчаника не може у потуности заштити твоје биткоине од крађе од стране малвера инфицира твој рачунар.</translation> </message> @@ -224,6 +228,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 +240,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 +262,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> @@ -401,7 +417,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 kB</source> <translation type="unfinished">%1 килобајта</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">подразумевани новчаник</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -638,6 +658,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> @@ -703,10 +727,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -716,6 +736,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> @@ -1040,10 +1065,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -2359,6 +2380,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Активност мреже онемогућена</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Nijedan</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Извршење команде без новчаника</translation> </message> @@ -3030,8 +3055,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Потписи - Потпиши / Потврди поруку</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">Можете потписати поруку/споразум са вашом адресом да би сте доказали да можете примити биткоин послат ка њима. Будите опрезни да не потписујете ништа нејасно или случајно, јер се може десити напад крађе идентитета, да потпишете ваш идентитет нападачу. Потпишите само потпуно детаљне изјаве са којима се слажете.</translation> + <source>&Sign Message</source> + <translation type="unfinished">&Потпиши поруку</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3118,10 +3143,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Молим проверите адресу и покушајте поново.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Унесена адреса се не односи на кључ.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Откључавање новчаника је отказано.</translation> </message> @@ -3179,6 +3200,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <context> <name>TransactionDesc</name> <message> + <source>conflicted with a transaction with %1 confirmations</source> + <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment> + <translation type="unfinished">постоји неусаглашеност са трансакцијом са %1 потврда</translation> + </message> + <message> <source>abandoned</source> <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment> <translation type="unfinished">напуштено</translation> @@ -3658,11 +3684,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>Could not commit transaction</source> <translation type="unfinished">Трансакција није могућа</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">подразумевани новчаник</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -3718,10 +3740,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Дистрибуирано под MIT софтверском лиценцом, погледајте придружени документ %s или %s</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Молим проверите да су време и датум на вашем рачунару тачни. Уколико је сат нетачан, %s неће радити исправно.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Молим донирајте, уколико сматрате %s корисним. Посетите %s за више информација о софтверу.</translation> </message> diff --git a/src/qt/locale/bitcoin_sr@ijekavianlatin.ts b/src/qt/locale/bitcoin_sr@ijekavianlatin.ts index a10aa71c10..b4c3906a17 100644 --- a/src/qt/locale/bitcoin_sr@ijekavianlatin.ts +++ b/src/qt/locale/bitcoin_sr@ijekavianlatin.ts @@ -184,6 +184,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Унеси стару лозинку и нову лозинку новчаника.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Nastavi</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Упамти, шифрирање новчаника не може у потуности заштити твоје биткоине од крађе од стране малвера инфицира твој рачунар.</translation> </message> @@ -224,6 +228,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 +240,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 +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> @@ -397,7 +413,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 kB</source> <translation type="unfinished">%1 килобајта</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">подразумевани новчаник</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -487,7 +507,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Options…</source> - <translation type="unfinished">&Опције...</translation> + <translation type="unfinished">&Opcije…</translation> </message> <message> <source>&Encrypt Wallet…</source> @@ -615,11 +635,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Error</source> - <translation type="unfinished">Грешка</translation> + <translation type="unfinished">Greska</translation> </message> <message> <source>Warning</source> - <translation type="unfinished">Упозорење</translation> + <translation type="unfinished">Upozorenje</translation> </message> <message> <source>Information</source> @@ -634,6 +654,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> @@ -699,10 +723,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -712,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> @@ -1036,10 +1061,6 @@ Signing is only possible with addresses of the type 'legacy'.</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">Otvori novčanik</translation> @@ -2355,6 +2376,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Активност мреже онемогућена</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Nijedan</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Извршење команде без новчаника</translation> </message> @@ -3026,8 +3051,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Потписи - Потпиши / Потврди поруку</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">Можете потписати поруку/споразум са вашом адресом да би сте доказали да можете примити биткоин послат ка њима. Будите опрезни да не потписујете ништа нејасно или случајно, јер се може десити напад крађе идентитета, да потпишете ваш идентитет нападачу. Потпишите само потпуно детаљне изјаве са којима се слажете.</translation> + <source>&Sign Message</source> + <translation type="unfinished">&Потпиши поруку</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3114,10 +3139,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Молим проверите адресу и покушајте поново.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Унесена адреса се не односи на кључ.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Откључавање новчаника је отказано.</translation> </message> @@ -3175,6 +3196,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <context> <name>TransactionDesc</name> <message> + <source>conflicted with a transaction with %1 confirmations</source> + <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment> + <translation type="unfinished">постоји неусаглашеност са трансакцијом са %1 потврда</translation> + </message> + <message> <source>abandoned</source> <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment> <translation type="unfinished">напуштено</translation> @@ -3654,11 +3680,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>Could not commit transaction</source> <translation type="unfinished">Трансакција није могућа</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">подразумевани новчаник</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -3714,10 +3736,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Дистрибуирано под MIT софтверском лиценцом, погледајте придружени документ %s или %s</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Молим проверите да су време и датум на вашем рачунару тачни. Уколико је сат нетачан, %s неће радити исправно.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Молим донирајте, уколико сматрате %s корисним. Посетите %s за више информација о софтверу.</translation> </message> diff --git a/src/qt/locale/bitcoin_sr@latin.ts b/src/qt/locale/bitcoin_sr@latin.ts index c7b80f3b02..395752767d 100644 --- a/src/qt/locale/bitcoin_sr@latin.ts +++ b/src/qt/locale/bitcoin_sr@latin.ts @@ -184,6 +184,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Unesite u novčanik staru lozinku i novu lozinku.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Nastavi</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> @@ -224,6 +228,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 +240,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 +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> @@ -397,7 +413,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 kB</source> <translation type="unfinished">%1 килобајта</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">подразумевани новчаник</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -487,7 +507,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Options…</source> - <translation type="unfinished">&Опције...</translation> + <translation type="unfinished">&Opcije…</translation> </message> <message> <source>&Encrypt Wallet…</source> @@ -634,6 +654,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> @@ -699,10 +723,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -712,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> @@ -1036,10 +1061,6 @@ Signing is only possible with addresses of the type 'legacy'.</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">Otvori novčanik</translation> @@ -2351,6 +2372,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Активност мреже онемогућена</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Nijedan</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Извршење команде без новчаника</translation> </message> @@ -3022,8 +3047,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Потписи - Потпиши / Потврди поруку</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">Можете потписати поруку/споразум са вашом адресом да би сте доказали да можете примити биткоин послат ка њима. Будите опрезни да не потписујете ништа нејасно или случајно, јер се може десити напад крађе идентитета, да потпишете ваш идентитет нападачу. Потпишите само потпуно детаљне изјаве са којима се слажете.</translation> + <source>&Sign Message</source> + <translation type="unfinished">&Потпиши поруку</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -3110,10 +3135,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Молим проверите адресу и покушајте поново.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Унесена адреса се не односи на кључ.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Откључавање новчаника је отказано.</translation> </message> @@ -3171,6 +3192,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <context> <name>TransactionDesc</name> <message> + <source>conflicted with a transaction with %1 confirmations</source> + <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment> + <translation type="unfinished">постоји неусаглашеност са трансакцијом са %1 потврда</translation> + </message> + <message> <source>abandoned</source> <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment> <translation type="unfinished">напуштено</translation> @@ -3650,11 +3676,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>Could not commit transaction</source> <translation type="unfinished">Трансакција није могућа</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">подразумевани новчаник</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -3710,10 +3732,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Дистрибуирано под MIT софтверском лиценцом, погледајте придружени документ %s или %s</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Молим проверите да су време и датум на вашем рачунару тачни. Уколико је сат нетачан, %s неће радити исправно.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Молим донирајте, уколико сматрате %s корисним. Посетите %s за више информација о софтверу.</translation> </message> diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 19903798dd..1bf74501cc 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">Högerklicka för att redigera adressen eller etiketten.</translation> + <translation type="unfinished">Adresi veya etiketi düzenlemek için sağ tıklayın.</translation> </message> <message> <source>Create a new address</source> @@ -26,10 +26,6 @@ <translation type="unfinished">S&täng</translation> </message> <message> - <source>Delete the currently selected address from the list</source> - <translation type="unfinished">Ta bort den valda adressen från listan</translation> - </message> - <message> <source>Enter address or label to search</source> <translation type="unfinished">Ange en adress eller etikett att söka efter</translation> </message> @@ -50,10 +46,6 @@ <translation type="unfinished">Välj en adress att skicka transaktionen till</translation> </message> <message> - <source>Choose the address to receive coins with</source> - <translation type="unfinished">Välj en adress att ta emot transaktionen med</translation> - </message> - <message> <source>C&hoose</source> <translation type="unfinished">V&älj</translation> </message> @@ -62,11 +54,6 @@ <translation type="unfinished">Detta är dina Bitcoin-adresser för att skicka betalningar. Kontrollera alltid belopp och mottagaradress innan du skickar bitcoin.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. -Signing is only possible with addresses of the type 'legacy'.</source> - <translation type="unfinished">Detta är dina Bitcoinadresser för att ta emot betalningar. Använd knappen 'Skapa ny mottagaradress' i mottagsfliken för att skapa nya adresser. Signering är bara tillgänglig för adresser av typen 'legacy'</translation> - </message> - <message> <source>&Copy Address</source> <translation type="unfinished">&Kopiera adress</translation> </message> @@ -94,10 +81,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> Försök igen.</translation> </message> <message> - <source>Sending addresses - %1</source> - <translation type="unfinished">Avsändaradresser - %1</translation> - </message> - <message> <source>Receiving addresses - %1</source> <translation type="unfinished">Mottagaradresser - %1</translation> </message> @@ -184,6 +167,14 @@ Försök igen.</translation> <translation type="unfinished">Ange den gamla lösenfrasen och den nya lösenfrasen för plånboken.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Fortsätt</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Tillbaka</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">Kom ihåg att kryptering av din plånbok inte helt kan skydda dig från stöld av dina bitcoins om skadlig kod infekterat din dator.</translation> </message> @@ -296,13 +287,17 @@ Försök igen.</translation> </message> <message> <source>%1 didn't yet exit safely…</source> - <translation type="unfinished">%1 har inte avslutats korrekt ännu...</translation> + <translation type="unfinished">%1 har inte avslutats korrekt än...</translation> </message> <message> <source>unknown</source> <translation type="unfinished">okänd</translation> </message> <message> + <source>Custom…</source> + <translation type="unfinished">Anpassad...</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Belopp</translation> </message> @@ -341,36 +336,36 @@ Försök igen.</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> @@ -380,11 +375,15 @@ Försök igen.</translation> <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> + <message> + <source>default wallet</source> + <translation type="unfinished">Standardplånbok</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -558,7 +557,7 @@ Försök igen.</translation> </message> <message> <source>Processing blocks on disk…</source> - <translation type="unfinished">Processar block på disken…</translation> + <translation type="unfinished">Behandlar block på disken…</translation> </message> <message> <source>Connecting to peers…</source> @@ -694,10 +693,6 @@ Försök igen.</translation> <translation type="unfinished">Dölj värden i översiktsfliken</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standardplånbok</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Inga plånböcker tillgängliga</translation> </message> @@ -739,7 +734,7 @@ Försök igen.</translation> </message> <message> <source>&Hide</source> - <translation type="unfinished">&Dölj</translation> + <translation type="unfinished">och göm</translation> </message> <message> <source>S&how</source> @@ -1054,7 +1049,7 @@ Försök igen.</translation> </message> <message> <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> - <translation type="unfinished">Är du säker att du vill migrera plånboken 1 %1 1 ?</translation> + <translation type="unfinished">Är du säker att du vill migrera plånboken <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. @@ -1098,10 +1093,6 @@ Om den här plånboken innehåller lösbara</translation> <translation type="unfinished">Öppna plånboksvarning</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standardplånbok</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Öppna plånbok</translation> @@ -1397,6 +1388,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 +1476,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 +1516,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 +1528,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 +1548,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 +1580,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> @@ -2207,6 +2237,10 @@ Om den här plånboken innehåller lösbara</translation> <translation type="unfinished">Riktning/Typ</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">BIP324 sessions ID-strängen i hex.</translation> + </message> + <message> <source>Services</source> <translation type="unfinished">Tjänster</translation> </message> @@ -2322,10 +2356,18 @@ Om den här plånboken innehåller lösbara</translation> <translation type="unfinished">Nätverksaktivitet inaktiverad</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Ingen</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Utför instruktion utan plånbok</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Nodfönster - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">Utför instruktion med plånbok "%1"</translation> </message> @@ -2745,6 +2787,10 @@ Om den här plånboken innehåller lösbara</translation> <translation type="unfinished">Verifiera ditt transaktionsförslag. Det kommer skapas en delvis signerad Bitcoin transaktion (PSBT) som du kan spara eller kopiera och sen signera med t.ex. en offline %1 plånbok, eller en PSBT-kompatibel hårdvaruplånbok.</translation> </message> <message> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1 från plånbok '%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">Vill du skapa den här transaktionen?</translation> @@ -2801,8 +2847,8 @@ Om den här plånboken innehåller lösbara</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> @@ -2907,10 +2953,6 @@ Om den här plånboken innehåller lösbara</translation> <translation type="unfinished">&Signera meddelande</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">Du kan signera meddelanden/avtal med dina adresser för att bevisa att du kan ta emot bitcoin som skickats till dem. Var försiktig så du inte signerar något oklart eller konstigt, eftersom phishing-angrepp kan försöka få dig att signera över din identitet till dem. Signera endast väldetaljerade meddelanden som du godkänner.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Bitcoin-adress att signera meddelandet med</translation> </message> @@ -2995,10 +3037,6 @@ Om den här plånboken innehåller lösbara</translation> <translation type="unfinished">Kontrollera adressen och försök igen.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Den angivna adressen refererar inte till en nyckel.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Upplåsningen av plånboken avbröts.</translation> </message> @@ -3111,8 +3149,8 @@ Om den här plånboken innehåller lösbara</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> @@ -3509,6 +3547,10 @@ Gå till Fil > Öppna plånbok för att läsa in en plånbok. <translation type="unfinished">PSBT kopierad</translation> </message> <message> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Avgifts-höjande PSBT kopierad till urklipp</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation type="unfinished">Kan ej signera transaktion.</translation> </message> @@ -3517,12 +3559,12 @@ Gå till Fil > Öppna plånbok för att läsa in en plånbok. <translation type="unfinished">Kunde inte skicka transaktion</translation> </message> <message> - <source>Can't display address</source> - <translation type="unfinished">Kan inte visa adress</translation> + <source>Signer error</source> + <translation type="unfinished">Signeringsfel</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">Standardplånbok</translation> + <source>Can't display address</source> + <translation type="unfinished">Kan inte visa adress</translation> </message> </context> <context> @@ -3588,10 +3630,6 @@ Gå till Fil > Öppna plånbok för att läsa in en plånbok. <translation type="unfinished">Fler än en onion-adress finns tillgänglig. Den automatiskt skapade Tor-tjänsten kommer använda %s.</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">Kontrollera att din dators datum och tid är korrekt! Om klockan går fel kommer %s inte att fungera korrekt.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Var snäll och bidra om du finner %s användbar. Besök %s för mer information om mjukvaran.</translation> </message> diff --git a/src/qt/locale/bitcoin_sw.ts b/src/qt/locale/bitcoin_sw.ts index 499eb68538..0497444d5e 100644 --- a/src/qt/locale/bitcoin_sw.ts +++ b/src/qt/locale/bitcoin_sw.ts @@ -243,6 +243,10 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <context> <name>BitcoinApplication</name> <message> + <source>Settings file %1 might be corrupt or invalid.</source> + <translation type="unfinished">Faili ya mipangilio ya asilimia %1 inaweza kuwa mbovu au batili.</translation> + </message> + <message> <source>Runaway exception</source> <translation type="unfinished">Ubaguzi wa kukimbia</translation> </message> @@ -321,7 +325,11 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">mkoba chaguo-msingi</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -357,6 +365,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> @@ -379,7 +391,7 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> </message> <message> <source>Proxy is <b>enabled</b>: %1</source> - <translation type="unfinished">Proxy imeamilishwa: %1</translation> + <translation type="unfinished">Proxy <b>imeamilishwa</b>: %1</translation> </message> <message> <source>Send coins to a Bitcoin address</source> @@ -398,14 +410,27 @@ 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> <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&Simba Mkoba...</translation> + </message> + <message> <source>Encrypt the private keys that belong to your wallet</source> <translation type="unfinished">Funga funguo za siri zinazomiliki mkoba wako.</translation> </message> <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Hifadhi Mkoba... +</translation> + </message> + <message> <source>&Change Passphrase…</source> <translation type="unfinished">&Badilisha Nenosiri...</translation> </message> @@ -418,10 +443,18 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <translation type="unfinished">Saini ujumbe na anwani zako za Bitcoin ili kuthibitisha umiliki wao.</translation> </message> <message> + <source>&Verify message…</source> + <translation type="unfinished">&Thibitisha ujumbe...</translation> + </message> + <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> <translation type="unfinished">Hakikisha ujumbe umethibitishwa kuwa ulisainiwa na anwani za Bitcoin zilizotajwa</translation> </message> <message> + <source>&Load PSBT from file…</source> + <translation type="unfinished">&Pakia PSBT kutoka faili...</translation> + </message> + <message> <source>Open &URI…</source> <translation type="unfinished">Fungua &URI ...</translation> </message> @@ -479,7 +512,7 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Onyesha orodha ya anuani za kutuma na chapa</translation> + <translation type="unfinished">Onyesha orodha ya anuani za kutuma zilizotumika na chapa</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> @@ -497,10 +530,159 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> </translation> </message> <message> + <source>%1 behind</source> + <translation type="unfinished">%1 nyuma</translation> + </message> + <message> + <source>Catching up…</source> + <translation type="unfinished">Inakamata...</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">Kosa</translation> + </message> + <message> + <source>Warning</source> + <translation type="unfinished">Onyo</translation> + </message> + <message> + <source>Information</source> + <translation type="unfinished">Habari</translation> + </message> + <message> + <source>Up to date</source> + <translation type="unfinished">Imesasishwa</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation type="unfinished">Pakia Muamala wa Bitcoin Uliosainiwa Kiasi</translation> + </message> + <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Pakia PSBT kutoka &clipboard...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation type="unfinished">Pakia Muamala wa Bitcoin Uliosainiwa Kiasi kutoka kwenye ubao wa kunakili</translation> + </message> + <message> + <source>Node window</source> + <translation type="unfinished">Dirisha la nodi</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation type="unfinished">Fungua utatuzi wa nodi na koni ya uchunguzi</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation type="unfinished">&Anwani za kutuma</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation type="unfinished">&Inapokea anwani</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation type="unfinished">Fungua bitcoin: URI</translation> + </message> + <message> + <source>Open Wallet</source> + <translation type="unfinished">Fungua Pochi</translation> + </message> + <message> + <source>Open a wallet</source> + <translation type="unfinished">Fungua pochi</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Funga pochi</translation> + </message> + <message> + <source>Restore Wallet…</source> + <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> + <translation type="unfinished">Rejesha Pochi...</translation> + </message> + <message> + <source>Restore a wallet from a backup file</source> + <extracomment>Status tip for Restore Wallet menu item</extracomment> + <translation type="unfinished">Rejesha mkoba kutoka kwa faili ya chelezo</translation> + </message> + <message> + <source>Close all wallets</source> + <translation type="unfinished">Funga pochi zote</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Hamisha Pochi</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">Hamisha mkoba</translation> + </message> + <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation type="unfinished">Onyesha %1 ujumbe wa usaidizi ili kupata orodha na chaguo zinazowezekana za mstari wa amri za Bitcoin</translation> + </message> + <message> + <source>&Mask values</source> + <translation type="unfinished">&Funga maadili</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation type="unfinished">Ficha maadili kwenye kichupo cha Muhtasari</translation> + </message> + <message> + <source>No wallets available</source> + <translation type="unfinished">Hakuna pochi zinazopatikana</translation> + </message> + <message> + <source>Wallet Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Data ya Pochi</translation> + </message> + <message> + <source>Load Wallet Backup</source> + <extracomment>The title for Restore Wallet File Windows</extracomment> + <translation type="unfinished">Pakia Hifadhi Nakala ya Wallet</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">Rejesha 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>&Window</source> + <translation type="unfinished">&Dirisha</translation> + </message> + <message> + <source>Zoom</source> + <translation type="unfinished">Kuza</translation> + </message> + <message> + <source>Main Window</source> + <translation type="unfinished">Dirisha Kuu</translation> + </message> + <message> + <source>%1 client</source> + <translation type="unfinished">%1 mteja</translation> + </message> + <message> + <source>&Hide</source> + <translation type="unfinished">&Ficha</translation> + </message> + <message> + <source>S&how</source> + <translation type="unfinished">Jinsi & jinsi</translation> + </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> @@ -510,13 +692,98 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> </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">Bofya kwa vitendo zaidi.</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">Onyesha kichupo cha Marika</translation> + </message> + <message> + <source>Disable network activity</source> + <extracomment>A context menu item.</extracomment> + <translation type="unfinished">Zima shughuli za mtandao</translation> + </message> + <message> + <source>Enable network activity</source> + <extracomment>A context menu item. The network activity was disabled previously.</extracomment> + <translation type="unfinished">Washa shughuli za mtandao</translation> + </message> + <message> + <source>Pre-syncing Headers (%1%)…</source> + <translation type="unfinished">Kusawazisha Vichwa vya awali (%1%)...</translation> + </message> + <message> + <source>Error creating wallet</source> + <translation type="unfinished">Hitilafu unapounda pochi</translation> + </message> + <message> + <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">Haiwezi kuunda pochi mpya, programu iliundwa bila usaidizi wa sqlite (inahitajika kwa pochi za maelezo)</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Kosa: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation type="unfinished">Onyo: %1</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation type="unfinished">Tarehe: %1</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation type="unfinished">Kiasi: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation type="unfinished">Pochi: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation type="unfinished">Aina: %1</translation> + </message> + <message> <source>Label: %1 </source> - <translation type="unfinished">Chapa: %1</translation> + <translation type="unfinished">Chapa: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation type="unfinished">Anwani: %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation type="unfinished">Umetuma muamala</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation type="unfinished">Muamala unaoingia</translation> + </message> + <message> + <source>HD key generation is <b>enabled</b></source> + <translation type="unfinished">Uzalishaji wa ufunguo wa HD ni <b>kuwezeshwa </b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation type="unfinished">Uzalishaji wa ufunguo wa HD ni <b>kutowezeshwa</b></translation> + </message> + <message> + <source>Private key <b>disabled</b></source> + <translation type="unfinished">Ufunguo wa kibinafsi <b> umezimwa </b></translation> </message> </context> <context> @@ -526,6 +793,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,8 +818,28 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> </message> </context> <context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Hamisha Pochi</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</source> + <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment> + <translation type="unfinished">Rejesha Pochi</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">Rejesha onyo la pochi</translation> @@ -549,9 +848,17 @@ 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> + <message> + <source>Close all wallets</source> + <translation type="unfinished">Funga pochi zote</translation> + </message> </context> <context> <name>CreateWalletDialog</name> @@ -657,6 +964,21 @@ 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>&Window</source> + <translation type="unfinished">&Dirisha</translation> + </message> + <message> + <source>Error</source> + <translation type="unfinished">Onyo</translation> + </message> </context> <context> <name>PeerTableModel</name> @@ -674,6 +996,13 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> </message> </context> <context> + <name>RPCConsole</name> + <message> + <source>Node window</source> + <translation type="unfinished">Dirisha la nodi</translation> + </message> + </context> +<context> <name>ReceiveCoinsDialog</name> <message> <source>&Label:</source> @@ -699,6 +1028,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 +1057,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 +1163,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> @@ -829,6 +1178,11 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <source>Export the data in the current tab to a file</source> <translation type="unfinished">Toa data katika kichupo cha sasa hadi kwenye faili</translation> </message> + <message> + <source>Wallet Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Data ya Pochi</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_szl.ts b/src/qt/locale/bitcoin_szl.ts index 81a33250ad..83ba8cb6fb 100644 --- a/src/qt/locale/bitcoin_szl.ts +++ b/src/qt/locale/bitcoin_szl.ts @@ -260,7 +260,11 @@ <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">wychodny portmanyj</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -427,10 +431,6 @@ <translation type="unfinished">Pokŏż pōmoc %1 coby zobŏczyć wykŏz wszyjskich ôpcyji piski nakŏzań.</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">wychodny portmanyj</translation> - </message> - <message> <source>&Window</source> <translation type="unfinished">Ô&kno</translation> </message> @@ -622,13 +622,6 @@ </message> </context> <context> - <name>OpenWalletActivity</name> - <message> - <source>default wallet</source> - <translation type="unfinished">wychodny portmanyj</translation> - </message> - </context> -<context> <name>CreateWalletDialog</name> <message> <source>Wallet</source> @@ -1593,11 +1586,7 @@ <source>New fee:</source> <translation type="unfinished">Nowŏ ôpłŏcka:</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">wychodny portmanyj</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_ta.ts b/src/qt/locale/bitcoin_ta.ts index 6255126438..797a07b778 100644 --- a/src/qt/locale/bitcoin_ta.ts +++ b/src/qt/locale/bitcoin_ta.ts @@ -342,7 +342,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">இயல்புநிலை வாலட்</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -408,7 +412,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Proxy is <b>enabled</b>: %1</source> - <translation type="unfinished">ப்ராக்ஸி இயக்கப்பட்டது: %1</translation> + <translation type="unfinished">ப்ராக்ஸி <b>இயக்கப்பட்டது</b>: %1</translation> </message> <message> <source>Send coins to a Bitcoin address</source> @@ -575,10 +579,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -665,23 +665,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>HD key generation is <b>enabled</b></source> - <translation type="unfinished">HD முக்கிய தலைமுறை இயக்கப்பட்டது</translation> + <translation type="unfinished">HD முக்கிய தலைமுறை <b>இயக்கப்பட்டது</b></translation> </message> <message> <source>HD key generation is <b>disabled</b></source> - <translation type="unfinished">HD முக்கிய தலைமுறை முடக்கப்பட்டுள்ளது</translation> + <translation type="unfinished">HD முக்கிய தலைமுறை <b>முடக்கப்பட்டுள்ளது</b></translation> </message> <message> <source>Private key <b>disabled</b></source> - <translation type="unfinished">தனிப்பட்ட விசை முடக்கப்பட்டது</translation> + <translation type="unfinished">தனிப்பட்ட விசை <b>முடக்கப்பட்டது</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">Wallet குறியாக்கப்பட்டு தற்போது திறக்கப்பட்டது</translation> + <translation type="unfinished">Wallet <b>குறியாக்கப்பட்டு</b> தற்போது <b>திறக்கப்பட்டது</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">Wallet குறியாக்கப்பட்டு தற்போது பூட்டப்பட்டுள்ளது</translation> + <translation type="unfinished">Wallet <b>குறியாக்கப்பட்டு</b> தற்போது <b>பூட்டப்பட்டுள்ளது</b></translation> </message> <message> <source>Original message:</source> @@ -833,10 +833,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -1788,6 +1784,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">நெட்வொர்க் செயல்பாடு முடக்கப்பட்டது</translation> </message> <message> + <source>None</source> + <translation type="unfinished">யாரும்</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">எந்த பணமும் இல்லாமல் கட்டளையை நிறைவேற்றும்</translation> </message> @@ -1844,7 +1844,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation type="unfinished">பணம் செலுத்த வேண்டுமெனில் இந்த படிவத்தைப் பயன்படுத்தவும். அனைத்து துறைகள் விருப்பமானவை.</translation> + <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> @@ -2157,6 +2157,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">தொகை உங்கள் இருப்பையைவிட அதிகமாக உள்ளது.</translation> </message> <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation type="unfinished">%1 பரிவர்த்தனைக் கட்டணம் சேர்க்கப்படும்போது மொத்த தொகை உங்கள் மீதம் உள்ள தொகையை மீறுகிறது.</translation> + </message> + <message> <source>Duplicate address found: addresses should only be used once each.</source> <translation type="unfinished">நகல் முகவரி காணப்பட்டது: முகவரிகள் ஒவ்வொன்றும் ஒரு முறை மட்டுமே பயன்படுத்தப்பட வேண்டும்.</translation> </message> @@ -2164,6 +2168,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Transaction creation failed!</source> <translation type="unfinished">பரிவர்த்தனை உருவாக்கம் தோல்வியடைந்தது!</translation> </message> + <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation type="unfinished">எந்த ஒரு கட்டணம் %1 ஐ விட அதிகமாக இருந்தால் அது அபத்தமான உயர் கட்டணமாக கருதப்படும்.</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> @@ -2265,10 +2273,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&செய்தியை கையொப்பமிடுங்கள்</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">மற்றவர்களுக்கு அனுப்பப்பட்ட பிட்காயின்களைப் நீங்கள் பெறலாம் என்பதை நிரூபிக்க உங்கள் முகவரிகளுடன் செய்திகள் / ஒப்பந்தங்களில் கையொப்பமிடலாம். தெளிவற்ற அல்லது சீரற்ற எதையும் கையொப்பமிடாமல் கவனமாக இருங்கள், ஏனெனில் ஃபிஷிங் தாக்குதல்கள் உங்கள் அடையாளத்தை அவர்களிடம் கையொப்பமிட்டு ஏமாற்ற முயற்சிக்கும். நீங்கள் ஒப்புக்கொள்ளும் முழுமையான மற்றும் விரிவான அறிக்கைகளில் மட்டுமே கையொப்பமிடுங்கள்.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">செய்தியை கையொப்பமிட பிட்காயின் முகவரி</translation> </message> @@ -2345,10 +2349,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">முகவரியைச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">உள்ளிட்ட முகவரி எந்த ஒரு கீயை குறிக்கவில்லை.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">வாலட் திறத்தல் ரத்து செய்யப்பட்டது.</translation> </message> @@ -2552,7 +2552,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>This pane shows a detailed description of the transaction</source> <translation type="unfinished">இந்த பலகம் பரிவர்த்தனை பற்றிய விரிவான விளக்கத்தைக் காட்டுகிறது</translation> </message> - </context> + <message> + <source>Details for %1</source> + <translation type="unfinished">%1 க்கான விவரங்கள்</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> @@ -2580,10 +2584,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">உறுதிப்படுத்துகிறது (%1 ன் %2 பரிந்துரைக்கப்பட்ட உறுதிப்படுத்தல்கல்)</translation> </message> <message> + <source>Confirmed (%1 confirmations)</source> + <translation type="unfinished">உறுதிப்படுத்தப்பட்டது (%1 உறுதிப்படுத்தல்கள்)</translation> + </message> + <message> <source>Conflicted</source> <translation type="unfinished">முரண்பாடு</translation> </message> <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation type="unfinished">முதிர்ச்சியடையவில்லை (%1 உறுதிப்படுத்தல்கள்,%2 க்குப் பிறகு கிடைக்கும்)</translation> + </message> + <message> <source>Generated but not accepted</source> <translation type="unfinished">உருவாக்கப்பட்டது ஆனால் ஏற்றுக்கொள்ளப்படவில்லை</translation> </message> @@ -2810,11 +2822,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Could not commit transaction</source> <translation type="unfinished">பரிவர்த்தனையை கமிட் செய்ய முடியவில்லை</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">இயல்புநிலை வாலட்</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -2865,10 +2873,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">எம்ஐடி சாப்ட்வேர் விதிமுறைகளின் கீழ் பகிர்ந்தளிக்கப்படுகிறது, அதனுடன் கொடுக்கப்பட்டுள்ள %s அல்லது %s பைல் ஐ பார்க்கவும்</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">உங்கள் கணினியின் தேதி மற்றும் நேரம் சரியாக உள்ளதா என்பதனை சரிபார்க்கவும்! உங்கள் கடிகாரம் தவறாக இருந்தால், %s சரியாக இயங்காது.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">%s பயனுள்ளதாக இருந்தால் தயவுசெய்து பங்களியுங்கள். இந்த சாஃட்வேர் பற்றிய கூடுதல் தகவலுக்கு %s ஐப் பார்வையிடவும்.</translation> </message> @@ -3009,6 +3013,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">-%s=<amount>: '%s' கான தவறான தொகை</translation> </message> <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation type="unfinished">-அனுமதிப்பட்டியல் குறிப்பிடப்பட்ட தவறான நெட்மாஸ்க்: '%s'</translation> + </message> + <message> <source>Not enough file descriptors available.</source> <translation type="unfinished">போதுமான ஃபைல் டிஸ்கிரிப்டார் கிடைக்கவில்லை.</translation> </message> diff --git a/src/qt/locale/bitcoin_te.ts b/src/qt/locale/bitcoin_te.ts index e30f9bebf5..28fabe2339 100644 --- a/src/qt/locale/bitcoin_te.ts +++ b/src/qt/locale/bitcoin_te.ts @@ -172,6 +172,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">వాలెట్ కోసం క్రొత్త పాస్ఫ్రేజ్ని నమోదు చేయండి.<br/> దయచేసి <b>పది లేదా అంతకంటే ఎక్కువ యాదృచ్ఛిక అక్షరాల</b> పాస్ఫ్రేజ్ని లేదా <b>ఎనిమిది లేదా అంతకంటే ఎక్కువ పదాలను ఉపయోగించండి.</b></translation> </message> <message> + <source>Continue</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> @@ -379,7 +383,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform>%n సంవత్సరం(లు)</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">డిఫాల్ట్ వాలెట్</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -473,7 +481,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">&వాలెట్ని ఎన్క్రిప్ట్ చేయండి...</translation> + <translation type="unfinished">&వాలెట్ని గుప్తీకరించు...</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -578,8 +586,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>లావాదేవీ చరిత్ర యొక్క %n బ్లాక్(లు) ప్రాసెస్ చేయబడింది.</numerusform> - <numerusform>లావాదేవీ చరిత్ర యొక్క %n బ్లాక్(లు) ప్రాసెస్ చేయబడింది.</numerusform> + <numerusform>లావాదేవీ %n చరిత్ర యొక్క ప్రాసెస్ చేయబడిన బ్లాక్(లు).</numerusform> + <numerusform>లావాదేవీ %n చరిత్ర యొక్క ప్రాసెస్ చేయబడిన బ్లాక్(లు).</numerusform> </translation> </message> <message> @@ -685,10 +693,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -734,7 +738,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>S&how</source> - <translation type="unfinished">S&ఎలా</translation> + <translation type="unfinished">&చూపించు</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -1040,10 +1044,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -2136,6 +2136,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&కాపీ చిరునామా</translation> </message> <message> + <source>None</source> + <translation type="unfinished">ఏదీ లేదు</translation> + </message> + <message> <source>To</source> <translation type="unfinished">కు</translation> </message> @@ -2494,13 +2498,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> </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> @@ -2611,10 +2608,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">లావాదేవీ చాలా పెద్దది</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">-maxsigcacheize కోసం మెమరీని కేటాయించడం సాధ్యం కాలేదు: '%s' MiB</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">బైండ్ చేయడం సాధ్యపడలేదు %s ఈ కంప్యూటర్లో (బైండ్ రిటర్న్ ఎర్రర్ %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_th.ts b/src/qt/locale/bitcoin_th.ts new file mode 100644 index 0000000000..464e39cbac --- /dev/null +++ b/src/qt/locale/bitcoin_th.ts @@ -0,0 +1,340 @@ +<TS version="2.1" language="th"> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Back</source> + <translation type="unfinished">ย้อนกลับ</translation> + </message> + </context> +<context> + <name>QObject</name> + <message> + <source>%1 didn't yet exit safely…</source> + <translation type="unfinished">%1 ยังไม่ออกอย่างปลอดภัย...</translation> + </message> + <message numerus="yes"> + <source>%n second(s)</source> + <translation type="unfinished"> + <numerusform>%n second(s)</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation type="unfinished"> + <numerusform>%n minute(s)</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation type="unfinished"> + <numerusform>%n hour(s)</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation type="unfinished"> + <numerusform>%n day(s)</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation type="unfinished"> + <numerusform>%n week(s)</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation type="unfinished"> + <numerusform>%n year(s)</numerusform> + </translation> + </message> + </context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Change the passphrase used for wallet encryption</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>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation type="unfinished">เซ็นชื่อด้วยข้อความ ที่เก็บ Bitcoin เพื่อแสดงว่าท่านเป็นเจ้าของ bitcoin นี้จริง</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation type="unfinished">ตรวจสอบ ข้อความ เพื่อให้แน่ใจว่า การเซ็นต์ชื่อ ด้วยที่เก็บ Bitcoin แล้ว</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>Connecting to peers…</source> + <translation type="unfinished">กำลังเชื่อมต่อ ไปยัง peers…</translation> + </message> + <message> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation type="unfinished">ขอการชำระเงิน (สร้างรหัส QR และ bitcoin: URIs)</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">&ตัวเลือก Command-line</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation type="unfinished"> + <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 PSBT from &clipboard…</source> + <translation type="unfinished">โหลด PSBT จากคลิปบอร์ด...</translation> + </message> + <message> + <source>Node window</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 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>&Mask values</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 numerus="yes"> + <source>%n active connection(s) to Bitcoin network.</source> + <extracomment>A substring of the tooltip.</extracomment> + <translation type="unfinished"> + <numerusform>%n active connection(s) to Bitcoin network.</numerusform> + </translation> + </message> + <message> + <source>Click for more actions.</source> + <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> + <translation type="unfinished">คลิกเพื่อดูการดำเนินการเพิ่มเติม</translation> + </message> + </context> +<context> + <name>CoinControlDialog</name> + <message> + <source>L&ock unspent</source> + <translation type="unfinished">L&ock ที่ไม่ได้ใข้</translation> + </message> + <message> + <source>&Unlock unspent</source> + <translation type="unfinished">&ปลดล็อค ที่ไม่ไดใช้</translation> + </message> + <message> + <source>(no label)</source> + <translation type="unfinished">(ไม่มีเลเบล)</translation> + </message> + <message> + <source>change from %1 (%2)</source> + <translation type="unfinished">เปลี่ยน จาก %1 (%2)</translation> + </message> + <message> + <source>(change)</source> + <translation type="unfinished">(เปลี่ยน)</translation> + </message> +</context> +<context> + <name>CreateWalletActivity</name> + <message> + <source>Create Wallet</source> + <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment> + <translation type="unfinished">สร้าง วอลเล็ต</translation> + </message> + <message> + <source>Creating Wallet <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> + </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>Intro</name> + <message numerus="yes"> + <source>%n GB of space available</source> + <translation type="unfinished"> + <numerusform>%n GB of space available</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation type="unfinished"> + <numerusform>(of %n GB needed)</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation type="unfinished"> + <numerusform>(%n GB needed for full chain)</numerusform> + </translation> + </message> + <message numerus="yes"> + <source>(sufficient to restore backups %n day(s) old)</source> + <extracomment>Explanatory text on the capability of the current prune target.</extracomment> + <translation type="unfinished"> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> + </translation> + </message> + </context> +<context> + <name>RPCConsole</name> + <message> + <source>Node window</source> + <translation type="unfinished">หน้าต่างโหนด</translation> + </message> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>(no label)</source> + <translation type="unfinished">(ไม่มีเลเบล)</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation type="unfinished"> + <numerusform>Estimated to begin confirmation within %n block(s).</numerusform> + </translation> + </message> + <message> + <source>(no label)</source> + <translation type="unfinished">(ไม่มีเลเบล)</translation> + </message> +</context> +<context> + <name>TransactionDesc</name> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation type="unfinished"> + <numerusform>matures in %n more block(s)</numerusform> + </translation> + </message> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>(no label)</source> + <translation type="unfinished">(ไม่มีเลเบล)</translation> + </message> + </context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_tk.ts b/src/qt/locale/bitcoin_tk.ts index 0afd01fd71..7a0a69513f 100644 --- a/src/qt/locale/bitcoin_tk.ts +++ b/src/qt/locale/bitcoin_tk.ts @@ -176,6 +176,10 @@ Diňe "miras" görnüşli salgylar bilen gol çekmek mümkin.</translation> <translation type="unfinished">Gapjyk üçin öňki we täze parol sözlemiňi ýaz.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Dowam et</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Gapjygyňy şifrlemek kompýuteriňe zyýanly programma ýokuşmak arkaly bitkoinleriň ogurlanmagyndan doly gorap bilmejekdigini ýatdan çykarma.</translation> </message> @@ -399,7 +403,11 @@ Diňe "miras" görnüşli salgylar bilen gol çekmek mümkin.</translation> <numerusform>%n ýyl</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">deslapky bellenen gapjyk</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -636,7 +644,7 @@ Diňe "miras" görnüşli salgylar bilen gol çekmek mümkin.</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">Bölekleýýin gol çekilen bitkoin amalyny (BGÇBA) ýükle</translation> + <translation type="unfinished">Bölekleýýin gol çekilen bitkoin geleşigini ýükle</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -644,7 +652,7 @@ Diňe "miras" görnüşli salgylar bilen gol çekmek mümkin.</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> - <translation type="unfinished">Bölekleýin gol çekilen bitkoin amalyny alyş-çalyş panelinden ýükle</translation> + <translation type="unfinished">Bölekleýin gol çekilen bitkoin geleşigini alyş-çalyş panelinden ýükle</translation> </message> <message> <source>Node window</source> @@ -705,10 +713,6 @@ Diňe "miras" görnüşli salgylar bilen gol çekmek mümkin.</translation> <translation type="unfinished">Gözden geçir bölüminde sanlaryň üstüni ört</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">deslapky bellenen gapjyk</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Elýeterli gapjyk ýok</translation> </message> @@ -1060,10 +1064,6 @@ Diňe "miras" görnüşli salgylar bilen gol çekmek mümkin.</translation> <translation type="unfinished">Gapjyk açmak duýduryşy</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">deslapky bellenen gapjyk</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Gapjygy aç</translation> @@ -2326,6 +2326,10 @@ Size bu ýalňyşlyk gelýän bolsa, siz täjirden BIP21-e gabat gelýän URI-ni <extracomment>Context menu action to copy the address of a peer.</extracomment> <translation type="unfinished">&Salgyny göçür</translation> </message> + <message> + <source>None</source> + <translation type="unfinished">ýok</translation> + </message> </context> <context> <name>ReceiveCoinsDialog</name> @@ -2582,13 +2586,6 @@ Size bu ýalňyşlyk gelýän bolsa, siz täjirden BIP21-e gabat gelýän URI-ni </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">deslapky bellenen gapjyk</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> diff --git a/src/qt/locale/bitcoin_tl.ts b/src/qt/locale/bitcoin_tl.ts index aaa9d64ccd..b042fb8ea9 100644 --- a/src/qt/locale/bitcoin_tl.ts +++ b/src/qt/locale/bitcoin_tl.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">pindutin lamang ang kanang pindutan upang i-edit ang address o label</translation> + <translation type="unfinished">pindutin lamang ang kanang pindutan upang i-edit ang address o label.</translation> </message> <message> <source>Create a new address</source> @@ -23,7 +23,7 @@ </message> <message> <source>C&lose</source> - <translation type="unfinished">Isara</translation> + <translation type="unfinished">(Do you mean: Close?) :isara, sarado </translation> </message> <message> <source>Delete the currently selected address from the list</source> @@ -55,7 +55,7 @@ </message> <message> <source>C&hoose</source> - <translation type="unfinished">&Pumili</translation> + <translation type="unfinished">(do you mean: CHOOSE?) ;Pumili,Piliin.</translation> </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> @@ -319,7 +319,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">pitaka na ♦default♦</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -359,6 +363,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Patungkol sa &♦Qt♦</translation> </message> <message> + <source>Show information about Qt</source> + <translation type="unfinished">Ipakita ang impormasyon tungkol sa Qt</translation> + </message> + <message> <source>Modify configuration options for %1</source> <translation type="unfinished">Baguhin ang mga pagpipilian sa ♦configuration♦ para sa 1%1</translation> </message> @@ -405,7 +413,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">&I-encrypt ang pitaka</translation> + <translation type="unfinished">&I-encrypt ang Pitaka</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -603,10 +611,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">I-mask ang mga halaga sa loob ng ♦Overview tab♦</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">pitaka na ♦default♦</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Walang pitaka na mayroon</translation> </message> @@ -914,10 +918,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Babala sa pagbukas ng pitaka</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">pitaka na ♦default♦</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Buksan ang pitaka</translation> @@ -1444,13 +1444,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> - <name>WalletModel</name> - <message> - <source>default wallet</source> - <translation type="unfinished">pitaka na ♦default♦</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index ba3ecca680..569a7c27be 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">Adresi veya etiketi düzenlemek için sağ tıklayın</translation> + <translation type="unfinished">Sağ tık ile adres ve etiket düzenle</translation> </message> <message> <source>Create a new address</source> @@ -185,6 +185,14 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Cüzdanınızın eski ve yeni parolasını giriniz.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Devam</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">Geri</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">Cüzdanınızı şifrelemenin bilgisayarınıza bulaşan kötü amaçlı yazılımlar tarafından bitcoinlerinizin çalınmasına karşı tamamen koruyamayacağını unutmayın.</translation> </message> @@ -225,6 +233,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Cüzdan parolasının kaldırılması için girilen parola yanlış.</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">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</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">Cüzdan parolası başarılı bir şekilde değiştirildi</translation> </message> @@ -259,10 +271,18 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Sızıntı istisnası</translation> </message> <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation type="unfinished">Önemli bir hata oluştu. %1 artık güvenli bir şekilde devam edemeyecek ve çıkacak.</translation> + </message> + <message> <source>Internal error</source> <translation type="unfinished">İç hata</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">Bir iç hata oluştu. %1 güvenli bir şekilde devam etmeye çalışacak. Bu, aşağıda açıklandığı gibi rapor edilebilecek beklenmedik bir hatadır.</translation> + </message> +</context> <context> <name>QObject</name> <message> @@ -288,6 +308,18 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">bilinmeyen</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">Yerleştir "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Varsayılan sistem fontu "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">Özel…</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Mitar</translation> </message> @@ -380,7 +412,11 @@ Cüzdan kilidini aç.</translation> <numerusform>%n yıl</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">varsayılan cüzdan</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -661,6 +697,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> @@ -669,10 +713,6 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Genel Bakış sekmesindeki değerleri maskeleyin</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">varsayılan cüzdan</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Erişilebilir cüzdan yok</translation> </message> @@ -733,11 +773,6 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">daha fazla seçenek için tıklayın.</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">Eşler sekmesini göster</translation> - </message> - <message> <source>Disable network activity</source> <extracomment>A context menu item.</extracomment> <translation type="unfinished">Ağ etkinliğini devre dışı bırak</translation> @@ -752,6 +787,14 @@ 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>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">Yeni cüzdan oluşturulamıyor, yazılım SQLite desteği olmadan derlenmiş (descriptor cüzdanlar için gereklidir).</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Hata: %1</translation> </message> @@ -805,11 +848,11 @@ Cüzdan kilidini aç.</translation> </message> <message> <source>HD key generation is <b>enabled</b></source> - <translation type="unfinished">HD anahtar üreticiler kullanilabilir</translation> + <translation type="unfinished">HD anahtar üreticiler <b>kullanilabilir</b></translation> </message> <message> <source>HD key generation is <b>disabled</b></source> - <translation type="unfinished">HD anahtar üreticiler kullanılamaz</translation> + <translation type="unfinished">HD anahtar üreticiler <b>kullanılamaz</b></translation> </message> <message> <source>Private key <b>disabled</b></source> @@ -817,11 +860,11 @@ Cüzdan kilidini aç.</translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">Cüzdan <b>şifrelenmiş</b> ve şu anda <b>kilitli değil</translation> + <translation type="unfinished">Cüzdan <b>şifrelenmiş</b> ve şu anda <b>kilitli değil</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">Cüzdan <b>şifrelenmiş</b> ve şu anda <b>kilitlidir</translation> + <translation type="unfinished">Cüzdan <b>şifrelenmiş</b> ve şu anda <b>kilitlidir</b></translation> </message> <message> <source>Original message:</source> @@ -979,10 +1022,6 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Cüzdan oluşturma uyarısı</translation> </message> <message> - <source>Can't list signers</source> - <translation type="unfinished">İmzalayanlar listelenmiyor</translation> - </message> - <message> <source>Too many external signers found</source> <translation type="unfinished">Çok fazla harici imzalayan bulundu</translation> </message> @@ -1001,6 +1040,57 @@ 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>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">Cüzdanı taşımak, bu cüzdanı bir veya daha fazla descriptor cüzdana dönüştürecektir. Yeni bir cüzdan yedeği oluşturulması gerekecektir. +Eğer bu cüzdan yalnızca izlenen scriptler içeriyorsa, bu scriptleri içeren yeni bir cüzdan oluşturulacaktır. +Eğer bu cüzdan çözülebilir ama izlenmeyen scriptler içeriyorsa, bu scriptleri içeren farklı ve yeni bir cüzdan oluşturulacaktır. + +Taşıma işlemi, taşıma işleminden önce cüzdanın bir yedeğini oluşturacaktır. Bu yedek dosya <wallet name>-<timestamp>.legacy.bak olarak adlandırılacak ve bu cüzdanın bulunduğu dizinde bulunacaktır. Yanlış bir taşıma durumunda, yedek "Cüzdanı Geri Yükle" işlevi ile geri yüklenebilir.</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>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Yalnızca izlenen scriptler yeni bir cüzdana taşındı, adı '%1'.</translation> + </message> + <message> + <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Çözülebilir ama izlenmeyen scriptler yeni bir cüzdana taşındı, adı '%1'.</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> @@ -1011,10 +1101,6 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Açık cüzdan uyarısı</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">varsayılan cüzdan</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Cüzdanı Aç</translation> @@ -1083,6 +1169,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> @@ -1409,6 +1503,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Pencere kapatıldığında uygulamadan çıkmak yerine uygulamayı küçültür. Bu seçenek etkinleştirildiğinde, uygulama sadece menüden çıkış seçildiğinde kapanacaktır.</translation> </message> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">Genel Bakış sekmesindeki yazı tipi:</translation> + </message> + <message> <source>Options set in this dialog are overridden by the command line:</source> <translation type="unfinished">Bu iletişim kutusundan ayarlanan seçenekler komut satırı tarafından geçersiz kılınır:</translation> </message> @@ -1812,6 +1910,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">PSBT diske kaydedildi.</translation> </message> <message> + <source>Sends %1 to %2</source> + <translation type="unfinished">Gönderiler %1 ile %2</translation> + </message> + <message> <source>own address</source> <translation type="unfinished">kendi adresiniz</translation> </message> @@ -2056,10 +2158,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> @@ -2146,6 +2256,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Yön/Tür</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">BIP324 oturum kimliği ID dizesi onaltılık ( hex ) biçimde</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">Bu çiftin bağlı olduğu internet protokolü : IPv4, IPv6, Onion, I2P, ya da CJDNS.</translation> </message> @@ -2226,6 +2340,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> @@ -2264,10 +2393,18 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Ağ etkinliği devre dışı bırakıldı</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Boş</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Komut cüzdan olmadan çalıştırılıyor.</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Bağlanan pencere - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">Komut "%1" cüzdanı kullanılarak çalıştırılıyor.</translation> </message> @@ -2645,6 +2782,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">veya</translation> </message> <message> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1 Cüzdandan '%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">Bu işlemi oluşturmak ister misiniz?</translation> @@ -2664,6 +2805,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">İşlem ücreti</translation> </message> <message> + <source>Total Amount</source> + <translation type="unfinished">Toplam Tutar</translation> + </message> + <message> <source>Unsigned Transaction</source> <comment>PSBT copied</comment> <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> @@ -2809,8 +2954,8 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">İleti &imzala</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">Adreslerinize yollanan bitcoinleri alabileceğiniz ispatlamak için adreslerinizle iletiler/anlaşmalar imzalayabilirsiniz. Oltalama saldırılarının kimliğinizi imzanızla elde etmeyi deneyebilecekleri için belirsiz ya da rastgele hiçbir şey imzalamamaya dikkat ediniz. Sadece ayrıntılı açıklaması olan ve tümüne katıldığınız ifadeleri imzalayınız.</translation> + <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">Eski (P2PKH) adreslerinizle mesajları/anlaşmaları imzalayarak bu adreslere gönderilen Bitcoin'leri alabileceğinizi unutmayın. Belirsiz veya rastgele şeyleri imzalamaktan kaçının, çünkü kimlik bilgilerinizi çalmak isteyen oltalama saldırıları sizi kandırmaya çalışabilir. Sadece tamamen ayrıntılı ve onayladığınız beyanları imzalayın.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> @@ -2893,8 +3038,8 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Lütfen adresi kontrol edip tekrar deneyiniz.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Girilen adres herhangi bir anahtara işaret etmemektedir.</translation> + <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">Girilen adres, eski (P2PKH) bir anahtarı belirtmiyor. Bu sürümde SegWit ve diğer P2PKH olmayan %1 versiyon adres türleri için mesajla imzalama desteklenmiyor. Lütfen adresi kontrol edin ve tekrar deneyin.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3079,6 +3224,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Çıktı indeksi</translation> </message> <message> + <source>%1 (Certificate was not verified)</source> + <translation type="unfinished">%1 (Sertifika doğrulanmadı)</translation> + </message> + <message> <source>Merchant</source> <translation type="unfinished">Tüccar</translation> </message> @@ -3397,9 +3546,8 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">PSBT kopyalandı</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Panoya kopyalandı</translation> + <source>Fee-bump PSBT copied to clipboard</source> + <translation type="unfinished">Ücret artırma PSBT'si panoya kopyalandı</translation> </message> <message> <source>Can't sign transaction.</source> @@ -3410,10 +3558,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Alışveriş taahüt edilemedi.</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">varsayılan cüzdan</translation> + <source>Signer error</source> + <translation type="unfinished">imzalayıcı hatası</translation> </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -3461,6 +3609,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">%s geliştiricileri</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 -assumeutxo anlık görüntü durumunu doğrulamada başarısız oldu. Bu, bir donanım sorunu, yazılımda bir hata veya geçersiz bir anlık görüntünün yüklenmesine izin veren kötü bir yazılım değişikliği olduğunu gösterir. Bu nedenle, düğüm kapanacak ve anlık görüntüye dayanan herhangi bir durumu kullanmayı bırakacak, zincir yüksekliğini %d'den %d'e sıfırlayacaktır. Bir sonraki yeniden başlatmada, düğüm herhangi bir anlık görüntü verisi kullanmadan %d'den senkronizasyona devam edecektir. Bu olayı %s'ye bildiriniz ve anlık görüntüyü nasıl elde ettiğinizi de ekleyiniz. Geçersiz anlık görüntü zincir durumu, bu hatanın nedenini teşhis etmekte yardımcı olabilir diye diskte bırakılacaktır.</translation> + </message> + <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation type="unfinished">%s veri dizininde kilit elde edilemedi. %s muhtemelen hâlihazırda çalışmaktadır.</translation> </message> @@ -3477,10 +3629,6 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Geçersiz veya bozuk peers.dat (%s). Bunun bir hata olduğunu düşünüyorsanız, lütfen %s'e bildirin. Geçici bir çözüm olarak, bir sonraki başlangıçta yeni bir dosya oluşturmak için dosyayı (%s) yoldan çekebilirsiniz (yeniden adlandırabilir, taşıyabilir veya silebilirsiniz).</translation> </message> <message> - <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation type="unfinished">Lütfen bilgisayarınızın tarih ve saatinin doğruluğunu kontrol edin. Hata varsa %s doğru çalışmayacaktır.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">%s programını faydalı buluyorsanız lütfen katkıda bulununuz. Yazılım hakkında daha fazla bilgi için %s adresini ziyaret ediniz.</translation> </message> @@ -3497,6 +3645,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Budama: son cüzdan eşleşmesi budanmış verilerin ötesine gitmektedir. -reindex kullanmanız gerekmektedir (Budanmış düğüm ise tüm blok zincirini tekrar indirmeniz gerekir.)</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">'%s' -> '%s' yeniden adlandırması başarısız oldu. Bunu, %s geçersiz anlık görüntü dizinini manuel olarak taşıyarak veya silerek çözmelisiniz; aksi takdirde, bir sonraki başlatmada aynı hata ile karşılaşabilirsiniz."</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">Blok veritabanı gelecekten gibi görünen bir blok içermektedir. Bu, bilgisayarınızın saat ve tarihinin yanlış ayarlanmış olmasından kaynaklanabilir. Blok veritabanını sadece bilgisayarınızın tarih ve saatinin doğru olduğundan eminseniz yeniden derleyin.</translation> </message> @@ -3521,6 +3673,30 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Ağ sürümü zincirinin toplam boyutu (%i) en yüksek boyutu geçmektedir (%i). Kullanıcı aracı açıklamasının sayısı veya boyutunu azaltınız.</translation> </message> <message> + <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> + <translation type="unfinished">Bilinmeyen cüzdan dosya biçimi “%s” girildi. Lütfen “bdb” veya “sqlite” formatlarından birini girin.</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">Desteklenmeyen kategoriye özgü günlükleme seviyesi %1$s=%2$s. Beklenen: %1$s=<category>:<loglevel>. Geçerli kategoriler: %3$s. Geçerli günlükleme seviyeleri: %4$s.</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">Cüzdan başarıyla oluşturuldu. Eski cüzdan türü kullanımdan kaldırılmaktadır ve eski cüzdan oluşturma ve açma desteği gelecekte kaldırılacaktır.</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">Cüzdan başarıyla yüklendi. Eski cüzdan türü kullanımdan kaldırılacak ve eski cüzdanların oluşturulması ve açılması desteği gelecekte kaldırılacaktır. Eski cüzdanlar, migratewallet komutuyla descriptor cüzdana dönüştürülebilir.</translation> + </message> + <message> + <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> + <translation type="unfinished">Uyarı: Dumpfile cüzdan formatı "%s", komut satırında belirtilen formatla "%s" eşleşmiyor.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation type="unfinished">Uyarı: {%s} cüzdanında özel anahtarlarla devre dışı bırakılmış özel anahtarlar algılandı</translation> + </message> + <message> <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> <translation type="unfinished">Uyarı: Ağ eşlerimizle tamamen anlaşamamışız gibi görünüyor! Güncelleme yapmanız gerekebilir ya da diğer düğümlerin güncelleme yapmaları gerekebilir.</translation> </message> @@ -3545,6 +3721,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">-dnsseed false olarak ayarlanırken -forcednsseed true olarak ayarlanamıyor.</translation> </message> <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation type="unfinished">-blockfilterindex olmadan -peerblockfilters ayarlanamıyor.</translation> + </message> + <message> <source>Cannot write to data directory '%s'; check permissions.</source> <translation type="unfinished">Veriler '%s' klasörüne yazılamıyor ; yetkilendirmeyi kontrol edin.</translation> </message> @@ -3557,20 +3737,90 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">%s yüklenirken hata oluştu: Harici imzalayan cüzdanı derlenmiş harici imzalayan desteği olmadan yükleniyor</translation> </message> <message> + <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> + <translation type="unfinished">Okumada Hata %s! Tüm anahtarlar doğru okundu, ancak işlem verileri veya adres metadata verileri eksik veya hatalı olabilir.</translation> + </message> + <message> + <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished">Hata: Cüzdandaki adres defteri verilerinin taşınan cüzdanlara ait olduğu tespit edilemiyor</translation> + </message> + <message> + <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source> + <translation type="unfinished">Hata: Geçiş sırasında yinelenen tanımlayıcılar oluşturuldu. Cüzdanınız bozulmuş olabilir.</translation> + </message> + <message> + <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished">Hata: Cüzdandaki %s işleminin taşınan cüzdanlara ait olduğu tespit edilemiyor</translation> + </message> + <message> + <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> + <translation type="unfinished">Ücret artışını hesaplamada başarısız olundu, çünkü onaylanmamış UTXO'lar, devasa bir onaylanmamış işlemler kümesine bağlı.</translation> + </message> + <message> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished">Anlık görüntü zincir durumu dizini (%s) kaldırılamadı. Yeniden başlatmadan önce manuel olarak silin. +</translation> + </message> + <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished">Geçersiz peers.dat dosyası yeniden adlandırılamadı. Lütfen taşıyın veya silin ve tekrar deneyin.</translation> </message> <message> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Blok dosyasını diske yazma başarısız oldu. Bu muhtemelen bir G/Ç hatasının sonucudur.</translation> + </message> + <message> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished">Geri alma dosyasını diske yazma başarısız oldu. Bu muhtemelen bir G/Ç hatasının sonucudur.</translation> + </message> + <message> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished">Maksimum işlem ağırlığı, işlem girdi ağırlığından daha küçük olmalıdır.</translation> + </message> + <message> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished">Maksimum işlem ağırlığı çok düşük, değişim çıktısını barındıramaz.</translation> + </message> + <message> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished">'%s' -> '%s' yeniden adlandırması başarısız oldu. Arka plan zincir durumu leveldb dizinini temizleyemiyor.</translation> + </message> + <message> + <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">Önceden seçilmiş girişlerin ve cüzdanın otomatik giriş seçiminin kombinasyonu, işlemin maksimum ağırlığını aşıyor. Lütfen daha küçük bir miktar göndermeyi deneyin veya cüzdanınızdaki UTXO'ları manuel olarak birleştirin.</translation> + </message> + <message> + <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">Bilgisayarınızın tarihi ve saati, ağla %d dakikadan fazla senkronizasyon görünmüyor; bu başarısız işlem hatasına yol açabilir. Bilgisayarınızın saatini düzenledikten sonra, bu mesaj tekrar görünmemelidir. Düğümünüzü yeniden başlattığınızda mesaj kaybolmalıdır. Yeniden başlatma olmadan, yeterli sayıda yeni çıkış bağlantısı sağladıktan sonra otomatik olarak kaybolmalıdır, bu biraz zaman alabilir. Daha fazla bilgi almak için `getpeerinfo` ve `getnetworkinfo` RPC yöntemlerinin `timeoffset` alanını kontrol edebilirsiniz.</translation> + </message> + <message> <source> Unable to restore backup of wallet.</source> <translation type="unfinished"> Cüzdan yedeği geri yüklenemiyor.</translation> </message> <message> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished">whitebind yalnızca gelen bağlantılar için kullanılabilir ('out' parametresi pas geçildi)</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">Kritik bir iç hata oluştu, detaylar için debug.log dosyasına bakın:</translation> + </message> + <message> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished">Verilen blok hash '%s' için AssumeUTXO verisi bulunamadı.</translation> + </message> + <message> <source>Copyright (C) %i-%i</source> <translation type="unfinished">Telif Hakkı (C) %i-%i</translation> </message> <message> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished">Bozuk bir blok bulundu, bu donanım arızası kaynaklı olabilir.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation type="unfinished">Bozuk blok veritabanı tespit edildi</translation> </message> @@ -3587,6 +3837,14 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Yükleme tamamlandı</translation> </message> <message> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished">Eliptik eğri kriptografisi sistem sağlığı kontrolü başarısız oldu. %s kapatılıyor.</translation> + </message> + <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">Cüzdan verilerinizin silinirken hata. Veri tabanı bağlantı hatası.</translation> + </message> + <message> <source>Error initializing block database</source> <translation type="unfinished">Blok veritabanını başlatılırken bir hata meydana geldi</translation> </message> @@ -3619,6 +3877,10 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Veritabanı okuma hatası, program kapatılıyor.</translation> </message> <message> + <source>Error starting db txn for wallet transactions removal</source> + <translation type="unfinished">Cüzdan verileriniz silinirken hata. Veri tabanı başlatılamadı</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">Hata: Yeni sadece izlenebilir (watchonly) cüzdanı oluşturulamadı</translation> </message> @@ -3627,18 +3889,74 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Hata: Bu cüzdan zaten SQLite kullanıyor</translation> </message> <message> + <source>Error: Unable to read wallet's best block locator record</source> + <translation type="unfinished">Hata: Cüzdan okunamadı en iyi blok bulucu kaydı </translation> + </message> + <message> + <source>Error: Unable to write solvable wallet best block locator record</source> + <translation type="unfinished">Hata: Cüzdana yazılamadı en iyi blok bulucu kaydı </translation> + </message> + <message> + <source>Error: Unable to write watchonly wallet best block locator record</source> + <translation type="unfinished">Hata: Yalnızca izlenen cüzdanın en iyi blok bulucu kaydını yazmak mümkün değil</translation> + </message> + <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">Hata: %s Cüzdan için adres defteri kopyası oluşturulamadı</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">Hata: %sCüzdan için veri tabanında işlem yapılamaz</translation> + </message> + <message> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished">En iyi (%s) bloğa bağlanmak başarısız oldu.</translation> + </message> + <message> + <source>Failed to disconnect block.</source> + <translation type="unfinished">Bloğun bağlantısı kesilemedi.</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Herhangi bir portun dinlenmesi başarısız oldu. Bunu istiyorsanız -listen=0 seçeneğini kullanınız.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">Bloğu okuma başarısız oldu.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <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> <message> + <source>Failed to write block.</source> + <translation type="unfinished">Bloğa yazma başarısız oldu.</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">Blok indeks veri tabanına yazma başarısız oldu.</translation> + </message> + <message> + <source>Failed to write to coin database.</source> + <translation type="unfinished">Coin veri tabanına yazma başarısız oldu.</translation> + </message> + <message> + <source>Failed to write undo data.</source> + <translation type="unfinished">Eski verilere yazma başarısız oldu.</translation> + </message> + <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">işlemi: %s silme başarısız oldu.</translation> + </message> + <message> <source>Importing…</source> <translation type="unfinished">İçe aktarılıyor...</translation> </message> @@ -3668,7 +3986,7 @@ Cüzdan yedeği geri yüklenemiyor.</translation> </message> <message> <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation type="unfinished">-%s=<tutar> için geçersiz tutar: '%s'</translation> + <translation type="unfinished">Geçersiz tutar için -%s=<amount>: '%s'</translation> </message> <message> <source>Invalid netmask specified in -whitelist: '%s'</source> @@ -3691,6 +4009,10 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Cüzdan yükleniyor...</translation> </message> <message> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished">Maksimum işlem yükü %d ile %d arasında olmalıdır</translation> + </message> + <message> <source>Missing amount</source> <translation type="unfinished">Eksik tutar</translation> </message> @@ -3711,6 +4033,10 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Kafi derecede dosya tanımlayıcıları mevcut değil.</translation> </message> <message> + <source>Only direction was set, no permissions: '%s'</source> + <translation type="unfinished">'%s' için izin yok. Sadece hedef ayarlandı.</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Budama negatif bir değerle yapılandırılamaz.</translation> </message> @@ -3727,6 +4053,18 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Yeniden taranıyor...</translation> </message> <message> + <source>Signer did not echo address</source> + <translation type="unfinished">İmzalayıcı adresi belirtilmedi.</translation> + </message> + <message> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished">İstenmeyen %s adrese imzalama yapıldı.</translation> + </message> + <message> + <source>Signer returned error: %s</source> + <translation type="unfinished">%s İmzayıcı hatası tekrarı.</translation> + </message> + <message> <source>Signing transaction failed</source> <translation type="unfinished">İşlemin imzalanması başarısız oldu</translation> </message> @@ -3743,6 +4081,18 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Belirtilen -walletdir "%s" bir dizin değildir</translation> </message> <message> + <source>System error while flushing: %s</source> + <translation type="unfinished">Temizleme esnasında sistem hatası: %s</translation> + </message> + <message> + <source>System error while loading external block file: %s</source> + <translation type="unfinished">%s : Harici blok dosyası yüklenirken sistem hatası.</translation> + </message> + <message> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished">%s Bloğu diske kaydederken sistem hatası oluştu.</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">%s'in kaynak kodu ulaşılabilir.</translation> </message> @@ -3755,6 +4105,10 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">Cüzdan en az aktarma ücretinden daha az ödeme yapmaktan sakınacaktır.</translation> </message> <message> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished">Bu adres için bir ScriptPubKeyManager bulunmuyor</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Bu deneysel bir uygulamadır.</translation> </message> @@ -3767,6 +4121,10 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">-paytxfee çok yüksek bir değere ayarlanmış! Bu, işlemi gönderirseniz ödeyeceğiniz işlem ücretidir.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">%s İşlem bu cüzdana ait değil.</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">İşlem tutarı çok düşük</translation> </message> @@ -3791,10 +4149,6 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">İşlem çok büyük</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">-maxsigcachesize: ' %s' MiB için bellek konumlandırılamıyor.</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Bu bilgisayarda %s ögesine bağlanılamadı (bağlanma %s hatasını verdi)</translation> </message> @@ -3831,10 +4185,34 @@ Cüzdan yedeği geri yüklenemiyor.</translation> <translation type="unfinished">-onlynet için bilinmeyen bir ağ belirtildi: '%s'</translation> </message> <message> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished">Tanınmayan seçenek "%s" sağlanan -test=<option>.</translation> + </message> + <message> + <source>Unsupported global logging level %s=%s. Valid values: %s.</source> + <translation type="unfinished">Desteklenmeyen global günlük seviyesi %s=%s. Geçerli değer:%s.</translation> + </message> + <message> + <source>Wallet file creation failed: %s</source> + <translation type="unfinished">%s Cüzdan dosyaları oluşturulamadı.</translation> + </message> + <message> + <source>acceptstalefeeestimates is not supported on %s chain.</source> + <translation type="unfinished">acceptstalefeeestimates %s blok zincirinde desteklenmiyor.</translation> + </message> + <message> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished">Desteklenmeyen günlük kategorisi %s=%s.</translation> </message> <message> + <source>Error: Could not add watchonly tx %s to watchonly wallet</source> + <translation type="unfinished">Hata: Sadece izleme %s cüzdanı. tx izleme cüzdanına eklenemedi</translation> + </message> + <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">Hata: Yalnızca izlenen işlemler silinemedi.</translation> + </message> + <message> <source>User Agent comment (%s) contains unsafe characters.</source> <translation type="unfinished">Kullanıcı Aracı açıklaması (%s) güvensiz karakterler içermektedir.</translation> </message> diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index 7679222848..f4c47b46b2 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -7,7 +7,7 @@ </message> <message> <source>Create a new address</source> - <translation type="unfinished">Створити нову адресу</translation> + <translation type="unfinished">Додати нову адрессу</translation> </message> <message> <source>&New</source> @@ -39,7 +39,7 @@ </message> <message> <source>&Export</source> - <translation type="unfinished">&Експортувати</translation> + <translation type="unfinished">Експортувати</translation> </message> <message> <source>&Delete</source> @@ -184,6 +184,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Введіть стару та нову парольну фразу для гаманця.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Продовжити</translation> + </message> + <message> + <source>Back</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> @@ -457,6 +465,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 ГБ</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">гаманець за замовчуванням</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -559,7 +571,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Backup Wallet…</source> - <translation type="unfinished">&Резервне копіювання гаманця…</translation> + <translation type="unfinished">&Резервне копіювання гаманця</translation> </message> <message> <source>&Change Passphrase…</source> @@ -591,15 +603,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">Закрити гаманець…</translation> + <translation type="unfinished">Закрити Гаманець…</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Створити гаманець…</translation> + <translation type="unfinished">Створити Гаманець…</translation> </message> <message> <source>Close All Wallets…</source> - <translation type="unfinished">Закрити всі гаманці…</translation> + <translation type="unfinished">Закрити Всі Гаманці…</translation> </message> <message> <source>&File</source> @@ -619,7 +631,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">Триває синхронізація заголовків (%1%)…</translation> + <translation type="unfinished">Синхронізація заголовків (%1%)…</translation> </message> <message> <source>Synchronizing with network…</source> @@ -651,7 +663,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">Параметри &командного рядка</translation> + <translation type="unfinished">П&араметри командного рядка</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -695,7 +707,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">Завантажити частково підписану біткоїн-транзакцію (PSBT) з файлу</translation> + <translation type="unfinished">Завантажити частково підписану біткоїн-транзакцію (PSBT)</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -715,11 +727,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Sending addresses</source> - <translation type="unfinished">Адреси для &відправлення</translation> + <translation type="unfinished">&Адреси для відправлення</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">Адреси для &отримання</translation> + <translation type="unfinished">&Адреси для отримання</translation> </message> <message> <source>Open a bitcoin: URI</source> @@ -772,10 +784,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -1186,10 +1194,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -2351,6 +2355,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Кількість підключень</translation> </message> <message> + <source>Local Addresses</source> + <translation type="unfinished">Локальні адреси</translation> + </message> + <message> <source>Block chain</source> <translation type="unfinished">Блокчейн</translation> </message> @@ -2399,6 +2407,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Виберіть учасника для перегляду детальнішої інформації</translation> </message> <message> + <source>Hide Peers Detail</source> + <translation type="unfinished">Приховати відомості про учасника</translation> + </message> + <message> <source>The transport layer version: %1</source> <translation type="unfinished">Версія транспортного рівня: %1</translation> </message> @@ -2407,10 +2419,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Траспорт</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Ідентифікатор сесії BIP324 у hex форматі, якщо є.</translation> - </message> - <message> <source>Session ID</source> <translation type="unfinished">ID сесії</translation> </message> @@ -2709,6 +2717,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Мережева активність вимкнена.</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Відсутні</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">Виконання команди без гаманця</translation> </message> @@ -3442,10 +3454,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">&Підписати повідомлення</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">Ви можете підписувати повідомлення/угоди своїми адресами, щоб довести можливість отримання біткоїнів, що будуть надіслані на них. Остерігайтеся підписувати будь-що нечітке чи неочікуване, так як за допомогою фішинг-атаки вас можуть спробувати ввести в оману для отримання вашого підпису під чужими словами. Підписуйте лише чіткі твердження, з якими ви повністю згодні.</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">Біткоїн-адреса для підпису цього повідомлення</translation> </message> @@ -3530,10 +3538,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Перевірте адресу та спробуйте ще раз.</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">Введена адреса не відноситься до ключа.</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">Розблокування гаманця було скасоване.</translation> </message> @@ -4115,11 +4119,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT-транзакцію скопійовано</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Скопійовано в буфер обміну</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">Не можливо підписати транзакцію.</translation> </message> @@ -4131,16 +4130,12 @@ Go to File > Open Wallet to load a wallet. <source>Can't display address</source> <translation type="unfinished">Неможливо показати адресу</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">гаманець за замовчуванням</translation> - </message> </context> <context> <name>WalletView</name> <message> <source>&Export</source> - <translation type="unfinished">&Експортувати</translation> + <translation type="unfinished">Експортувати</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -4192,7 +4187,7 @@ Go to File > Open Wallet to load a wallet. </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 прохання прослухати на порту %u . Цей порт вважається «поганим» і тому навряд чи до нього підключиться який-небудь бенкет. Перегляньте doc/p2p-bad-ports.md для отримання детальної інформації та повного списку.</translation> + <translation type="unfinished">Запит %s на прослуховування порту %u. Цей порт вважається «поганим» і тому навряд чи до нього підключиться який-небудь учасник. Перегляньте doc/p2p-bad-ports.md для отримання подробиць та повного списку.</translation> </message> <message> <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> @@ -4267,10 +4262,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Не вказано формат файлу гаманця. Щоб використовувати createfromdump, потрібно вказати -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> - <translation type="unfinished">Перевірте правильність дати та часу свого комп'ютера. Якщо ваш годинник налаштовано невірно, %s не буде працювати належним чином.</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">Будь ласка, зробіть внесок, якщо ви знаходите %s корисним. Відвідайте %s для отримання додаткової інформації про програмне забезпечення.</translation> </message> @@ -4379,10 +4370,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool має бути не менше %d МБ</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Сталася критична внутрішня помилка, дивіться подробиці в debug.log</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">Не вдалося перетворити -%s адресу: '%s'</translation> </message> @@ -4973,10 +4960,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">Транзакція занадто велика</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Не вдалося виділити пам'ять для -maxsigcachesize: '%s' МіБ</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Не вдалося прив'язатися до %s на цьому комп'ютері (bind повернув помилку: %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_ur.ts b/src/qt/locale/bitcoin_ur.ts index c0ff575864..de2357da71 100644 --- a/src/qt/locale/bitcoin_ur.ts +++ b/src/qt/locale/bitcoin_ur.ts @@ -2,12 +2,12 @@ <context> <name>AddressBookPage</name> <message> - <source>Create a new address</source> - <translation type="unfinished">نیا پتہ تخلیق کریں</translation> + <source>Right-click to edit address or label</source> + <translation type="unfinished">ایڈریس یا لیبل میں ترمیم کرنے کے لیے رائیٹ کلک کریں</translation> </message> <message> - <source>&New</source> - <translation type="unfinished">اور نیا</translation> + <source>Create a new address</source> + <translation type="unfinished">نیا ایڈریس بنائیں</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> @@ -89,6 +89,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> @@ -171,6 +179,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">پرس کے لئے پرانا پاسفریج اور نیا پاسفریز درج کریں۔</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">جاری رکھیں</translation> + </message> + <message> + <source>Back</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> @@ -211,6 +227,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">آپ کا والٹ کھولنے کے لیے جو خفیہ لفظ (passphrase) دیا گیا ہے وہ غلط ہے۔ اس میں ایک خالی حرف (null character) موجود ہے۔ اگر یہ خفیہ لفظ اس سافٹ ویئر کے ورژن 25.0 سے پہلے والے ورژن میں بنایا گیا تھا تو براہِ کرم پہلے خالی حرف سے پہلے تک کے حروف استعمال کرکے دوبارہ کوشش کریں۔ اگر یہ کامیاب ہوجائے تو مستقبل میں اس مسئلے سے بچنے کے لیے نیا خفیہ لفظ مقرر کرلیں۔</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">والیٹ کا پاسفریز کامیابی کے ساتھ تبدیل کردیا گیا تھا۔</translation> </message> @@ -265,6 +285,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> @@ -335,7 +360,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <numerusform /> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">پہلے سے طے شدہ والیٹ</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -563,6 +592,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">جزوی طور پر دستخط شدہ بٹ کوائن ٹرانزیکشن لوڈ کریں۔</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">PSBT کو &clipboard سے لوڈ کریں...</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">کلپ بورڈ سے جزوی طور پر دستخط شدہ بٹ کوائن ٹرانزیکشن لوڈ کریں۔</translation> </message> @@ -599,10 +632,28 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">والیٹ بند کریں</translation> </message> <message> + <source>Restore Wallet…</source> + <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> + <translation type="unfinished">والیٹ بحال کریں...</translation> + </message> + <message> + <source>Restore a wallet from a backup file</source> + <extracomment>Status tip for Restore Wallet menu item</extracomment> + <translation type="unfinished">بیک اپ فائل سے والیٹ بحال کریں</translation> + </message> + <message> <source>Close all wallets</source> <translation type="unfinished">تمام والیٹس بند کریں</translation> </message> <message> + <source>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> @@ -615,14 +666,25 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -672,6 +734,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -733,7 +799,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Private key <b>disabled</b></source> - <translation type="unfinished">نجی کلید <b>غیر فعال <b/>ہے۔</translation> + <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>Original message:</source> @@ -904,6 +974,27 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>MigrateWalletActivity</name> + <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 ہوگا اور یہ اس والیٹ کی ڈائرکٹری میں مل سکتی ہے۔ غلط منتقلی کی صورت میں، بیک اپ کو "Restore Wallet" فعالیت کے ساتھ بحال کیا جا سکتا ہے۔</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">والیٹ منتقل کریں</translation> + </message> + </context> +<context> <name>OpenWalletActivity</name> <message> <source>Open wallet failed</source> @@ -914,16 +1005,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">والیٹ کھولنے کی انتباہ</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">پہلے سے طے شدہ والیٹ</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">والیٹ کھولیں</translation> </message> </context> <context> + <name>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> + </context> +<context> <name>WalletController</name> <message> <source>Close wallet</source> @@ -949,6 +1044,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -1037,6 +1136,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">بھیجنے کے پتے میں ترمیم کریں۔</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> @@ -1333,6 +1440,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">کنفیگریشن کے اختیارات</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">جاری رکھیں</translation> + </message> + <message> <source>Error</source> <translation type="unfinished">نقص</translation> </message> @@ -2110,10 +2221,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">دستخط - ایک پیغام پر دستخط / تصدیق کریں۔</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">آپ یہ ثابت کرنے کے لیے اپنے پتوں کے ساتھ پیغامات/معاہدوں پر دستخط کر سکتے ہیں کہ آپ ان پر بھیجے گئے بٹ کوائنز وصول کر سکتے ہیں۔ ہوشیار رہیں کہ کسی بھی مبہم یا بے ترتیب پر دستخط نہ کریں، کیونکہ فریب دہی کے حملے آپ کو اپنی شناخت پر دستخط کرنے کے لیے دھوکہ دینے کی کوشش کر سکتے ہیں۔ صرف مکمل تفصیلی بیانات پر دستخط کریں جن سے آپ اتفاق کرتے ہیں۔</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">پیغام پر دستخط کرنے کے لیے بٹ کوائن کا پتہ</translation> </message> @@ -2288,11 +2395,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <source>Send Coins</source> <translation type="unfinished">سکے بھیجیں۔</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">پہلے سے طے شدہ والیٹ</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> @@ -2303,6 +2406,11 @@ If you are receiving this error you should request the merchant provide a BIP21 <source>Export the data in the current tab to a file</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> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_uz.ts b/src/qt/locale/bitcoin_uz.ts index b7193d36b8..0ecf99ac43 100644 --- a/src/qt/locale/bitcoin_uz.ts +++ b/src/qt/locale/bitcoin_uz.ts @@ -365,6 +365,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 ГБ</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">standart hamyon</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -443,7 +447,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Hamyon shifrlanishi uchun ishlatilgan maxfiy so'zni almashtirish</translation> + <translation type="unfinished">Паролни ўзгартириш ҳамённи кодлашда фойдаланилади</translation> </message> <message> <source>&Send</source> @@ -463,7 +467,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">Hamyonga tegishli bo'lgan maxfiy so'zlarni shifrlash</translation> + <translation type="unfinished">Ҳамёнингизга тегишли махфий калитларни кодлаш</translation> </message> <message> <source>&Backup Wallet…</source> @@ -479,7 +483,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Bitkoin manzillarga ega ekaningizni tasdiqlash uchun xabarni signlang</translation> + <translation type="unfinished">Bitcoin манзилидан унинг эгаси эканлигингизни исботлаш учун хабарлар ёзинг</translation> </message> <message> <source>&Verify message…</source> @@ -487,7 +491,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished">Xabar belgilangan Bitkoin manzillari bilan imzolanganligiga ishonch hosil qilish uchun ularni tasdiqlang</translation> + <translation type="unfinished">Хабарларни махсус Bitcoin манзилларингиз билан ёзилганлигига ишонч ҳосил қилиш учун уларни тасдиқланг</translation> </message> <message> <source>&Load PSBT from file…</source> @@ -511,19 +515,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&File</source> - <translation type="unfinished">&Fayl</translation> + <translation type="unfinished">&Файл</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">&Sozlamalar</translation> + <translation type="unfinished">& Созламалар</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">&Yordam</translation> + <translation type="unfinished">&Ёрдам</translation> </message> <message> <source>Tabs toolbar</source> - <translation type="unfinished">Yorliqlar menyusi</translation> + <translation type="unfinished">Ички ойналар асбоблар панели</translation> </message> <message> <source>Syncing Headers (%1%)…</source> @@ -547,19 +551,19 @@ 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">Тўловлар (QR кодлари ва bitcoin ёрдамида яратишлар: URI’лар) сўраш</translation> + <translation type="unfinished">To'lovlarni so'rash(QR kolar va bitkoin yaratish: URL manzillar)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Фойдаланилган жўнатилган манзиллар ва ёрлиқлар рўйхатини кўрсатиш</translation> + <translation type="unfinished">Manzillar va yorliqlar ro'yxatini ko'rsatish</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Фойдаланилган қабул қилинган манзиллар ва ёрлиқлар рўйхатини кўрсатиш</translation> + <translation type="unfinished">Qabul qilish manzillari va yorliqlar ro'yxatini ko'rsatish</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">&Буйруқлар сатри мосламалари</translation> + <translation type="unfinished">&Command-line sozlamalari</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -570,7 +574,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 орқада</translation> + <translation type="unfinished">%1 yonida</translation> </message> <message> <source>Catching up…</source> @@ -578,27 +582,27 @@ 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">Сўнги қабул қилинган блок %1 олдин яратилган.</translation> + <translation type="unfinished">%1 oldin oxirgi marta blok qabul qilingan edi.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Бундан кейинги пул ўтказмалари кўринмайдиган бўлади.</translation> + <translation type="unfinished">Shundan keyingi operatsiyalar hali ko'rinmaydi.</translation> </message> <message> <source>Error</source> - <translation type="unfinished">Хатолик</translation> + <translation type="unfinished">Xatolik</translation> </message> <message> <source>Warning</source> - <translation type="unfinished">Диққат</translation> + <translation type="unfinished">Eslatma</translation> </message> <message> <source>Information</source> - <translation type="unfinished">Маълумот</translation> + <translation type="unfinished">Informatsiya</translation> </message> <message> <source>Up to date</source> - <translation type="unfinished">Янгиланган</translation> + <translation type="unfinished">Hozirgi kunda</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> @@ -634,7 +638,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Ochiq hamyon</translation> + <translation type="unfinished">Hamyonni ochish</translation> </message> <message> <source>Open a wallet</source> @@ -657,10 +661,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Umumiy ko'rinish menyusidagi qiymatlarni maskirovka qilish</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Hamyonlar mavjud emas</translation> </message> @@ -841,7 +841,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Tree mode</source> - <translation type="unfinished">Daraxt rejimi</translation> + <translation type="unfinished">Дарахт усулида</translation> </message> <message> <source>List mode</source> @@ -849,7 +849,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Amount</source> - <translation type="unfinished">Miqdor</translation> + <translation type="unfinished">Миқдори</translation> </message> <message> <source>Received with label</source> @@ -865,11 +865,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Confirmations</source> - <translation type="unfinished">Tasdiqlar</translation> + <translation type="unfinished">Тасдиқлашлар</translation> </message> <message> <source>Confirmed</source> - <translation type="unfinished">Tasdiqlangan</translation> + <translation type="unfinished">Тасдиқланди</translation> </message> <message> <source>Copy amount</source> @@ -893,7 +893,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>L&ock unspent</source> - <translation type="unfinished">Sarflanmagan miqdorlarni q&ulflash</translation> + <translation type="unfinished">Sarflanmagan tranzaksiyalarni q&ulflash</translation> </message> <message> <source>&Unlock unspent</source> @@ -917,11 +917,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Copy change</source> - <translation type="unfinished">O'zgarishni nusxalash</translation> + <translation type="unfinished">Нусха қайтими</translation> </message> <message> <source>(%1 locked)</source> - <translation type="unfinished">(%1 qulflangan)</translation> + <translation type="unfinished">(%1 қулфланган)</translation> </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> @@ -929,7 +929,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(no label)</source> - <translation type="unfinished">(Ёрлиқ мавжуд эмас)</translation> + <translation type="unfinished">(Yorliqlar mavjud emas)</translation> </message> <message> <source>change from %1 (%2)</source> @@ -989,10 +989,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Hamyonni ochish ogohlantirishi</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Ochiq hamyon</translation> @@ -1821,6 +1817,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&Manzilni nusxalash</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Йўқ</translation> + </message> + <message> <source>via %1</source> <translation type="unfinished">%1 орқали</translation> </message> @@ -2078,7 +2078,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Copy change</source> - <translation type="unfinished">O'zgarishni nusxalash</translation> + <translation type="unfinished">Нусха қайтими</translation> </message> <message> <source>%1 to %2</source> @@ -2259,7 +2259,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Amount</source> - <translation type="unfinished">Miqdor</translation> + <translation type="unfinished">Миқдори</translation> </message> <message> <source>true</source> @@ -2469,11 +2469,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Send Coins</source> <translation type="unfinished">Тангаларни жунат</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts index f335cb39ab..addb6fb9e8 100644 --- a/src/qt/locale/bitcoin_uz@Cyrl.ts +++ b/src/qt/locale/bitcoin_uz@Cyrl.ts @@ -370,6 +370,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 ГБ</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">standart hamyon</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -639,7 +643,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Ochiq hamyon</translation> + <translation type="unfinished">Hamyonni ochish</translation> </message> <message> <source>Open a wallet</source> @@ -662,10 +666,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Umumiy ko'rinish menyusidagi qiymatlarni maskirovka qilish</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Hamyonlar mavjud emas</translation> </message> @@ -898,7 +898,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>L&ock unspent</source> - <translation type="unfinished">Sarflanmagan miqdorlarni q&ulflash</translation> + <translation type="unfinished">Sarflanmagan tranzaksiyalarni q&ulflash</translation> </message> <message> <source>&Unlock unspent</source> @@ -994,10 +994,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Hamyonni ochish ogohlantirishi</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Ochiq hamyon</translation> @@ -1826,6 +1822,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&Manzilni nusxalash</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Йўқ</translation> + </message> + <message> <source>via %1</source> <translation type="unfinished">%1 орқали</translation> </message> @@ -2474,11 +2474,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Send Coins</source> <translation type="unfinished">Тангаларни жунат</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_uz@Latn.ts b/src/qt/locale/bitcoin_uz@Latn.ts index 823b21be06..75ce7b974d 100644 --- a/src/qt/locale/bitcoin_uz@Latn.ts +++ b/src/qt/locale/bitcoin_uz@Latn.ts @@ -370,6 +370,10 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> <source>%1 GB</source> <translation type="unfinished">%1 ГБ</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">standart hamyon</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -448,7 +452,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Hamyon shifrlanishi uchun ishlatilgan maxfiy so'zni almashtirish</translation> + <translation type="unfinished">Паролни ўзгартириш ҳамённи кодлашда фойдаланилади</translation> </message> <message> <source>&Send</source> @@ -468,7 +472,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">Hamyonga tegishli bo'lgan maxfiy so'zlarni shifrlash</translation> + <translation type="unfinished">Ҳамёнингизга тегишли махфий калитларни кодлаш</translation> </message> <message> <source>&Backup Wallet…</source> @@ -484,7 +488,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Bitkoin manzillarga ega ekaningizni tasdiqlash uchun xabarni signlang</translation> + <translation type="unfinished">Bitcoin манзилидан унинг эгаси эканлигингизни исботлаш учун хабарлар ёзинг</translation> </message> <message> <source>&Verify message…</source> @@ -492,7 +496,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished">Xabar belgilangan Bitkoin manzillari bilan imzolanganligiga ishonch hosil qilish uchun ularni tasdiqlang</translation> + <translation type="unfinished">Хабарларни махсус Bitcoin манзилларингиз билан ёзилганлигига ишонч ҳосил қилиш учун уларни тасдиқланг</translation> </message> <message> <source>&Load PSBT from file…</source> @@ -516,19 +520,19 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>&File</source> - <translation type="unfinished">&Fayl</translation> + <translation type="unfinished">&Файл</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">&Sozlamalar</translation> + <translation type="unfinished">& Созламалар</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">&Yordam</translation> + <translation type="unfinished">&Ёрдам</translation> </message> <message> <source>Tabs toolbar</source> - <translation type="unfinished">Yorliqlar menyusi</translation> + <translation type="unfinished">Ички ойналар асбоблар панели</translation> </message> <message> <source>Syncing Headers (%1%)…</source> @@ -552,19 +556,19 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Тўловлар (QR кодлари ва bitcoin ёрдамида яратишлар: URI’лар) сўраш</translation> + <translation type="unfinished">To'lovlarni so'rash(QR kolar va bitkoin yaratish: URL manzillar)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Фойдаланилган жўнатилган манзиллар ва ёрлиқлар рўйхатини кўрсатиш</translation> + <translation type="unfinished">Manzillar va yorliqlar ro'yxatini ko'rsatish</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Фойдаланилган қабул қилинган манзиллар ва ёрлиқлар рўйхатини кўрсатиш</translation> + <translation type="unfinished">Qabul qilish manzillari va yorliqlar ro'yxatini ko'rsatish</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">&Буйруқлар сатри мосламалари</translation> + <translation type="unfinished">&Command-line sozlamalari</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -575,7 +579,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 орқада</translation> + <translation type="unfinished">%1 yonida</translation> </message> <message> <source>Catching up…</source> @@ -583,27 +587,27 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">Сўнги қабул қилинган блок %1 олдин яратилган.</translation> + <translation type="unfinished">%1 oldin oxirgi marta blok qabul qilingan edi.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Бундан кейинги пул ўтказмалари кўринмайдиган бўлади.</translation> + <translation type="unfinished">Shundan keyingi operatsiyalar hali ko'rinmaydi.</translation> </message> <message> <source>Error</source> - <translation type="unfinished">Хатолик</translation> + <translation type="unfinished">Xatolik</translation> </message> <message> <source>Warning</source> - <translation type="unfinished">Диққат</translation> + <translation type="unfinished">Eslatma</translation> </message> <message> <source>Information</source> - <translation type="unfinished">Маълумот</translation> + <translation type="unfinished">Informatsiya</translation> </message> <message> <source>Up to date</source> - <translation type="unfinished">Янгиланган</translation> + <translation type="unfinished">Hozirgi kunda</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> @@ -639,7 +643,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Ochiq hamyon</translation> + <translation type="unfinished">Hamyonni ochish</translation> </message> <message> <source>Open a wallet</source> @@ -662,10 +666,6 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> <translation type="unfinished">Umumiy ko'rinish menyusidagi qiymatlarni maskirovka qilish</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Hamyonlar mavjud emas</translation> </message> @@ -994,10 +994,6 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> <translation type="unfinished">Hamyonni ochish ogohlantirishi</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Ochiq hamyon</translation> @@ -1826,6 +1822,10 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> <translation type="unfinished">&Manzilni nusxalash</translation> </message> <message> + <source>None</source> + <translation type="unfinished">Йўқ</translation> + </message> + <message> <source>via %1</source> <translation type="unfinished">%1 орқали</translation> </message> @@ -1964,7 +1964,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>(no label)</source> - <translation type="unfinished">(Yorliqlar mavjud emas)</translation> + <translation type="unfinished">(Ёрлиқ мавжуд эмас)</translation> </message> <message> <source>(no message)</source> @@ -2122,7 +2122,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>(no label)</source> - <translation type="unfinished">(Yorliqlar mavjud emas)</translation> + <translation type="unfinished">(Ёрлиқ мавжуд эмас)</translation> </message> </context> <context> @@ -2330,7 +2330,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> </message> <message> <source>(no label)</source> - <translation type="unfinished">(Yorliqlar mavjud emas)</translation> + <translation type="unfinished">(Ёрлиқ мавжуд эмас)</translation> </message> <message> <source>Transaction status. Hover over this field to show number of confirmations.</source> @@ -2474,11 +2474,7 @@ Kirish faqat 'legacy' turidagi manzillar uchun.</translation> <source>Send Coins</source> <translation type="unfinished">Тангаларни жунат</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">standart hamyon</translation> - </message> -</context> + </context> <context> <name>WalletView</name> <message> diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts index fe69b4c1f3..f675452e26 100644 --- a/src/qt/locale/bitcoin_vi.ts +++ b/src/qt/locale/bitcoin_vi.ts @@ -70,10 +70,6 @@ <translation type="unfinished">Xuất danh sách địa chỉ</translation> </message> <message> - <source>Sending addresses - %1</source> - <translation type="unfinished">Địa chỉ gửi%1</translation> - </message> - <message> <source>Exporting Failed</source> <translation type="unfinished">Quá trình xuất dữ liệu đã thất bại</translation> </message> @@ -156,6 +152,10 @@ <translation type="unfinished">Nhập mật khẩu cũ và mật khẩu mới cho ví.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Tiếp tục</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">Xin lưu ý rằng mã hoá ví của bạn không thể bảo về hoàn toàn Bitcoin của bạn khỏi việc bị đánh cắp mới các phần mềm gián điệp nhiễm vào máy tính của bạn.</translation> </message> @@ -290,7 +290,11 @@ <numerusform>%nnăm</numerusform> </translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">ví mặc định</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -415,18 +419,6 @@ <translation type="unfinished">Đóng tất cả các ví…</translation> </message> <message> - <source>&File</source> - <translation type="unfinished">&Tệp</translation> - </message> - <message> - <source>&Settings</source> - <translation type="unfinished">&Cài đặt</translation> - </message> - <message> - <source>&Help</source> - <translation type="unfinished">&Giúp đỡ</translation> - </message> - <message> <source>Tabs toolbar</source> <translation type="unfinished">Các thanh công cụ</translation> </message> @@ -446,6 +438,10 @@ <source>Processing blocks on disk…</source> <translation type="unfinished">Xử lý khối trên đĩa…</translation> </message> + <message> + <source>Connecting to peers…</source> + <translation type="unfinished">Kết nối với các peer…</translation> + </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> @@ -457,6 +453,10 @@ <translation type="unfinished">%1 phía sau</translation> </message> <message> + <source>Catching up…</source> + <translation type="unfinished">Đang bắt kịp...</translation> + </message> + <message> <source>Error</source> <translation type="unfinished">Lỗi</translation> </message> @@ -470,7 +470,7 @@ </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> - <translation type="unfinished">Tải một phần giao dịch Bitcoin đã ký</translation> + <translation type="unfinished">Kết nối với mạng Bitcoin thông qua một proxy SOCKS5 riêng cho các dịch vụ Tor hành.</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -490,11 +490,11 @@ </message> <message> <source>&Sending addresses</source> - <translation type="unfinished">Các địa chỉ đang &gửi</translation> + <translation type="unfinished">&Các địa chỉ đang gửi</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">Các địa chỉ đang &nhận</translation> + <translation type="unfinished">&Các địa chỉ đang nhận</translation> </message> <message> <source>Open a bitcoin: URI</source> @@ -539,10 +539,6 @@ <translation type="unfinished">Che các giá trị trong tab Tổng quan</translation> </message> <message> - <source>default wallet</source> - <translation type="unfinished">ví mặc định</translation> - </message> - <message> <source>No wallets available</source> <translation type="unfinished">Không có ví nào</translation> </message> @@ -561,6 +557,10 @@ <translation type="unfinished">Nhấn Ctrl + M</translation> </message> <message> + <source>%1 client</source> + <translation type="unfinished">%1 khách</translation> + </message> + <message> <source>&Hide</source> <translation type="unfinished">&Ẩn</translation> </message> @@ -669,10 +669,6 @@ <context> <name>OpenWalletActivity</name> <message> - <source>default wallet</source> - <translation type="unfinished">ví mặc định</translation> - </message> - <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Mớ ví</translation> @@ -1115,10 +1111,6 @@ <source>Label</source> <translation type="unfinished">Nhãn</translation> </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(không có nhãn)</translation> - </message> </context> <context> <name>SendCoinsDialog</name> @@ -1156,11 +1148,7 @@ <numerusform>Ước tính sẽ bắt đầu xác nhận trong %n khối.</numerusform> </translation> </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(không có nhãn)</translation> - </message> -</context> + </context> <context> <name>SendCoinsEntry</name> <message> @@ -1214,10 +1202,6 @@ <source>Label</source> <translation type="unfinished">Nhãn</translation> </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(không có nhãn)</translation> - </message> </context> <context> <name>TransactionView</name> @@ -1255,18 +1239,6 @@ </message> </context> <context> - <name>WalletModel</name> - <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">Đã sao chép vào bảng tạm.</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">ví mặc định</translation> - </message> -</context> -<context> <name>WalletView</name> <message> <source>&Export</source> @@ -1304,6 +1276,10 @@ <translation type="unfinished">Không thể đặt -forcednsseed thành true khi đặt -dnsseed thành false.</translation> </message> <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation type="unfinished">Không thể ghi vào thư mục dữ liệu '%s'; kiểm tra lại quyền.</translation> + </message> + <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> <translation type="unfinished">Không thể cung cấp các kết nối cụ thể và yêu cầu addrman tìm các kết nối gửi đi cùng một lúc.</translation> </message> @@ -1450,10 +1426,6 @@ Không thể khôi phục bản sao lưu của ví.</translation> <translation type="unfinished">Giao dịch cần thay đổi địa chỉ, nhưng chúng tôi không thể tạo địa chỉ đó.</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">Không có khả năng để phân bổ bộ nhớ cho -maxsigcachesize: '%s' MiB</translation> - </message> - <message> <source>Unable to find UTXO for external input</source> <translation type="unfinished">Không thể tìm UTXO cho đầu vào từ bên ngoài</translation> </message> diff --git a/src/qt/locale/bitcoin_yue.ts b/src/qt/locale/bitcoin_yue.ts index 1ed37d36ce..ea7a1e177f 100644 --- a/src/qt/locale/bitcoin_yue.ts +++ b/src/qt/locale/bitcoin_yue.ts @@ -179,6 +179,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">输入钱包的旧密码和新密码。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</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> @@ -261,6 +269,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -432,7 +444,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 GB (十億位元組)</translation> </message> -</context> + </context> <context> <name>BitcoinGUI</name> <message> @@ -510,7 +522,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">修改钱包加密密码</translation> + <translation type="unfinished">更改钱包密码</translation> </message> <message> <source>&Send</source> @@ -521,16 +533,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">接收(&R)</translation> </message> <message> - <source>&Options…</source> - <translation type="unfinished">选项(&O)</translation> - </message> - <message> - <source>&Encrypt Wallet…</source> - <translation type="unfinished">加密钱包(&E)</translation> - </message> - <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">把你钱包中的私钥加密</translation> + <translation type="unfinished">將錢包中之密鑰加密</translation> </message> <message> <source>&Backup Wallet…</source> @@ -541,22 +545,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">修改密码(&C)</translation> </message> <message> - <source>Sign &message…</source> - <translation type="unfinished">签名消息(&M)</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">验证消息(&V)</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">从文件加载PSBT(&L)...</translation> </message> @@ -573,32 +565,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">创建钱包...</translation> </message> <message> - <source>Close All Wallets…</source> - <translation type="unfinished">关闭所有钱包...</translation> - </message> - <message> <source>&File</source> - <translation type="unfinished">文件(&F)</translation> + <translation type="unfinished">&文件</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">设置(&S)</translation> + <translation type="unfinished">&設定</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">帮助(&H)</translation> + <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> + <translation type="unfinished">分頁工具列</translation> </message> <message> <source>Indexing blocks on disk…</source> @@ -610,7 +590,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> @@ -622,7 +602,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">顯示已使用過的接收地址和標籤清單</translation> + <translation type="unfinished">显示用过的收款地址和标签的列表</translation> </message> <message> <source>&Command-line options</source> @@ -640,15 +620,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">赶上...</translation> + <translation type="unfinished">正在追上进度...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">最新收到的区块产生于 %1 之前。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">在此之后的交易尚不可见</translation> </message> <message> <source>Error</source> @@ -660,7 +640,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Information</source> - <translation type="unfinished">資訊</translation> + <translation type="unfinished">信息</translation> </message> <message> <source>Up to date</source> @@ -734,7 +714,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation type="unfinished">显示 %1 帮助信息,获取可用命令行选项列表</translation> + <translation type="unfinished">显示%1帮助消息以获得可能包含Bitcoin命令行选项的列表</translation> </message> <message> <source>&Mask values</source> @@ -745,10 +725,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -786,15 +762,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 client</source> - <translation type="unfinished">%1 客户端</translation> + <translation type="unfinished">%1 客戶端</translation> </message> <message> <source>&Hide</source> - <translation type="unfinished">隐藏(&H)</translation> + <translation type="unfinished">&躲</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">&顯示</translation> + <translation type="unfinished">显示(&H)</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -806,26 +782,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <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> + <translation type="unfinished">關閉網路紀錄</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">預先同步標頭(%1%)</translation> + <translation type="unfinished">预同步区块头 (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -905,7 +871,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">錢包<b>已加密</b>並且<b>上鎖中</b></translation> + <translation type="unfinished">錢包已<b>加密</b>並且<b>上鎖中</b></translation> </message> <message> <source>Original message:</source> @@ -927,11 +893,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Quantity:</source> - <translation type="unfinished">总量:</translation> + <translation type="unfinished">數量:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished">位元組數:</translation> + <translation type="unfinished">位元組:</translation> </message> <message> <source>Amount:</source> @@ -946,14 +912,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">計費後金額:</translation> </message> <message> - <source>Change:</source> - <translation type="unfinished">找零:</translation> - </message> - <message> - <source>(un)select all</source> - <translation type="unfinished">全(不)选</translation> - </message> - <message> <source>Tree mode</source> <translation type="unfinished">树状模式</translation> </message> @@ -966,22 +924,10 @@ Signing is only possible with addresses of the type 'legacy'.</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>Confirmed</source> - <translation type="unfinished">已确认</translation> - </message> - <message> <source>Copy amount</source> <translation type="unfinished">复制金额</translation> </message> @@ -1006,10 +952,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">锁定未花费(&O)</translation> </message> <message> - <source>&Unlock unspent</source> - <translation type="unfinished">解锁未花费(&U)</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">复制数目</translation> </message> @@ -1045,11 +987,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>change from %1 (%2)</source> <translation type="unfinished">找零來自於 %1 (%2)</translation> </message> - <message> - <source>(change)</source> - <translation type="unfinished">(找零)</translation> - </message> -</context> + </context> <context> <name>CreateWalletActivity</name> <message> @@ -1141,10 +1079,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1480,7 +1414,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <source>Paste address from clipboard</source> <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> </context> <context> @@ -1491,11 +1425,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>&Main</source> - <translation type="unfinished">主要(&M)</translation> + <translation type="unfinished">&主要(&Main)</translation> </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">在登入系统后自动启动 %1</translation> + <translation type="unfinished">登錄系統%1後自動啟動。</translation> </message> <message> <source>&Start %1 on system login</source> @@ -1507,11 +1441,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Size of &database cache</source> - <translation type="unfinished">数据库缓存大小(&D)</translation> + <translation type="unfinished">資料庫快取的大小 </translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">脚本验证线程数(&V)</translation> + <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> @@ -2262,10 +2196,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2372,6 +2302,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/类型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2540,7 +2474,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 天(&A)</translation> + <translation type="unfinished">一天</translation> </message> <message> <source>1 &week</source> @@ -2564,6 +2498,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">无</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -2599,7 +2537,7 @@ For more information on using this console, type %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(节点: %1)</translation> + <translation type="unfinished">(同儕:%1)</translation> </message> <message> <source>via %1</source> @@ -2789,11 +2727,11 @@ For more information on using this console, type %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">验证(&V)</translation> + <translation type="unfinished">&驗證</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">在像是硬件钱包屏幕的地方检验这个地址</translation> + <translation type="unfinished">在例如硬體錢包螢幕上驗證這個地址</translation> </message> <message> <source>&Save Image…</source> @@ -2931,7 +2869,7 @@ For more information on using this console, type %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">输入...</translation> + <translation type="unfinished">輸入…</translation> </message> <message> <source>Choose…</source> @@ -2945,9 +2883,9 @@ For more information on using this console, type %6. <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">指定交易虚拟大小的每kB (1,000字节) 自定义费率。 + <translation type="unfinished">指定每千字節(1,000字節)交易虛擬大小的自訂手續費。 -附注:因为矿工费是按字节计费的,所以如果费率是“每kvB支付100聪”,那么对于一笔500虚拟字节 (1kvB的一半) 的交易,最终将只会产生50聪的矿工费。(译注:这里就是提醒单位是字节,而不是千字节,如果搞错的话,矿工费会过低,导致交易长时间无法确认,或者压根无法发出)</translation> +注意:由於手續費是按每字節計算的,對於虛擬大小為500字節(半千字節)的交易,手續費率為「每千字節100聰」,最終將只收取50聰的手續費。</translation> </message> <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> @@ -3062,6 +3000,10 @@ 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 balance:</source> + <translation type="unfinished">外部餘額:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">或</translation> </message> @@ -3070,6 +3012,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">你可以之後再提高手續費(有 BIP-125 手續費追加的標記)</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">請檢查您的交易提案。這將產生部分簽名的比特幣交易(PSBT),您可以儲存或複製該交易,然後使用簽名。離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 from wallet '%2'</source> <translation type="unfinished">%1 来自钱包 “%2”</translation> </message> @@ -3201,7 +3148,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Remove this entry</source> @@ -3258,10 +3205,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">簽署訊息(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以使用您的地址簽名訊息/協議,以證明您可以接收發送給他們的比特幣。但是請小心,不要簽名語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽名的手法來冒充是你。只有簽名您同意的詳細內容。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3271,7 +3214,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Enter the message you want to sign here</source> @@ -3346,10 +3289,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -3402,6 +3341,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <source>kB/s</source> + <translation type="unfinished">千字節/秒</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -3780,7 +3726,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Confirmed</source> - <translation type="unfinished">已确认</translation> + <translation type="unfinished">已確認</translation> </message> <message> <source>Watch-only</source> @@ -3918,11 +3864,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT已複製</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">沒辦法簽署交易。</translation> </message> @@ -3932,11 +3873,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Can't display address</source> - <translation type="unfinished">無法顯示地址</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">默认钱包</translation> + <translation type="unfinished">無法顯示錢包位址</translation> </message> </context> <context> @@ -3986,6 +3923,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s 開發人員</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation type="unfinished">%s損壞。嘗試使用錢包工具bitcoin-wallet挽救或還原備份。</translation> + </message> + <message> <source>%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 验证 -assumeutxo 快照状态失败。这表明硬件可能有问题,也可能是软件bug,或者还可能是软件被不当修改、从而让非法快照也能够被加载。因此,将关闭节点并停止使用从这个快照构建出的任何状态,并将链高度从 %d 重置到 %d 。下次启动时,节点将会不使用快照数据从 %d 继续同步。请将这个事件报告给 %s 并在报告中包括您是如何获得这份快照的。无效的链状态快照仍被保存至磁盘上,以供诊断问题的原因。</translation> </message> @@ -3999,7 +3940,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">无法锁定数据目录 %s。%s 可能已经在运行。</translation> + <translation type="unfinished">無法在資料目錄上獲取鎖定%s。%s可能已經在運行了。</translation> </message> <message> <source>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> @@ -4027,7 +3968,9 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">错误: 转储文件标识符记录不正确。得到的是 "%s",而预期本应得到的是 "%s"。</translation> + <translation type="unfinished"> +錯誤:轉存檔案識別記錄不正確。獲得%s,預期 +%s。</translation> </message> <message> <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> @@ -4066,10 +4009,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">没有提供钱包格式。要使用 createfromdump ,必须提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4178,10 +4117,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">參數 -maxmempool 至少要給 %d 百萬位元組(MB)</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">沒辦法解析 -%s 參數指定的地址: '%s'</translation> </message> @@ -4316,6 +4251,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4333,7 +4272,7 @@ Unable to restore backup of wallet.</source> </message> <message> <source>Could not find asmap file %s</source> - <translation type="unfinished">找不到asmap文件%s</translation> + <translation type="unfinished">找不到asmap 檔案 %s</translation> </message> <message> <source>Could not parse asmap file %s</source> @@ -4424,14 +4363,34 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: %s 所在的磁盘空间低。</translation> </message> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">錯誤:轉存檔案的校驗和不匹配。%s計算得%s</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">错误:创建新仅观察钱包失败</translation> </message> <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的鍵不是十六進制:%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的值不是十六進制:%s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">錯誤:keypool已用完,請先重新呼叫keypoolrefill</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">錯誤:缺少校驗和</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">錯誤: 沒有可用的 %s 地址</translation> + </message> + <message> <source>Error: This wallet already uses SQLite</source> <translation type="unfinished">错误:此钱包已经在使用SQLite</translation> </message> @@ -4484,6 +4443,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: 钱包%s的数据库事务无法被执行</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to start indexes, shutting down..</source> <translation type="unfinished">无法启动索引,关闭中...</translation> </message> @@ -4492,6 +4455,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">校验数据库失败</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4516,6 +4487,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">dbcache不足以用于区块验证</translation> </message> <message> + <source>Insufficient funds</source> + <translation type="unfinished">金额不足</translation> + </message> + <message> <source>Invalid -i2psam address or hostname: '%s'</source> <translation type="unfinished">无效的 -i2psam 地址或主机名: '%s'</translation> </message> @@ -4688,10 +4663,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易位元量太大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation type="unfinished">沒辦法繫結在這台電腦上的 %s 。%s 可能已經在執行了。</translation> </message> diff --git a/src/qt/locale/bitcoin_zh-Hans.ts b/src/qt/locale/bitcoin_zh-Hans.ts index 4b2769a0c5..9f827ee890 100644 --- a/src/qt/locale/bitcoin_zh-Hans.ts +++ b/src/qt/locale/bitcoin_zh-Hans.ts @@ -184,6 +184,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">输入此钱包的旧密码和新密码。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</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> @@ -433,7 +441,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 B</source> <translation type="unfinished">%1 字节</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">默认钱包</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -511,7 +523,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">修改钱包加密密码</translation> + <translation type="unfinished">更改钱包密码</translation> </message> <message> <source>&Send</source> @@ -526,12 +538,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">选项(&O)</translation> </message> <message> - <source>&Encrypt Wallet…</source> - <translation type="unfinished">加密钱包(&E)</translation> - </message> - <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">把你钱包中的私钥加密</translation> + <translation type="unfinished">將錢包中之密鑰加密</translation> </message> <message> <source>&Backup Wallet…</source> @@ -542,22 +550,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">修改密码(&C)</translation> </message> <message> - <source>Sign &message…</source> - <translation type="unfinished">签名消息(&M)</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">验证消息(&V)</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">从文件加载PSBT(&L)...</translation> </message> @@ -574,32 +570,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">创建钱包...</translation> </message> <message> - <source>Close All Wallets…</source> - <translation type="unfinished">关闭所有钱包...</translation> - </message> - <message> <source>&File</source> - <translation type="unfinished">文件(&F)</translation> + <translation type="unfinished">&文件</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">设置(&S)</translation> + <translation type="unfinished">&設定</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">帮助(&H)</translation> + <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> + <translation type="unfinished">分頁工具列</translation> </message> <message> <source>Indexing blocks on disk…</source> @@ -611,7 +595,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> @@ -641,15 +625,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">赶上...</translation> + <translation type="unfinished">正在追上进度...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">最新收到的区块产生于 %1 之前。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">在此之后的交易尚不可见</translation> </message> <message> <source>Error</source> @@ -746,10 +730,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -801,7 +781,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>%n 条到比特币网络的活动连接</numerusform> + <numerusform>%n active connection(s) to Bitcoin network.</numerusform> </translation> </message> <message> @@ -1159,10 +1139,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1308,7 +1284,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> @@ -2363,10 +2339,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2473,6 +2445,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/类型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2665,6 +2641,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">无</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -3386,10 +3366,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">消息签名(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以用你的地址对消息/协议进行签名,以证明您可以接收发送到该地址的比特币。注意不要对任何模棱两可或者随机的消息进行签名,以免遭受钓鱼式攻击。请确保消息内容准确的表达了您的真实意愿。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3474,10 +3450,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -4046,11 +4018,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">已复制PSBT</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">无法签名交易</translation> </message> @@ -4062,10 +4029,6 @@ Go to File > Open Wallet to load a wallet. <source>Can't display address</source> <translation type="unfinished">无法显示地址</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">默认钱包</translation> - </message> </context> <context> <name>WalletView</name> @@ -4198,10 +4161,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">没有提供钱包格式。要使用 createfromdump ,必须提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4310,10 +4269,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool 最小为%d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">无法解析 - %s 地址: '%s'</translation> </message> @@ -4448,6 +4403,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4640,6 +4599,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">监听端口失败。如果你愿意的话,请使用 -listen=0 参数。</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">初始化时重扫描钱包失败</translation> </message> @@ -4652,6 +4615,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">校验数据库失败</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">删除交易时失败: %s</translation> </message> @@ -4904,10 +4875,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易过大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">无法在本机绑定%s端口 (bind函数返回了错误 %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_zh-Hant.ts b/src/qt/locale/bitcoin_zh-Hant.ts index 9fe760619b..ee666c5ff3 100644 --- a/src/qt/locale/bitcoin_zh-Hant.ts +++ b/src/qt/locale/bitcoin_zh-Hant.ts @@ -179,6 +179,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">输入钱包的旧密码和新密码。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</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> @@ -261,6 +269,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -432,7 +444,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 GB (十億位元組)</translation> </message> -</context> + </context> <context> <name>BitcoinGUI</name> <message> @@ -510,7 +522,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">修改钱包加密密码</translation> + <translation type="unfinished">更改钱包密码</translation> </message> <message> <source>&Send</source> @@ -521,16 +533,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">接收(&R)</translation> </message> <message> - <source>&Options…</source> - <translation type="unfinished">选项(&O)</translation> - </message> - <message> - <source>&Encrypt Wallet…</source> - <translation type="unfinished">加密钱包(&E)</translation> - </message> - <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">把你钱包中的私钥加密</translation> + <translation type="unfinished">將錢包中之密鑰加密</translation> </message> <message> <source>&Backup Wallet…</source> @@ -541,22 +545,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">修改密码(&C)</translation> </message> <message> - <source>Sign &message…</source> - <translation type="unfinished">签名消息(&M)</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">验证消息(&V)</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">从文件加载PSBT(&L)...</translation> </message> @@ -573,32 +565,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">创建钱包...</translation> </message> <message> - <source>Close All Wallets…</source> - <translation type="unfinished">关闭所有钱包...</translation> - </message> - <message> <source>&File</source> - <translation type="unfinished">文件(&F)</translation> + <translation type="unfinished">&文件</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished">设置(&S)</translation> + <translation type="unfinished">&設定</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">帮助(&H)</translation> + <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> + <translation type="unfinished">分頁工具列</translation> </message> <message> <source>Indexing blocks on disk…</source> @@ -610,7 +590,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> @@ -640,15 +620,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">赶上...</translation> + <translation type="unfinished">正在追上进度...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">最新收到的区块产生于 %1 之前。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">在此之后的交易尚不可见</translation> </message> <message> <source>Error</source> @@ -734,7 +714,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation type="unfinished">显示 %1 帮助信息,获取可用命令行选项列表</translation> + <translation type="unfinished">显示%1帮助消息以获得可能包含Bitcoin命令行选项的列表</translation> </message> <message> <source>&Mask values</source> @@ -745,10 +725,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -770,7 +746,7 @@ 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">钱包名称</translation> + <translation type="unfinished">錢包名稱</translation> </message> <message> <source>&Window</source> @@ -786,15 +762,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 client</source> - <translation type="unfinished">%1 客户端</translation> + <translation type="unfinished">%1 客戶端</translation> </message> <message> <source>&Hide</source> - <translation type="unfinished">隐藏(&H)</translation> + <translation type="unfinished">&躲</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">&顯示</translation> + <translation type="unfinished">显示(&H)</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -806,26 +782,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <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> + <translation type="unfinished">關閉網路紀錄</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">預先同步標頭(%1%)</translation> + <translation type="unfinished">预同步区块头 (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -927,11 +893,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Quantity:</source> - <translation type="unfinished">总量:</translation> + <translation type="unfinished">數量:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished">位元組數:</translation> + <translation type="unfinished">位元組:</translation> </message> <message> <source>Amount:</source> @@ -946,14 +912,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">計費後金額:</translation> </message> <message> - <source>Change:</source> - <translation type="unfinished">找零:</translation> - </message> - <message> - <source>(un)select all</source> - <translation type="unfinished">全(不)选</translation> - </message> - <message> <source>Tree mode</source> <translation type="unfinished">树状模式</translation> </message> @@ -966,22 +924,10 @@ Signing is only possible with addresses of the type 'legacy'.</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>Confirmed</source> - <translation type="unfinished">已确认</translation> - </message> - <message> <source>Copy amount</source> <translation type="unfinished">复制金额</translation> </message> @@ -1006,10 +952,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">锁定未花费(&O)</translation> </message> <message> - <source>&Unlock unspent</source> - <translation type="unfinished">解锁未花费(&U)</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">复制数目</translation> </message> @@ -1045,11 +987,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>change from %1 (%2)</source> <translation type="unfinished">找零來自於 %1 (%2)</translation> </message> - <message> - <source>(change)</source> - <translation type="unfinished">(找零)</translation> - </message> -</context> + </context> <context> <name>CreateWalletActivity</name> <message> @@ -1141,10 +1079,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1194,7 +1128,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">您确定想要关闭所有钱包吗?</translation> + <translation type="unfinished">您確定要關閉所有錢包嗎?</translation> </message> </context> <context> @@ -1245,7 +1179,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Create</source> - <translation type="unfinished">创建</translation> + <translation type="unfinished">創建</translation> </message> </context> <context> @@ -1284,7 +1218,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> - <translation type="unfinished">地址“%1”已经存在,它是一个收款地址,标签为“%2”,所以它不能作为一个付款地址被添加进来。</translation> + <translation type="unfinished">地址“%1”為已登記存在“%2”的地址,因此無法新增為發送地址。</translation> </message> <message> <source>The entered address "%1" is already in the address book with label "%2".</source> @@ -1307,7 +1241,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>name</source> - <translation type="unfinished">名称</translation> + <translation type="unfinished">姓名</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> @@ -1315,7 +1249,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Path already exists, and is not a directory.</source> - <translation type="unfinished">路径已存在,并且不是一个目录。</translation> + <translation type="unfinished">已經有指定的路徑了,並且不是一個目錄。</translation> </message> <message> <source>Cannot create data directory here.</source> @@ -1352,7 +1286,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">会在此目录中存储约 %1 GB 的数据。</translation> + <translation type="unfinished">此目錄中將儲存約%1 GB 的資料。</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1383,7 +1317,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Welcome to %1.</source> - <translation type="unfinished">欢迎使用 %1</translation> + <translation type="unfinished">歡迎來到 %1。</translation> </message> <message> <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> @@ -1391,7 +1325,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation type="unfinished">取消此设置需要重新下载整个区块链。先完整下载整条链再进行修剪会更快。这会禁用一些高级功能。</translation> + <translation type="unfinished">恢復此設定需要重新下載整個區塊鏈。 先下載完整鏈然後再修剪它的速度更快。 禁用一些高級功能。</translation> </message> <message> <source>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> @@ -1437,7 +1371,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">在此窗口消失前不要关闭计算机。</translation> + <translation type="unfinished">在該視窗消失之前,請勿關閉電腦。</translation> </message> </context> <context> @@ -1448,15 +1382,15 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation type="unfinished">近期交易可能尚未显示,因此当前余额可能不准确。以上信息将在与比特币网络完全同步后更正。详情如下</translation> + <translation type="unfinished">最近的交易可能還看不到,因此錢包餘額可能不正確。在錢包軟體完成跟 bitcoin 網路的同步後,這裡的資訊就會正確。詳情請見下面。</translation> </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation type="unfinished">尝试使用受未可见交易影响的余额将不被网络接受。</translation> + <translation type="unfinished">嘗試花費受尚未顯示的交易影響的比特幣將不會被網路接受。</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">剩余区块数量</translation> + <translation type="unfinished">剩餘區塊數量</translation> </message> <message> <source>Unknown…</source> @@ -1468,7 +1402,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>Progress</source> @@ -1480,7 +1414,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Estimated time left until synced</source> - <translation type="unfinished">预计剩余同步时间</translation> + <translation type="unfinished">預計完成同步所需時間</translation> </message> <message> <source>Hide</source> @@ -1508,7 +1442,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <source>Paste address from clipboard</source> <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> </context> <context> @@ -1519,11 +1453,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>&Main</source> - <translation type="unfinished">主要(&M)</translation> + <translation type="unfinished">&主要(&Main)</translation> </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">在登入系统后自动启动 %1</translation> + <translation type="unfinished">登錄系統%1後自動啟動。</translation> </message> <message> <source>&Start %1 on system login</source> @@ -1535,11 +1469,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Size of &database cache</source> - <translation type="unfinished">数据库缓存大小(&D)</translation> + <translation type="unfinished">資料庫快取的大小 </translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">脚本验证线程数(&V)</translation> + <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> @@ -2290,10 +2224,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2400,6 +2330,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/类型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2462,7 +2396,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>&Open</source> @@ -2568,7 +2502,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 天(&A)</translation> + <translation type="unfinished">一天</translation> </message> <message> <source>1 &week</source> @@ -2592,6 +2526,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">无</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -2627,7 +2565,7 @@ For more information on using this console, type %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(节点: %1)</translation> + <translation type="unfinished">(同儕:%1)</translation> </message> <message> <source>via %1</source> @@ -2817,11 +2755,11 @@ For more information on using this console, type %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">验证(&V)</translation> + <translation type="unfinished">&驗證</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">在像是硬件钱包屏幕的地方检验这个地址</translation> + <translation type="unfinished">在例如硬體錢包螢幕上驗證這個地址</translation> </message> <message> <source>&Save Image…</source> @@ -2959,7 +2897,7 @@ For more information on using this console, type %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">输入...</translation> + <translation type="unfinished">輸入…</translation> </message> <message> <source>Choose…</source> @@ -2973,9 +2911,9 @@ For more information on using this console, type %6. <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">指定交易虚拟大小的每kB (1,000字节) 自定义费率。 + <translation type="unfinished">指定每千字節(1,000字節)交易虛擬大小的自訂手續費。 -附注:因为矿工费是按字节计费的,所以如果费率是“每kvB支付100聪”,那么对于一笔500虚拟字节 (1kvB的一半) 的交易,最终将只会产生50聪的矿工费。(译注:这里就是提醒单位是字节,而不是千字节,如果搞错的话,矿工费会过低,导致交易长时间无法确认,或者压根无法发出)</translation> +注意:由於手續費是按每字節計算的,對於虛擬大小為500字節(半千字節)的交易,手續費率為「每千字節100聰」,最終將只收取50聰的手續費。</translation> </message> <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> @@ -3090,6 +3028,10 @@ 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 balance:</source> + <translation type="unfinished">外部餘額:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">或</translation> </message> @@ -3098,6 +3040,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">你可以之後再提高手續費(有 BIP-125 手續費追加的標記)</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">請檢查您的交易提案。這將產生部分簽名的比特幣交易(PSBT),您可以儲存或複製該交易,然後使用簽名。離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 from wallet '%2'</source> <translation type="unfinished">%1 来自钱包 “%2”</translation> </message> @@ -3229,7 +3176,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Remove this entry</source> @@ -3286,10 +3233,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">簽署訊息(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以使用您的地址簽名訊息/協議,以證明您可以接收發送給他們的比特幣。但是請小心,不要簽名語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽名的手法來冒充是你。只有簽名您同意的詳細內容。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3299,7 +3242,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Enter the message you want to sign here</source> @@ -3374,10 +3317,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -3430,6 +3369,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <source>kB/s</source> + <translation type="unfinished">千字節/秒</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -3808,7 +3754,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Confirmed</source> - <translation type="unfinished">已确认</translation> + <translation type="unfinished">已確認</translation> </message> <message> <source>Watch-only</source> @@ -3946,11 +3892,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT已複製</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">沒辦法簽署交易。</translation> </message> @@ -3960,11 +3901,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Can't display address</source> - <translation type="unfinished">無法顯示地址</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">默认钱包</translation> + <translation type="unfinished">無法顯示錢包位址</translation> </message> </context> <context> @@ -4014,6 +3951,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s 開發人員</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation type="unfinished">%s損壞。嘗試使用錢包工具bitcoin-wallet挽救或還原備份。</translation> + </message> + <message> <source>%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 验证 -assumeutxo 快照状态失败。这表明硬件可能有问题,也可能是软件bug,或者还可能是软件被不当修改、从而让非法快照也能够被加载。因此,将关闭节点并停止使用从这个快照构建出的任何状态,并将链高度从 %d 重置到 %d 。下次启动时,节点将会不使用快照数据从 %d 继续同步。请将这个事件报告给 %s 并在报告中包括您是如何获得这份快照的。无效的链状态快照仍被保存至磁盘上,以供诊断问题的原因。</translation> </message> @@ -4027,7 +3968,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">无法锁定数据目录 %s。%s 可能已经在运行。</translation> + <translation type="unfinished">無法在資料目錄上獲取鎖定%s。%s可能已經在運行了。</translation> </message> <message> <source>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> @@ -4055,7 +3996,9 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">错误: 转储文件标识符记录不正确。得到的是 "%s",而预期本应得到的是 "%s"。</translation> + <translation type="unfinished"> +錯誤:轉存檔案識別記錄不正確。獲得%s,預期 +%s。</translation> </message> <message> <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> @@ -4094,10 +4037,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">没有提供钱包格式。要使用 createfromdump ,必须提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4206,10 +4145,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">參數 -maxmempool 至少要給 %d 百萬位元組(MB)</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">沒辦法解析 -%s 參數指定的地址: '%s'</translation> </message> @@ -4344,6 +4279,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4361,7 +4300,7 @@ Unable to restore backup of wallet.</source> </message> <message> <source>Could not find asmap file %s</source> - <translation type="unfinished">找不到asmap文件%s</translation> + <translation type="unfinished">找不到asmap 檔案 %s</translation> </message> <message> <source>Could not parse asmap file %s</source> @@ -4452,14 +4391,34 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: %s 所在的磁盘空间低。</translation> </message> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">錯誤:轉存檔案的校驗和不匹配。%s計算得%s</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">错误:创建新仅观察钱包失败</translation> </message> <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的鍵不是十六進制:%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的值不是十六進制:%s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">錯誤:keypool已用完,請先重新呼叫keypoolrefill</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">錯誤:缺少校驗和</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">錯誤: 沒有可用的 %s 地址</translation> + </message> + <message> <source>Error: This wallet already uses SQLite</source> <translation type="unfinished">错误:此钱包已经在使用SQLite</translation> </message> @@ -4512,6 +4471,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: 钱包%s的数据库事务无法被执行</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to start indexes, shutting down..</source> <translation type="unfinished">无法启动索引,关闭中...</translation> </message> @@ -4520,6 +4483,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">校验数据库失败</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4544,6 +4515,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">dbcache不足以用于区块验证</translation> </message> <message> + <source>Insufficient funds</source> + <translation type="unfinished">金额不足</translation> + </message> + <message> <source>Invalid -i2psam address or hostname: '%s'</source> <translation type="unfinished">无效的 -i2psam 地址或主机名: '%s'</translation> </message> @@ -4716,10 +4691,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易位元量太大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation type="unfinished">沒辦法繫結在這台電腦上的 %s 。%s 可能已經在執行了。</translation> </message> diff --git a/src/qt/locale/bitcoin_zh.ts b/src/qt/locale/bitcoin_zh.ts index 0b2297d0b7..3d279e6da0 100644 --- a/src/qt/locale/bitcoin_zh.ts +++ b/src/qt/locale/bitcoin_zh.ts @@ -50,10 +50,6 @@ <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">选择(&H)</translation> </message> @@ -98,10 +94,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -184,6 +176,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">输入钱包的旧密码和新密码。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</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> @@ -434,14 +434,10 @@ 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> -</context> + </context> <context> <name>BitcoinGUI</name> <message> @@ -453,6 +449,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">最小化</translation> </message> <message> + <source>Wallet:</source> + <translation type="unfinished">钱包:</translation> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation type="unfinished">更改钱包密码</translation> + </message> + <message> <source>&File</source> <translation type="unfinished">&文件</translation> </message> @@ -469,24 +473,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">标签工具栏</translation> </message> <message> - <source>Connecting to peers…</source> - <translation type="unfinished">正在跟其他節點連線中...</translation> - </message> - <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">请求支付 (生成二维码和 bitcoin: URI)</translation> + <translation type="unfinished">请求支付(生成二维码和比特币链接)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">显示用过的付款地址和标签的列表</translation> + <translation type="unfinished">显示使用过的发送地址或标签的列表</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">显示用过的收款地址和标签的列表</translation> + <translation type="unfinished">显示使用接收的地址或标签的列表</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">命令行选项(&C)</translation> + <translation type="unfinished">&命令行选项</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -496,19 +496,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 behind</source> - <translation type="unfinished">落后 %1</translation> - </message> - <message> - <source>Catching up…</source> - <translation type="unfinished">追上中...</translation> + <translation type="unfinished">%1 落后</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">上次接收到的块是在%1之前生成的。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">之后的交易还不可见。</translation> </message> <message> <source>Error</source> @@ -520,11 +516,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Information</source> - <translation type="unfinished">信息</translation> + <translation type="unfinished">消息</translation> </message> <message> <source>Up to date</source> - <translation type="unfinished">已是最新</translation> + <translation type="unfinished">最新的</translation> </message> <message> <source>Load PSBT from &clipboard…</source> @@ -573,10 +569,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> @@ -589,10 +581,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">显示%1帮助消息以获得可能包含Bitcoin命令行选项的列表</translation> </message> <message> + <source>&Mask values</source> + <translation type="unfinished">遮住数值(&M)</translation> + </message> + <message> + <source>Mask the values in the Overview tab</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> @@ -603,6 +608,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">恢復錢包</translation> </message> <message> + <source>Wallet Name</source> + <extracomment>Label of the input field where the name of the wallet is entered.</extracomment> + <translation type="unfinished">錢包名稱</translation> + </message> + <message> <source>&Window</source> <translation type="unfinished">&窗口</translation> </message> @@ -620,11 +630,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Hide</source> - <translation type="unfinished">隐藏(&H)</translation> + <translation type="unfinished">&躲</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">&顯示</translation> + <translation type="unfinished">显示(&H)</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -634,8 +644,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> </translation> </message> <message> + <source>Click for more actions.</source> + <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> + <translation type="unfinished">點擊查看更多操作</translation> + </message> + <message> + <source>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> + <translation type="unfinished">预同步区块头 (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -737,11 +757,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Quantity:</source> - <translation type="unfinished">总量:</translation> + <translation type="unfinished">數量:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished">位元組數:</translation> + <translation type="unfinished">位元組:</translation> </message> <message> <source>Amount:</source> @@ -753,15 +773,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>After Fee:</source> - <translation type="unfinished">加上交易费用后:</translation> - </message> - <message> - <source>Change:</source> - <translation type="unfinished">找零:</translation> - </message> - <message> - <source>(un)select all</source> - <translation type="unfinished">全(不)选</translation> + <translation type="unfinished">計費後金額:</translation> </message> <message> <source>Tree mode</source> @@ -776,40 +788,24 @@ Signing is only possible with addresses of the type 'legacy'.</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> + <translation type="unfinished">复制地址(&C)</translation> </message> <message> <source>Copy &label</source> - <translation type="unfinished">複製 &label</translation> + <translation type="unfinished">复制标签(&L)</translation> </message> <message> <source>Copy &amount</source> - <translation type="unfinished">複製 &amount</translation> + <translation type="unfinished">复制和数量</translation> </message> <message> <source>Copy transaction &ID and output index</source> @@ -820,10 +816,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">锁定未花费(&O)</translation> </message> <message> - <source>&Unlock unspent</source> - <translation type="unfinished">解锁未花费(&U)</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">复制数目</translation> </message> @@ -833,54 +825,33 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Copy after fee</source> - <translation type="unfinished">复制含交易费的金额</translation> + <translation type="unfinished">複製計費後金額</translation> </message> <message> <source>Copy bytes</source> <translation type="unfinished">复制字节数</translation> </message> <message> - <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation type="unfinished">每个输入可能有 +/- %1 聪 (satoshi) 的误差。</translation> - </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(无标签)</translation> + <source>Copy change</source> + <translation type="unfinished">複製找零金額</translation> </message> <message> - <source>change from %1 (%2)</source> - <translation type="unfinished">来自 %1 的找零 (%2)</translation> + <source>(%1 locked)</source> + <translation type="unfinished">(%1已锁定)</translation> </message> <message> - <source>(change)</source> - <translation type="unfinished">(找零)</translation> + <source>(no label)</source> + <translation type="unfinished">(无标签)</translation> </message> -</context> + </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> @@ -947,10 +918,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -997,7 +964,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Are you sure you wish to close the wallet <i>%1</i>?</source> - <translation type="unfinished">您确定想要关闭钱包<i>%1</i>吗?</translation> + <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> @@ -1009,7 +976,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">您确定想要关闭所有钱包吗?</translation> + <translation type="unfinished">您確定要關閉所有錢包嗎?</translation> </message> </context> <context> @@ -1072,7 +1039,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Create</source> - <translation type="unfinished">创建</translation> + <translation type="unfinished">創建</translation> </message> <message> <source>Compiled without external signing support (required for external signing)</source> @@ -1096,7 +1063,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> @@ -1120,7 +1087,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> - <translation type="unfinished">地址“%1”已经存在,它是一个收款地址,标签为“%2”,所以它不能作为一个付款地址被添加进来。</translation> + <translation type="unfinished">地址“%1”為已登記存在“%2”的地址,因此無法新增為發送地址。</translation> </message> <message> <source>The entered address "%1" is already in the address book with label "%2".</source> @@ -1143,7 +1110,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>name</source> - <translation type="unfinished">名称</translation> + <translation type="unfinished">姓名</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> @@ -1151,7 +1118,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Path already exists, and is not a directory.</source> - <translation type="unfinished">路径已存在,并且不是一个目录。</translation> + <translation type="unfinished">已經有指定的路徑了,並且不是一個目錄。</translation> </message> <message> <source>Cannot create data directory here.</source> @@ -1192,7 +1159,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">会在此目录中存储约 %1 GB 的数据。</translation> + <translation type="unfinished">此目錄中將儲存約%1 GB 的資料。</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1223,7 +1190,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Welcome to %1.</source> - <translation type="unfinished">欢迎使用 %1</translation> + <translation type="unfinished">歡迎來到 %1。</translation> </message> <message> <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> @@ -1235,7 +1202,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation type="unfinished">取消此设置需要重新下载整个区块链。先完整下载整条链再进行修剪会更快。这会禁用一些高级功能。</translation> + <translation type="unfinished">恢復此設定需要重新下載整個區塊鏈。 先下載完整鏈然後再修剪它的速度更快。 禁用一些高級功能。</translation> </message> <message> <source>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> @@ -1281,7 +1248,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">在此窗口消失前不要关闭计算机。</translation> + <translation type="unfinished">在該視窗消失之前,請勿關閉電腦。</translation> </message> </context> <context> @@ -1292,15 +1259,15 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation type="unfinished">近期交易可能尚未显示,因此当前余额可能不准确。以上信息将在与比特币网络完全同步后更正。详情如下</translation> + <translation type="unfinished">最近的交易可能還看不到,因此錢包餘額可能不正確。在錢包軟體完成跟 bitcoin 網路的同步後,這裡的資訊就會正確。詳情請見下面。</translation> </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation type="unfinished">尝试使用受未可见交易影响的余额将不被网络接受。</translation> + <translation type="unfinished">嘗試花費受尚未顯示的交易影響的比特幣將不會被網路接受。</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">剩余区块数量</translation> + <translation type="unfinished">剩餘區塊數量</translation> </message> <message> <source>Unknown…</source> @@ -1312,7 +1279,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>Progress</source> @@ -1324,7 +1291,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Estimated time left until synced</source> - <translation type="unfinished">预计剩余同步时间</translation> + <translation type="unfinished">預計完成同步所需時間</translation> </message> <message> <source>Hide</source> @@ -1332,7 +1299,7 @@ The migration process will create a backup of the wallet before migrating. This </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> + <translation type="unfinished">%1 當前正在同步。它將從peers下載區塊頭和區塊,並對其進行驗證,直到到達區塊鏈的頂為止。</translation> </message> <message> <source>Unknown. Syncing Headers (%1, %2%)…</source> @@ -1352,7 +1319,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <source>Paste address from clipboard</source> <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> </context> <context> @@ -1363,11 +1330,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>&Main</source> - <translation type="unfinished">主要(&M)</translation> + <translation type="unfinished">&主要(&Main)</translation> </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">在登入系统后自动启动 %1</translation> + <translation type="unfinished">登錄系統%1後自動啟動。</translation> </message> <message> <source>&Start %1 on system login</source> @@ -1379,11 +1346,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Size of &database cache</source> - <translation type="unfinished">数据库缓存大小(&D)</translation> + <translation type="unfinished">資料庫快取的大小 </translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">脚本验证线程数(&V)</translation> + <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> @@ -2151,10 +2118,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2261,6 +2224,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/類型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2323,7 +2290,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>&Open</source> @@ -2429,7 +2396,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 天(&A)</translation> + <translation type="unfinished">一天</translation> </message> <message> <source>1 &week</source> @@ -2453,6 +2420,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">无</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -2488,7 +2459,7 @@ For more information on using this console, type %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(节点: %1)</translation> + <translation type="unfinished">(同儕:%1)</translation> </message> <message> <source>via %1</source> @@ -2639,7 +2610,7 @@ For more information on using this console, type %6. </message> <message> <source>Could not generate new %1 address</source> - <translation type="unfinished">无法生成新的%1地址</translation> + <translation type="unfinished">無法產生新的 %1 地址</translation> </message> </context> <context> @@ -2678,11 +2649,11 @@ For more information on using this console, type %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">验证(&V)</translation> + <translation type="unfinished">&驗證</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">在像是硬件钱包屏幕的地方检验这个地址</translation> + <translation type="unfinished">在例如硬體錢包螢幕上驗證這個地址</translation> </message> <message> <source>&Save Image…</source> @@ -2712,10 +2683,6 @@ For more information on using this console, type %6. <translation type="unfinished">消息</translation> </message> <message> - <source>(no label)</source> - <translation type="unfinished">(无标签)</translation> - </message> - <message> <source>(no message)</source> <translation type="unfinished">(无消息)</translation> </message> @@ -2820,7 +2787,7 @@ For more information on using this console, type %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">输入...</translation> + <translation type="unfinished">輸入…</translation> </message> <message> <source>Choose…</source> @@ -2834,9 +2801,9 @@ For more information on using this console, type %6. <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">指定交易虚拟大小的每kB (1,000字节) 自定义费率。 + <translation type="unfinished">指定每千字節(1,000字節)交易虛擬大小的自訂手續費。 -附注:因为矿工费是按字节计费的,所以如果费率是“每kvB支付100聪”,那么对于一笔500虚拟字节 (1kvB的一半) 的交易,最终将只会产生50聪的矿工费。(译注:这里就是提醒单位是字节,而不是千字节,如果搞错的话,矿工费会过低,导致交易长时间无法确认,或者压根无法发出)</translation> +注意:由於手續費是按每字節計算的,對於虛擬大小為500字節(半千字節)的交易,手續費率為「每千字節100聰」,最終將只收取50聰的手續費。</translation> </message> <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> @@ -2892,13 +2859,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Copy after fee</source> - <translation type="unfinished">复制含交易费的金额</translation> + <translation type="unfinished">複製計費後金額</translation> </message> <message> <source>Copy bytes</source> <translation type="unfinished">复制字节数</translation> </message> <message> + <source>Copy change</source> + <translation type="unfinished">複製找零金額</translation> + </message> + <message> <source>%1 (%2 blocks)</source> <translation type="unfinished">%1 (%2个块)</translation> </message> @@ -2922,7 +2893,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation type="unfinished">创建一个“部分签名比特币交易”(PSBT),以用于诸如离线%1钱包,或是兼容PSBT的硬件钱包这类用途。</translation> + <translation type="unfinished">產生一個部分簽名的比特幣交易(PSBT)以用於例如離線%1錢包或與PSBT相容的硬體錢包。</translation> </message> <message> <source>Save Transaction Data</source> @@ -2934,10 +2905,19 @@ 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 balance:</source> + <translation type="unfinished">外部餘額:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">或</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">請檢查您的交易提案。這將產生部分簽名的比特幣交易(PSBT),您可以儲存或複製該交易,然後使用簽名。離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 from wallet '%2'</source> <translation type="unfinished">%1 来自钱包 “%2”</translation> </message> @@ -3040,11 +3020,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> <translation type="unfinished">你选择的找零地址未被包含在本钱包中,你钱包中的部分或全部金额将被发送至该地址。你确定要这样做吗?</translation> </message> - <message> - <source>(no label)</source> - <translation type="unfinished">(无标签)</translation> - </message> -</context> + </context> <context> <name>SendCoinsEntry</name> <message> @@ -3064,12 +3040,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">选择以前用过的地址</translation> </message> <message> - <source>The Bitcoin address to send the payment to</source> - <translation type="unfinished">付款目的地址</translation> - </message> - <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Remove this entry</source> @@ -3126,10 +3098,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">消息签名(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以用你的地址对消息/协议进行签名,以证明您可以接收发送到该地址的比特币。注意不要对任何模棱两可或者随机的消息进行签名,以免遭受钓鱼式攻击。请确保消息内容准确的表达了您的真实意愿。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3139,7 +3107,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Enter the message you want to sign here</source> @@ -3214,10 +3182,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -3270,6 +3234,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <source>kB/s</source> + <translation type="unfinished">千字節/秒</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -3514,10 +3485,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">(不可用)</translation> </message> <message> - <source>(no label)</source> - <translation type="unfinished">(无标签)</translation> - </message> - <message> <source>Transaction status. Hover over this field to show number of confirmations.</source> <translation type="unfinished">交易状态。 鼠标移到此区域可显示确认数。</translation> </message> @@ -3652,7 +3619,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Confirmed</source> - <translation type="unfinished">已确认</translation> + <translation type="unfinished">已確認</translation> </message> <message> <source>Watch-only</source> @@ -3786,11 +3753,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT已複製</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">无法签名交易</translation> </message> @@ -3800,11 +3762,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Can't display address</source> - <translation type="unfinished">無法顯示地址</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">默认钱包</translation> + <translation type="unfinished">無法顯示錢包位址</translation> </message> </context> <context> @@ -3822,6 +3780,11 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">备份钱包</translation> </message> <message> + <source>Wallet Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">錢包資料</translation> + </message> + <message> <source>Backup Failed</source> <translation type="unfinished">备份失败</translation> </message> @@ -3850,7 +3813,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> - <translation type="unfinished">%s损坏。请尝试用bitcoin-wallet钱包工具来对其进行急救。或者用一个备份进行还原。</translation> + <translation type="unfinished">%s損壞。嘗試使用錢包工具bitcoin-wallet挽救或還原備份。</translation> </message> <message> <source>%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> @@ -3866,7 +3829,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">无法锁定数据目录 %s。%s 可能已经在运行。</translation> + <translation type="unfinished">無法在資料目錄上獲取鎖定%s。%s可能已經在運行了。</translation> </message> <message> <source>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> @@ -3894,7 +3857,9 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">错误: 转储文件标识符记录不正确。得到的是 "%s",而预期本应得到的是 "%s"。</translation> + <translation type="unfinished"> +錯誤:轉存檔案識別記錄不正確。獲得%s,預期 +%s。</translation> </message> <message> <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> @@ -3933,10 +3898,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">沒有提供錢包格式。 要使用 createfromdump ,必須提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4045,10 +4006,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool 最小为%d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">无法解析 - %s 地址: '%s'</translation> </message> @@ -4183,6 +4140,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4200,7 +4161,7 @@ Unable to restore backup of wallet.</source> </message> <message> <source>Could not find asmap file %s</source> - <translation type="unfinished">找不到asmap文件%s</translation> + <translation type="unfinished">找不到asmap 檔案 %s</translation> </message> <message> <source>Could not parse asmap file %s</source> @@ -4283,10 +4244,30 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: 无法从生成的scriptpubkey提取目标</translation> </message> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">錯誤:轉存檔案的校驗和不匹配。%s計算得%s</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">错误:创建新仅观察钱包失败</translation> </message> <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的鍵不是十六進制:%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的值不是十六進制:%s</translation> + </message> + <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">錯誤:缺少校驗和</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">錯誤: 沒有可用的 %s 地址</translation> + </message> + <message> <source>Error: This wallet already uses SQLite</source> <translation type="unfinished">错误:此钱包已经在使用SQLite</translation> </message> @@ -4335,10 +4316,22 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: 钱包%s的数据库事务无法被执行</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to start indexes, shutting down..</source> <translation type="unfinished">无法启动索引,关闭中...</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4351,6 +4344,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">dbcache不足以用于区块验证</translation> </message> <message> + <source>Insufficient funds</source> + <translation type="unfinished">金额不足</translation> + </message> + <message> <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> <translation type="unfinished">%s=<amount>: '%s' 中指定了非法的金额 (必须至少达到 %s)</translation> </message> @@ -4407,10 +4404,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易需要一个找零地址,但是我们无法生成它。</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to find UTXO for external input</source> <translation type="unfinished">无法为外部输入找到UTXO</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 21f57a8f6d..7bab106bd5 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -184,6 +184,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">输入此钱包的旧密码和新密码。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</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> @@ -433,7 +441,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 B</source> <translation type="unfinished">%1 字节</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation type="unfinished">默认钱包</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -611,7 +623,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> @@ -641,15 +653,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">赶上...</translation> + <translation type="unfinished">正在追上进度...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">最新收到的区块产生于 %1 之前。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">在此之后的交易尚不可见</translation> </message> <message> <source>Error</source> @@ -746,10 +758,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -1039,62 +1047,20 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">(%1已锁定)</translation> </message> <message> - <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation type="unfinished">每个输入可能有 +/- %1 聪 (satoshi) 的误差。</translation> - </message> - <message> <source>(no label)</source> <translation type="unfinished">(无标签)</translation> </message> - <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> <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> + <translation type="unfinished">正在创建钱包<b>%1</b>...</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> + <translation type="unfinished">偵測到的外接簽名器過多</translation> </message> </context> <context> @@ -1159,10 +1125,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -2363,10 +2325,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2473,6 +2431,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/类型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2665,6 +2627,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">无</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -3386,10 +3352,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">消息签名(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以用你的地址对消息/协议进行签名,以证明您可以接收发送到该地址的比特币。注意不要对任何模棱两可或者随机的消息进行签名,以免遭受钓鱼式攻击。请确保消息内容准确的表达了您的真实意愿。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3474,10 +3436,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -4046,11 +4004,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">已复制PSBT</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">无法签名交易</translation> </message> @@ -4062,10 +4015,6 @@ Go to File > Open Wallet to load a wallet. <source>Can't display address</source> <translation type="unfinished">无法显示地址</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">默认钱包</translation> - </message> </context> <context> <name>WalletView</name> @@ -4198,10 +4147,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">没有提供钱包格式。要使用 createfromdump ,必须提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4310,10 +4255,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">-maxmempool 最小为%d MB</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">无法解析 - %s 地址: '%s'</translation> </message> @@ -4448,6 +4389,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4640,6 +4585,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">监听端口失败。如果你愿意的话,请使用 -listen=0 参数。</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">初始化时重扫描钱包失败</translation> </message> @@ -4652,6 +4601,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">校验数据库失败</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4904,10 +4861,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易过大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">无法在本机绑定%s端口 (bind函数返回了错误 %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_HK.ts b/src/qt/locale/bitcoin_zh_HK.ts index 55551bfe71..174ae53fba 100644 --- a/src/qt/locale/bitcoin_zh_HK.ts +++ b/src/qt/locale/bitcoin_zh_HK.ts @@ -183,6 +183,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">請輸入舊密碼和新密碼至錢包。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">继续</translation> + </message> + <message> + <source>Back</source> + <translation type="unfinished">返回</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished">請記得將錢包加密不能完全防止你的 Bitcoins 經被入侵電腦的惡意程式偷取。</translation> </message> @@ -265,6 +273,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -432,6 +444,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 GB (十億位元組)</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">預設錢包</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -521,16 +537,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">收款 &R</translation> </message> <message> - <source>&Options…</source> - <translation type="unfinished">选项(&O)</translation> - </message> - <message> - <source>&Encrypt Wallet…</source> - <translation type="unfinished">加密钱包(&E)</translation> - </message> - <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished">把你钱包中的私钥加密</translation> + <translation type="unfinished">將錢包中之密鑰加密</translation> </message> <message> <source>&Backup Wallet…</source> @@ -541,22 +549,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">修改密码(&C)</translation> </message> <message> - <source>Sign &message…</source> - <translation type="unfinished">签名消息(&M)</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">验证消息(&V)</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">从文件加载PSBT(&L)...</translation> </message> @@ -573,10 +569,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">创建钱包...</translation> </message> <message> - <source>Close All Wallets…</source> - <translation type="unfinished">关闭所有钱包...</translation> - </message> - <message> <source>&File</source> <translation type="unfinished">檔案 &F</translation> </message> @@ -590,15 +582,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </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> + <translation type="unfinished">分頁工具列</translation> </message> <message> <source>Indexing blocks on disk…</source> @@ -610,7 +594,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> @@ -640,15 +624,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">赶上...</translation> + <translation type="unfinished">正在追上进度...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">最新接收到的区块是在%1之前生成的。</translation> + <translation type="unfinished">最新收到的区块产生于 %1 之前。</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">在此之后的交易尚不可见。</translation> + <translation type="unfinished">在此之后的交易尚不可见</translation> </message> <message> <source>Error</source> @@ -734,7 +718,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation type="unfinished">显示 %1 帮助信息,获取可用命令行选项列表</translation> + <translation type="unfinished">显示%1帮助消息以获得可能包含Bitcoin命令行选项的列表</translation> </message> <message> <source>&Mask values</source> @@ -745,10 +729,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -770,7 +750,7 @@ 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">钱包名称</translation> + <translation type="unfinished">錢包名稱</translation> </message> <message> <source>&Window</source> @@ -786,15 +766,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>%1 client</source> - <translation type="unfinished">%1 客户端</translation> + <translation type="unfinished">%1 客戶端</translation> </message> <message> <source>&Hide</source> - <translation type="unfinished">隐藏(&H)</translation> + <translation type="unfinished">&躲</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">&顯示</translation> + <translation type="unfinished">显示(&H)</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> @@ -806,26 +786,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <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> + <translation type="unfinished">關閉網路紀錄</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> - <translation type="unfinished">預先同步標頭(%1%)</translation> + <translation type="unfinished">预同步区块头 (%1%)…</translation> </message> <message> <source>Error creating wallet</source> @@ -905,7 +875,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">錢包<b>已加密</b>並且<b>上鎖中</b></translation> + <translation type="unfinished">錢包<b>已加密</b>並且已<b>上鎖</b></translation> </message> <message> <source>Original message:</source> @@ -927,11 +897,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Quantity:</source> - <translation type="unfinished">总量:</translation> + <translation type="unfinished">數量:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished">位元組數:</translation> + <translation type="unfinished">位元組:</translation> </message> <message> <source>Amount:</source> @@ -939,21 +909,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Fee:</source> - <translation type="unfinished">费用:</translation> + <translation type="unfinished">費用:</translation> </message> <message> <source>After Fee:</source> <translation type="unfinished">計費後金額:</translation> </message> <message> - <source>Change:</source> - <translation type="unfinished">找零:</translation> - </message> - <message> - <source>(un)select all</source> - <translation type="unfinished">全(不)选</translation> - </message> - <message> <source>Tree mode</source> <translation type="unfinished">树状模式</translation> </message> @@ -966,18 +928,10 @@ Signing is only possible with addresses of the type 'legacy'.</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>Confirmed</source> <translation type="unfinished">已確認</translation> </message> @@ -1006,10 +960,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">锁定未花费(&O)</translation> </message> <message> - <source>&Unlock unspent</source> - <translation type="unfinished">解锁未花费(&U)</translation> - </message> - <message> <source>Copy quantity</source> <translation type="unfinished">复制数目</translation> </message> @@ -1045,11 +995,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>change from %1 (%2)</source> <translation type="unfinished">找零來自於 %1 (%2)</translation> </message> - <message> - <source>(change)</source> - <translation type="unfinished">(找零)</translation> - </message> -</context> + </context> <context> <name>CreateWalletActivity</name> <message> @@ -1141,10 +1087,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -1194,7 +1136,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">您确定想要关闭所有钱包吗?</translation> + <translation type="unfinished">您確定要關閉所有錢包嗎?</translation> </message> </context> <context> @@ -1245,7 +1187,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Create</source> - <translation type="unfinished">创建</translation> + <translation type="unfinished">創建</translation> </message> </context> <context> @@ -1284,7 +1226,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> - <translation type="unfinished">地址“%1”已经存在,它是一个收款地址,标签为“%2”,所以它不能作为一个付款地址被添加进来。</translation> + <translation type="unfinished">地址“%1”為已登記存在“%2”的地址,因此無法新增為發送地址。</translation> </message> <message> <source>The entered address "%1" is already in the address book with label "%2".</source> @@ -1307,7 +1249,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>name</source> - <translation type="unfinished">名称</translation> + <translation type="unfinished">姓名</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> @@ -1315,7 +1257,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Path already exists, and is not a directory.</source> - <translation type="unfinished">路径已存在,并且不是一个目录。</translation> + <translation type="unfinished">已經有指定的路徑了,並且不是一個目錄。</translation> </message> <message> <source>Cannot create data directory here.</source> @@ -1352,7 +1294,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">会在此目录中存储约 %1 GB 的数据。</translation> + <translation type="unfinished">此目錄中將儲存約%1 GB 的資料。</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1383,7 +1325,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Welcome to %1.</source> - <translation type="unfinished">欢迎使用 %1</translation> + <translation type="unfinished">歡迎來到 %1。</translation> </message> <message> <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> @@ -1391,7 +1333,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation type="unfinished">取消此设置需要重新下载整个区块链。先完整下载整条链再进行修剪会更快。这会禁用一些高级功能。</translation> + <translation type="unfinished">恢復此設定需要重新下載整個區塊鏈。 先下載完整鏈然後再修剪它的速度更快。 禁用一些高級功能。</translation> </message> <message> <source>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> @@ -1437,7 +1379,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished">在此窗口消失前不要关闭计算机。</translation> + <translation type="unfinished">在該視窗消失之前,請勿關閉電腦。</translation> </message> </context> <context> @@ -1448,15 +1390,15 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation type="unfinished">近期交易可能尚未显示,因此当前余额可能不准确。以上信息将在与比特币网络完全同步后更正。详情如下</translation> + <translation type="unfinished">最近的交易可能還看不到,因此錢包餘額可能不正確。在錢包軟體完成跟 bitcoin 網路的同步後,這裡的資訊就會正確。詳情請見下面。</translation> </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation type="unfinished">尝试使用受未可见交易影响的余额将不被网络接受。</translation> + <translation type="unfinished">嘗試花費受尚未顯示的交易影響的比特幣將不會被網路接受。</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">剩余区块数量</translation> + <translation type="unfinished">剩餘區塊數量</translation> </message> <message> <source>Unknown…</source> @@ -1468,7 +1410,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>Progress</source> @@ -1480,7 +1422,7 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Estimated time left until synced</source> - <translation type="unfinished">预计剩余同步时间</translation> + <translation type="unfinished">預計完成同步所需時間</translation> </message> <message> <source>Hide</source> @@ -1508,7 +1450,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <source>Paste address from clipboard</source> <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> </context> <context> @@ -1519,11 +1461,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>&Main</source> - <translation type="unfinished">主要(&M)</translation> + <translation type="unfinished">&主要(&Main)</translation> </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation type="unfinished">在登入系统后自动启动 %1</translation> + <translation type="unfinished">登錄系統%1後自動啟動。</translation> </message> <message> <source>&Start %1 on system login</source> @@ -1535,11 +1477,11 @@ The migration process will create a backup of the wallet before migrating. This </message> <message> <source>Size of &database cache</source> - <translation type="unfinished">数据库缓存大小(&D)</translation> + <translation type="unfinished">資料庫快取的大小 </translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">脚本验证线程数(&V)</translation> + <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> @@ -2219,11 +2161,11 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>Network</source> - <translation type="unfinished">网络</translation> + <translation type="unfinished">網路</translation> </message> <message> <source>Name</source> - <translation type="unfinished">名称</translation> + <translation type="unfinished">名稱</translation> </message> <message> <source>Number of connections</source> @@ -2286,10 +2228,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">会话ID</translation> </message> @@ -2396,6 +2334,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/类型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2458,7 +2400,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>Last block time</source> - <translation type="unfinished">上一区块时间</translation> + <translation type="unfinished">最近區塊時間</translation> </message> <message> <source>&Open</source> @@ -2564,7 +2506,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 天(&A)</translation> + <translation type="unfinished">一天</translation> </message> <message> <source>1 &week</source> @@ -2588,6 +2530,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">网络活动已禁用</translation> </message> <message> + <source>None</source> + <translation type="unfinished">沒有</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何钱包执行命令</translation> </message> @@ -2623,7 +2569,7 @@ For more information on using this console, type %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(节点: %1)</translation> + <translation type="unfinished">(同儕:%1)</translation> </message> <message> <source>via %1</source> @@ -2813,11 +2759,11 @@ For more information on using this console, type %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">验证(&V)</translation> + <translation type="unfinished">&驗證</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">在像是硬件钱包屏幕的地方检验这个地址</translation> + <translation type="unfinished">在例如硬體錢包螢幕上驗證這個地址</translation> </message> <message> <source>&Save Image…</source> @@ -2955,7 +2901,7 @@ For more information on using this console, type %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">输入...</translation> + <translation type="unfinished">輸入…</translation> </message> <message> <source>Choose…</source> @@ -2969,9 +2915,9 @@ For more information on using this console, type %6. <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">指定交易虚拟大小的每kB (1,000字节) 自定义费率。 + <translation type="unfinished">指定每千字節(1,000字節)交易虛擬大小的自訂手續費。 -附注:因为矿工费是按字节计费的,所以如果费率是“每kvB支付100聪”,那么对于一笔500虚拟字节 (1kvB的一半) 的交易,最终将只会产生50聪的矿工费。(译注:这里就是提醒单位是字节,而不是千字节,如果搞错的话,矿工费会过低,导致交易长时间无法确认,或者压根无法发出)</translation> +注意:由於手續費是按每字節計算的,對於虛擬大小為500字節(半千字節)的交易,手續費率為「每千字節100聰」,最終將只收取50聰的手續費。</translation> </message> <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> @@ -3086,6 +3032,10 @@ 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 balance:</source> + <translation type="unfinished">外部餘額:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">或</translation> </message> @@ -3094,6 +3044,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">你可以之後再提高手續費(有 BIP-125 手續費追加的標記)</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">請檢查您的交易提案。這將產生部分簽名的比特幣交易(PSBT),您可以儲存或複製該交易,然後使用簽名。離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 from wallet '%2'</source> <translation type="unfinished">%1 来自钱包 “%2”</translation> </message> @@ -3225,7 +3180,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Remove this entry</source> @@ -3282,10 +3237,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">簽署訊息(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以使用您的地址簽名訊息/協議,以證明您可以接收發送給他們的比特幣。但是請小心,不要簽名語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽名的手法來冒充是你。只有簽名您同意的詳細內容。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用来对消息签名的地址</translation> </message> @@ -3295,7 +3246,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">从剪贴板粘贴地址</translation> + <translation type="unfinished">從剪貼簿粘貼錢包位址</translation> </message> <message> <source>Enter the message you want to sign here</source> @@ -3370,10 +3321,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">请检查地址后重试。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">找不到与输入地址相关的密钥。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">已取消解锁钱包。</translation> </message> @@ -3426,6 +3373,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <source>kB/s</source> + <translation type="unfinished">千字節/秒</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -3942,11 +3896,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT已複製</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">复制到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">沒辦法簽署交易。</translation> </message> @@ -3956,11 +3905,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Can't display address</source> - <translation type="unfinished">無法顯示地址</translation> - </message> - <message> - <source>default wallet</source> - <translation type="unfinished">預設錢包</translation> + <translation type="unfinished">無法顯示錢包位址</translation> </message> </context> <context> @@ -4010,6 +3955,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s 開發人員</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation type="unfinished">%s損壞。嘗試使用錢包工具bitcoin-wallet挽救或還原備份。</translation> + </message> + <message> <source>%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 验证 -assumeutxo 快照状态失败。这表明硬件可能有问题,也可能是软件bug,或者还可能是软件被不当修改、从而让非法快照也能够被加载。因此,将关闭节点并停止使用从这个快照构建出的任何状态,并将链高度从 %d 重置到 %d 。下次启动时,节点将会不使用快照数据从 %d 继续同步。请将这个事件报告给 %s 并在报告中包括您是如何获得这份快照的。无效的链状态快照仍被保存至磁盘上,以供诊断问题的原因。</translation> </message> @@ -4023,7 +3972,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">无法锁定数据目录 %s。%s 可能已经在运行。</translation> + <translation type="unfinished">無法在資料目錄上獲取鎖定%s。%s可能已經在運行了。</translation> </message> <message> <source>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> @@ -4051,7 +4000,9 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">错误: 转储文件标识符记录不正确。得到的是 "%s",而预期本应得到的是 "%s"。</translation> + <translation type="unfinished"> +錯誤:轉存檔案識別記錄不正確。獲得%s,預期 +%s。</translation> </message> <message> <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> @@ -4090,10 +4041,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">没有提供钱包格式。要使用 createfromdump ,必须提供 -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> - <translation type="unfinished">请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> @@ -4202,10 +4149,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">參數 -maxmempool 至少要給 %d 百萬位元組(MB)</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">发生了致命的内部错误,请在debug.log中查看详情</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">沒辦法解析 -%s 參數指定的地址: '%s'</translation> </message> @@ -4340,6 +4283,10 @@ Unable to restore backup of wallet.</source> 无法还原钱包备份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">区块验证已中断</translation> </message> @@ -4357,7 +4304,7 @@ Unable to restore backup of wallet.</source> </message> <message> <source>Could not find asmap file %s</source> - <translation type="unfinished">找不到asmap文件%s</translation> + <translation type="unfinished">找不到asmap 檔案 %s</translation> </message> <message> <source>Could not parse asmap file %s</source> @@ -4448,14 +4395,34 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: %s 所在的磁盘空间低。</translation> </message> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">錯誤:轉存檔案的校驗和不匹配。%s計算得%s</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">错误:创建新仅观察钱包失败</translation> </message> <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的鍵不是十六進制:%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的值不是十六進制:%s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">錯誤:keypool已用完,請先重新呼叫keypoolrefill</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">錯誤:缺少校驗和</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">錯誤: 沒有可用的 %s 地址</translation> + </message> + <message> <source>Error: This wallet already uses SQLite</source> <translation type="unfinished">错误:此钱包已经在使用SQLite</translation> </message> @@ -4508,6 +4475,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">错误: 钱包%s的数据库事务无法被执行</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to start indexes, shutting down..</source> <translation type="unfinished">无法启动索引,关闭中...</translation> </message> @@ -4516,6 +4487,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">校验数据库失败</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4540,6 +4519,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">dbcache不足以用于区块验证</translation> </message> <message> + <source>Insufficient funds</source> + <translation type="unfinished">金额不足</translation> + </message> + <message> <source>Invalid -i2psam address or hostname: '%s'</source> <translation type="unfinished">无效的 -i2psam 地址或主机名: '%s'</translation> </message> @@ -4712,10 +4695,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易位元量太大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation type="unfinished">沒辦法繫結在這台電腦上的 %s 。%s 可能已經在執行了。</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 17332db7b1..72432891a9 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -179,6 +179,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">輸入錢包的密碼短語和新密碼短語。</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">繼續</translation> + </message> + <message> + <source>Back</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> @@ -287,7 +295,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Error: %1</source> - <translation type="unfinished">錯誤:%1</translation> + <translation type="unfinished">错误:%1</translation> </message> <message> <source>%1 didn't yet exit safely…</source> @@ -436,6 +444,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>%1 GB</source> <translation type="unfinished">%1 GB (十億位元組)</translation> </message> + <message> + <source>default wallet</source> + <translation type="unfinished">默认钱包</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -525,57 +537,40 @@ 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> + <translation type="unfinished">备份钱包(&B)</translation> </message> <message> <source>&Change Passphrase…</source> - <translation type="unfinished">&更改密碼短語...</translation> - </message> - <message> - <source>Sign &message…</source> - <translation type="unfinished">簽名 &信息…</translation> + <translation type="unfinished">修改密码(&C)</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">&從檔案載入PSBT...</translation> + <translation type="unfinished">从文件加载PSBT(&L)...</translation> </message> <message> <source>Open &URI…</source> - <translation type="unfinished">開啟 &URI...</translation> + <translation type="unfinished">打开&URI...</translation> </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">關錢包..</translation> + <translation type="unfinished">关闭钱包...</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">創建錢包...</translation> - </message> - <message> - <source>Close All Wallets…</source> - <translation type="unfinished">關所有錢包...</translation> + <translation type="unfinished">创建钱包...</translation> </message> <message> <source>&File</source> @@ -594,24 +589,16 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">分頁工具列</translation> </message> <message> - <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">同步區塊頭 (%1%)…</translation> - </message> - <message> - <source>Synchronizing with network…</source> - <translation type="unfinished">正在與網絡同步…</translation> - </message> - <message> <source>Indexing blocks on disk…</source> - <translation type="unfinished">索引磁盤上的索引塊中...</translation> + <translation type="unfinished">对磁盘上的区块进行索引...</translation> </message> <message> <source>Processing blocks on disk…</source> - <translation type="unfinished">處理磁碟裡的區塊中...</translation> + <translation type="unfinished">处理磁盘上的区块...</translation> </message> <message> <source>Connecting to peers…</source> - <translation type="unfinished">正在跟其他節點連線中...</translation> + <translation type="unfinished">连到同行...</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> @@ -641,7 +628,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Catching up…</source> - <translation type="unfinished">追上中...</translation> + <translation type="unfinished">赶上...</translation> </message> <message> <source>Last received block was generated %1 ago.</source> @@ -746,10 +733,6 @@ Signing is only possible with addresses of the type 'legacy'.</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> @@ -838,7 +821,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Error: %1</source> - <translation type="unfinished">錯誤:%1</translation> + <translation type="unfinished">错误:%1</translation> </message> <message> <source>Warning: %1</source> @@ -992,15 +975,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Copy address</source> - <translation type="unfinished">&複製地址</translation> + <translation type="unfinished">&复制地址</translation> </message> <message> <source>Copy &label</source> - <translation type="unfinished">複製 &label</translation> + <translation type="unfinished">复制和标签</translation> </message> <message> <source>Copy &amount</source> - <translation type="unfinished">複製 &amount</translation> + <translation type="unfinished">复制和数量</translation> </message> <message> <source>Copy transaction &ID and output index</source> @@ -1146,10 +1129,6 @@ The migration process will create a backup of the wallet before migrating. This <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> @@ -2305,10 +2284,6 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">傳輸</translation> </message> <message> - <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">HEX格式的BIP324 session ID,如果有的話。</translation> - </message> - <message> <source>Version</source> <translation type="unfinished">版本</translation> </message> @@ -2411,6 +2386,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">方向/類型</translation> </message> <message> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished">十六进制格式的BIP324会话ID。</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> @@ -2579,7 +2558,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 天(&A)</translation> + <translation type="unfinished">1 天&</translation> </message> <message> <source>1 &week</source> @@ -2603,6 +2582,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">網路活動已關閉</translation> </message> <message> + <source>None</source> + <translation type="unfinished">無</translation> + </message> + <message> <source>Executing command without any wallet</source> <translation type="unfinished">不使用任何錢包來執行指令</translation> </message> @@ -2638,7 +2621,7 @@ For more information on using this console, type %6. </message> <message> <source>(peer: %1)</source> - <translation type="unfinished">(节点: %1)</translation> + <translation type="unfinished">(同儕:%1)</translation> </message> <message> <source>via %1</source> @@ -2787,7 +2770,11 @@ For more information on using this console, type %6. <source>Could not unlock wallet.</source> <translation type="unfinished">沒辦法把錢包解鎖。</translation> </message> - </context> + <message> + <source>Could not generate new %1 address</source> + <translation type="unfinished">無法產生新的 %1 地址</translation> + </message> +</context> <context> <name>ReceiveRequestDialog</name> <message> @@ -2824,11 +2811,11 @@ For more information on using this console, type %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">验证(&V)</translation> + <translation type="unfinished">&驗證</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">在像是硬件钱包屏幕的地方检验这个地址</translation> + <translation type="unfinished">在例如硬體錢包螢幕上驗證這個地址</translation> </message> <message> <source>&Save Image…</source> @@ -2966,7 +2953,7 @@ For more information on using this console, type %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">输入...</translation> + <translation type="unfinished">輸入…</translation> </message> <message> <source>Choose…</source> @@ -2980,9 +2967,9 @@ For more information on using this console, type %6. <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> - <translation type="unfinished">指定交易虚拟大小的每kB (1,000字节) 自定义费率。 + <translation type="unfinished">指定每千字節(1,000字節)交易虛擬大小的自訂手續費。 -附注:因为矿工费是按字节计费的,所以如果费率是“每kvB支付100聪”,那么对于一笔500虚拟字节 (1kvB的一半) 的交易,最终将只会产生50聪的矿工费。(译注:这里就是提醒单位是字节,而不是千字节,如果搞错的话,矿工费会过低,导致交易长时间无法确认,或者压根无法发出)</translation> +注意:由於手續費是按每字節計算的,對於虛擬大小為500字節(半千字節)的交易,手續費率為「每千字節100聰」,最終將只收取50聰的手續費。</translation> </message> <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> @@ -3071,6 +3058,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Cr&eate未簽名</translation> </message> <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation type="unfinished">產生一個部分簽名的比特幣交易(PSBT)以用於例如離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 to '%2'</source> <translation type="unfinished">%1 到 '%2'</translation> </message> @@ -3111,6 +3102,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">PSBT已儲存</translation> </message> <message> + <source>External balance:</source> + <translation type="unfinished">外部餘額:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">或</translation> </message> @@ -3119,6 +3114,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">你可以之後再提高手續費(有 BIP-125 手續費追加的標記)</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment> + <translation type="unfinished">請檢查您的交易提案。這將產生部分簽名的比特幣交易(PSBT),您可以儲存或複製該交易,然後使用簽名。離線%1錢包或與PSBT相容的硬體錢包。</translation> + </message> + <message> <source>%1 from wallet '%2'</source> <translation type="unfinished">%1 来自钱包 “%2”</translation> </message> @@ -3307,10 +3307,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">簽署訊息(&S)</translation> </message> <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation type="unfinished">您可以使用您的地址簽名訊息/協議,以證明您可以接收發送給他們的比特幣。但是請小心,不要簽名語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽名的手法來冒充是你。只有簽名您同意的詳細內容。</translation> - </message> - <message> <source>The Bitcoin address to sign the message with</source> <translation type="unfinished">用來簽名訊息的 比特幣地址</translation> </message> @@ -3395,10 +3391,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">請檢查地址是否正確後再試一次。</translation> </message> <message> - <source>The entered address does not refer to a key.</source> - <translation type="unfinished">輸入的地址沒有對應到你的任何鑰匙。</translation> - </message> - <message> <source>Wallet unlock was cancelled.</source> <translation type="unfinished">錢包解鎖已取消。</translation> </message> @@ -3451,6 +3443,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <source>kB/s</source> + <translation type="unfinished">千字節/秒</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -3971,11 +3970,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">PSBT已複製</translation> </message> <message> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> - <translation type="unfinished">複製到剪贴板</translation> - </message> - <message> <source>Can't sign transaction.</source> <translation type="unfinished">沒辦法簽署交易。</translation> </message> @@ -3987,10 +3981,6 @@ Go to File > Open Wallet to load a wallet. <source>Can't display address</source> <translation type="unfinished">無法顯示地址</translation> </message> - <message> - <source>default wallet</source> - <translation type="unfinished">預設錢包</translation> - </message> </context> <context> <name>WalletView</name> @@ -4039,6 +4029,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">%s 開發人員</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation type="unfinished">%s損壞。嘗試使用錢包工具bitcoin-wallet挽救或還原備份。</translation> + </message> + <message> <source>%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 驗證 -assumeutxo 快照狀態失敗。 這顯示硬體可能有問題,也可能是軟體bug,或是軟體被不當修改、從而讓非法快照也能夠載入。 因此,將關閉節點並停止使用從這個快照建構出的任何狀態,並將鏈高度從 %d 重置到 %d 。下次啟動時,節點將會不使用快照資料從 %d 繼續同步。 請將這個事件回報給 %s 並在報告中包括您是如何獲得這份快照的。 無效的鏈狀態快照仍保存至磁碟上,以供診斷問題的原因。</translation> </message> @@ -4080,7 +4074,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <translation type="unfinished">错误: 转储文件标识符记录不正确。得到的是 "%s",而预期本应得到的是 "%s"。</translation> + <translation type="unfinished">錯誤: 轉存檔案識別記錄不正確。獲得 '%s',預期 '%s'。</translation> </message> <message> <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> @@ -4119,10 +4113,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">沒有提供錢包格式。 要使用 createfromdump ,必須提供 -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> - <translation type="unfinished">請檢查電腦日期和時間是否正確!%s 沒辦法在時鐘不準的情況下正常運作。</translation> - </message> - <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished">如果你覺得 %s 有用,可以幫助我們。關於這個軟體的更多資訊請見 %s。</translation> </message> @@ -4231,10 +4221,6 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">參數 -maxmempool 至少要給 %d 百萬位元組(MB)</translation> </message> <message> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">發生致命的內部錯誤,有關詳細細節,請參見debug.log</translation> - </message> - <message> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished">沒辦法解析 -%s 參數指定的地址: '%s'</translation> </message> @@ -4369,6 +4355,10 @@ Unable to restore backup of wallet.</source> 無法還原錢包備份</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished">發生致命的內部錯誤,有關詳情請查看 debug.log:</translation> + </message> + <message> <source>Block verification was interrupted</source> <translation type="unfinished">區塊驗證已中斷</translation> </message> @@ -4385,6 +4375,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">發現區塊資料庫壞掉了</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation type="unfinished">找不到asmap 檔案 %s</translation> + </message> + <message> <source>Could not parse asmap file %s</source> <translation type="unfinished">無法解析asmap文件%s</translation> </message> @@ -4473,14 +4467,34 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">錯誤: 硬碟空間不足 %s</translation> </message> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">錯誤:轉存檔案的校驗和不匹配。%s計算得%s</translation> + </message> + <message> <source>Error: Failed to create new watchonly wallet</source> <translation type="unfinished">錯誤:建立新僅觀察錢包失敗</translation> </message> <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的鍵不是十六進制:%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">錯誤:獲得的值不是十六進制:%s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">錯誤:keypool已用完,請先重新呼叫keypoolrefill</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">錯誤:缺少校驗和</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">錯誤: 沒有可用的 %s 地址</translation> + </message> + <message> <source>Error: This wallet already uses SQLite</source> <translation type="unfinished">錯誤:此錢包已經在使用SQLite</translation> </message> @@ -4537,6 +4551,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">在任意的通訊埠聽候失敗。如果你希望這樣的話,可以設定 -listen=0.</translation> </message> <message> + <source>Failed to read block.</source> + <translation type="unfinished">讀取區塊失敗。</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">初始化時重新掃描錢包失敗了</translation> </message> @@ -4549,6 +4567,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">無法驗證資料庫</translation> </message> <message> + <source>Failed to write block.</source> + <translation type="unfinished">寫入區塊失敗。</translation> + </message> + <message> + <source>Failed to write to block index database.</source> + <translation type="unfinished">寫入區塊索引資料庫失敗。</translation> + </message> + <message> <source>Failure removing transaction: %s</source> <translation type="unfinished">%s删除交易时失败: </translation> </message> @@ -4781,10 +4807,6 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">交易位元量太大</translation> </message> <message> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished">無法為 -maxsigcachesize: '%s' MiB 分配内存</translation> - </message> - <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">無法和這台電腦上的 %s 繫結(回傳錯誤 %s)</translation> </message> diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index 7bc6ccdc49..522ecfd801 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/modaloverlay.h> #include <qt/forms/ui_modaloverlay.h> @@ -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/notificator.cpp b/src/qt/notificator.cpp index 85bdeee49a..af97bb2143 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/notificator.h> diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 8808716aa4..932cfc4651 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_QT_NOTIFICATOR_H #define BITCOIN_QT_NOTIFICATOR_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <QIcon> #include <QObject> diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index ee53a59bb5..b70769ed24 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/optionsdialog.h> #include <qt/forms/ui_optionsdialog.h> @@ -87,14 +87,15 @@ 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); + ui->databaseCache->setRange(nMinDbCache, std::numeric_limits<int>::max()); ui->threadsScriptVerif->setMinimum(-GetNumCores()); ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS); ui->pruneWarning->setVisible(false); @@ -107,9 +108,6 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) #ifndef USE_UPNP ui->mapPortUpnp->setEnabled(false); #endif -#ifndef USE_NATPMP - ui->mapPortNatpmp->setEnabled(false); -#endif ui->proxyIp->setEnabled(false); ui->proxyPort->setEnabled(false); @@ -168,8 +166,15 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) /** check if the locale name consists of 2 parts (language_country) */ if(langStr.contains("_")) { - /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */ - ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); + /** display language strings as "native language - native country/territory (locale name)", e.g. "Deutsch - Deutschland (de)" */ + ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)) + locale.nativeTerritoryName() + +#else + locale.nativeCountryName() + +#endif + QString(" (") + langStr + QString(")"), QVariant(langStr)); + } else { @@ -440,7 +445,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/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 0c21c6748d..5bca5c5320 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/optionsmodel.h> @@ -320,10 +320,15 @@ static ProxySetting ParseProxyString(const QString& proxy) if (proxy.isEmpty()) { return default_val; } - // contains IP at index 0 and port at index 1 - QStringList ip_port = GUIUtil::SplitSkipEmptyParts(proxy, ":"); - if (ip_port.size() == 2) { - return {true, ip_port.at(0), ip_port.at(1)}; + uint16_t port{0}; + std::string hostname; + if (SplitHostPort(proxy.toStdString(), port, hostname) && port != 0) { + // Valid and port within the valid range + // Check if the hostname contains a colon, indicating an IPv6 address + if (hostname.find(':') != std::string::npos) { + hostname = "[" + hostname + "]"; // Wrap IPv6 address in brackets + } + return {true, QString::fromStdString(hostname), QString::number(port)}; } else { // Invalid: return default return default_val; } @@ -414,11 +419,7 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return false; #endif // USE_UPNP case MapPortNatpmp: -#ifdef USE_NATPMP return SettingToBool(setting(), DEFAULT_NATPMP); -#else - return false; -#endif // USE_NATPMP case MinimizeOnClose: return fMinimizeOnClose; diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 353709c7f5..5a4b4442f3 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -4,10 +4,12 @@ #include <qt/psbtoperationsdialog.h> +#include <common/messages.h> #include <core_io.h> #include <interfaces/node.h> #include <key_io.h> #include <node/psbt.h> +#include <node/types.h> #include <policy/policy.h> #include <qt/bitcoinunits.h> #include <qt/forms/ui_psbtoperationsdialog.h> @@ -20,9 +22,11 @@ #include <iostream> #include <string> +using common::TransactionErrorString; using node::AnalyzePSBT; using node::DEFAULT_MAX_RAW_TX_FEE_RATE; using node::PSBTAnalysis; +using node::TransactionError; PSBTOperationsDialog::PSBTOperationsDialog( QWidget* parent, WalletModel* wallet_model, ClientModel* client_model) : QDialog(parent, GUIUtil::dialog_flags), @@ -55,10 +59,10 @@ void PSBTOperationsDialog::openWithPSBT(PartiallySignedTransaction psbtx) bool complete = FinalizePSBT(psbtx); // Make sure all existing signatures are fully combined before checking for completeness. if (m_wallet_model) { size_t n_could_sign; - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, &n_could_sign, m_transaction_data, complete); - if (err != TransactionError::OK) { + const auto err{m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, &n_could_sign, m_transaction_data, complete)}; + if (err) { showStatus(tr("Failed to load transaction: %1") - .arg(QString::fromStdString(TransactionErrorString(err).translated)), + .arg(QString::fromStdString(PSBTErrorString(*err).translated)), StatusLevel::ERR); return; } @@ -79,11 +83,11 @@ void PSBTOperationsDialog::signTransaction() WalletModel::UnlockContext ctx(m_wallet_model->requestUnlock()); - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, &n_signed, m_transaction_data, complete); + const auto err{m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, &n_signed, m_transaction_data, complete)}; - if (err != TransactionError::OK) { + if (err) { showStatus(tr("Failed to sign transaction: %1") - .arg(QString::fromStdString(TransactionErrorString(err).translated)), StatusLevel::ERR); + .arg(QString::fromStdString(PSBTErrorString(*err).translated)), StatusLevel::ERR); return; } @@ -247,9 +251,9 @@ size_t PSBTOperationsDialog::couldSignInputs(const PartiallySignedTransaction &p size_t n_signed; bool complete; - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/false, &n_signed, m_transaction_data, complete); + const auto err{m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/false, &n_signed, m_transaction_data, complete)}; - if (err != TransactionError::OK) { + if (err) { return 0; } return n_signed; diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index f6e712a047..e912dafa60 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -15,7 +15,7 @@ #include <QMouseEvent> #include <QPainter> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #ifdef USE_QRCODE #include <qrencode.h> diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index b4322ddc0f..a5ee6583e0 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -14,7 +14,7 @@ #include <QDialog> #include <QString> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep ReceiveRequestDialog::ReceiveRequestDialog(QWidget* parent) : QDialog(parent, GUIUtil::dialog_flags), diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 52d4e45d49..a8d54cdc0c 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -20,6 +20,8 @@ #include <QLatin1Char> #include <QLatin1String> +using util::ToString; + RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : QAbstractTableModel(parent), walletModel(parent) { diff --git a/src/qt/res/bitcoin-qt-res.rc b/src/qt/res/bitcoin-qt-res.rc index e590b407b0..d84744f91e 100644 --- a/src/qt/res/bitcoin-qt-res.rc +++ b/src/qt/res/bitcoin-qt-res.rc @@ -1,5 +1,7 @@ IDI_ICON1 ICON DISCARDABLE "icons/bitcoin.ico" IDI_ICON2 ICON DISCARDABLE "icons/bitcoin_testnet.ico" +IDI_ICON3 ICON DISCARDABLE "icons/bitcoin_signet.ico" +IDI_ICON4 ICON DISCARDABLE "icons/bitcoin_testnet.ico" // testnet4 #include <windows.h> // needed for VERSIONINFO #include "../../clientversion.h" // holds the needed client version information diff --git a/src/qt/res/icons/bitcoin_signet.ico b/src/qt/res/icons/bitcoin_signet.ico Binary files differnew file mode 100644 index 0000000000..fb9be5153b --- /dev/null +++ b/src/qt/res/icons/bitcoin_signet.ico diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 702ca44395..018c22a4a8 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/rpcconsole.h> #include <qt/forms/ui_debugwindow.h> @@ -16,7 +16,9 @@ #include <qt/guiutil.h> #include <qt/peertablesortproxy.h> #include <qt/platformstyle.h> +#ifdef ENABLE_WALLET #include <qt/walletmodel.h> +#endif // ENABLE_WALLET #include <rpc/client.h> #include <rpc/server.h> #include <util/strencodings.h> @@ -48,6 +50,8 @@ #include <chrono> +using util::Join; + const int CONSOLE_HISTORY = 50; const int INITIAL_TRAFFIC_GRAPH_MINS = 30; const QSize FONT_RANGE(4, 40); @@ -558,6 +562,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); @@ -975,6 +980,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) @@ -998,15 +1015,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() @@ -1248,6 +1266,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(); } @@ -1398,4 +1417,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..894ecb1fdf 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_QT_RPCCONSOLE_H #define BITCOIN_QT_RPCCONSOLE_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/clientmodel.h> #include <qt/guiutil.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/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0d8c0f7a63..4019ca5e9d 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/sendcoinsdialog.h> #include <qt/forms/ui_sendcoinsdialog.h> @@ -20,6 +20,7 @@ #include <interfaces/node.h> #include <key_io.h> #include <node/interface_ui.h> +#include <node/types.h> #include <policy/fees.h> #include <txmempool.h> #include <validation.h> @@ -37,6 +38,7 @@ #include <QSettings> #include <QTextDocument> +using common::PSBTError; using wallet::CCoinControl; using wallet::DEFAULT_PAY_TX_FEE; @@ -442,26 +444,26 @@ void SendCoinsDialog::presentPSBT(PartiallySignedTransaction& psbtx) } bool SendCoinsDialog::signWithExternalSigner(PartiallySignedTransaction& psbtx, CMutableTransaction& mtx, bool& complete) { - TransactionError err; + std::optional<PSBTError> err; try { err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete); } catch (const std::runtime_error& e) { QMessageBox::critical(nullptr, tr("Sign failed"), e.what()); return false; } - if (err == TransactionError::EXTERNAL_SIGNER_NOT_FOUND) { + if (err == PSBTError::EXTERNAL_SIGNER_NOT_FOUND) { //: "External signer" means using devices such as hardware wallets. const QString msg = tr("External signer not found"); QMessageBox::critical(nullptr, msg, msg); return false; } - if (err == TransactionError::EXTERNAL_SIGNER_FAILED) { + if (err == PSBTError::EXTERNAL_SIGNER_FAILED) { //: "External signer" means using devices such as hardware wallets. const QString msg = tr("External signer failure"); QMessageBox::critical(nullptr, msg, msg); return false; } - if (err != TransactionError::OK) { + if (err) { tfm::format(std::cerr, "Failed to sign PSBT"); processSendCoinsReturn(WalletModel::TransactionCreationFailed); return false; @@ -501,9 +503,9 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) PartiallySignedTransaction psbtx(mtx); bool complete = false; // Fill without signing - TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete); + const auto err{model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete)}; assert(!complete); - assert(err == TransactionError::OK); + assert(!err); // Copy PSBT to clipboard and offer to save presentPSBT(psbtx); @@ -517,9 +519,9 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) bool complete = false; // Always fill without signing first. This prevents an external signer // from being called prematurely and is not expensive. - TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete); + const auto err{model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete)}; assert(!complete); - assert(err == TransactionError::OK); + assert(!err); send_failure = !signWithExternalSigner(psbtx, mtx, complete); // Don't broadcast when user rejects it on the device or there's a failure: broadcast = complete && !send_failure; diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 4392d76328..0b1d3c6c3a 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -10,9 +10,9 @@ #include <qt/platformstyle.h> #include <qt/walletmodel.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <common/signmessage.h> // For MessageSign(), MessageVerify() +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <key_io.h> -#include <util/message.h> // For MessageSign(), MessageVerify() #include <wallet/wallet.h> #include <vector> diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index ffd6689910..e194b5fd32 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/splashscreen.h> diff --git a/src/qt/test/CMakeLists.txt b/src/qt/test/CMakeLists.txt new file mode 100644 index 0000000000..582ed71466 --- /dev/null +++ b/src/qt/test/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_executable(test_bitcoin-qt + apptests.cpp + optiontests.cpp + rpcnestedtests.cpp + test_main.cpp + uritests.cpp + util.cpp + ../../init/bitcoin-qt.cpp +) + +target_link_libraries(test_bitcoin-qt + core_interface + bitcoinqt + test_util + bitcoin_node + Boost::headers + Qt5::Test +) + +import_plugins(test_bitcoin-qt) + +if(ENABLE_WALLET) + target_sources(test_bitcoin-qt + PRIVATE + addressbooktests.cpp + wallettests.cpp + ../../wallet/test/wallet_test_fixture.cpp + ) +endif() + +if(NOT QT_IS_STATIC) + add_custom_command( + TARGET test_bitcoin-qt POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_PROPERTY:Qt5::QMinimalIntegrationPlugin,LOCATION_$<UPPER_CASE:$<CONFIG>>> $<TARGET_FILE_DIR:test_bitcoin-qt>/plugins/platforms + VERBATIM + ) +endif() + +add_test(NAME test_bitcoin-qt + COMMAND test_bitcoin-qt +) +if(WIN32 AND VCPKG_TARGET_TRIPLET) + # On Windows, vcpkg configures Qt with `-opengl dynamic`, which makes + # the "minimal" platform plugin unusable due to internal Qt bugs. + set_tests_properties(test_bitcoin-qt PROPERTIES + ENVIRONMENT "QT_QPA_PLATFORM=windows" + ) +endif() + +install(TARGETS test_bitcoin-qt + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/qt/test/Makefile b/src/qt/test/Makefile deleted file mode 100644 index a02f86b62a..0000000000 --- a/src/qt/test/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: - $(MAKE) -C ../../ test_bitcoin_qt -clean: - $(MAKE) -C ../../ test_bitcoin_qt_clean -check: - $(MAKE) -C ../../ test_bitcoin_qt_check diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index f7d66f316e..3d5cb4a863 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -222,8 +222,8 @@ void AddressBookTests::addressBookTests() // framework when it tries to look up unimplemented cocoa functions, // and fails to handle returned nulls // (https://bugreports.qt.io/browse/QTBUG-49686). - QWARN("Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " - "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build."); + qWarning() << "Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " + "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build."; return; } #endif diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 10abcb00eb..73e04b55c8 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -60,8 +60,8 @@ void AppTests::appTests() // framework when it tries to look up unimplemented cocoa functions, // and fails to handle returned nulls // (https://bugreports.qt.io/browse/QTBUG-49686). - QWARN("Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " - "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build."); + qWarning() << "Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " + "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build."; return; } #endif diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp index 0f82f65f3e..4f3eb778c5 100644 --- a/src/qt/test/optiontests.cpp +++ b/src/qt/test/optiontests.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <common/args.h> #include <init.h> diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index 72e8055425..0797d31a71 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -127,6 +127,11 @@ void RPCNestedTests::rpcNestedTests() RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest( abc , cba )"); QVERIFY(result == "[\"abc\",\"cba\"]"); +// Handle deprecated macro, can be removed once minimum Qt is at least 6.3.0. +#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) +#undef QVERIFY_EXCEPTION_THROWN +#define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) QVERIFY_THROWS_EXCEPTION(exceptiontype, expression) +#endif QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo("); //tolerate non closing brackets if we have no arguments diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index f310d0a02b..172c06f4ea 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <interfaces/init.h> #include <interfaces/node.h> @@ -28,22 +28,6 @@ #include <functional> -#if defined(QT_STATICPLUGIN) -#include <QtPlugin> -#if defined(QT_QPA_PLATFORM_MINIMAL) -Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin); -#endif -#if defined(QT_QPA_PLATFORM_XCB) -Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); -#elif defined(QT_QPA_PLATFORM_WINDOWS) -Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); -#elif defined(QT_QPA_PLATFORM_COCOA) -Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); -#elif defined(QT_QPA_PLATFORM_ANDROID) -Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin) -#endif -#endif - const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{}; @@ -74,7 +58,7 @@ int main(int argc, char* argv[]) gArgs.ForceSetArg("-natpmp", "0"); std::string error; - if (!gArgs.ReadConfigFiles(error, true)) QWARN(error.c_str()); + if (!gArgs.ReadConfigFiles(error, true)) qWarning() << error.c_str(); // Prefer the "minimal" platform for the test instead of the normal default // platform ("xcb", "windows", or "cocoa") so tests can't unintentionally diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 603df0b15f..98dfe12f08 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -199,7 +199,7 @@ std::shared_ptr<CWallet> SetupLegacyWatchOnlyWallet(interfaces::Node& node, Test wallet->SetupLegacyScriptPubKeyMan(); // Add watched key CPubKey pubKey = test.coinbaseKey.GetPubKey(); - bool import_keys = wallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*internal=*/false, /*timestamp=*/1); + bool import_keys = wallet->ImportPubKeys({{pubKey.GetID(), false}}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*timestamp=*/1); assert(import_keys); wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash())); } @@ -218,8 +218,10 @@ std::shared_ptr<CWallet> SetupDescriptorsWallet(interfaces::Node& node, TestChai // Add the coinbase key FlatSigningProvider provider; std::string error; - std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false); - assert(desc); + auto descs = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false); + assert(!descs.empty()); + assert(descs.size() == 1); + auto& desc = descs.at(0); WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1); if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false); CTxDestination dest = GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type); @@ -473,8 +475,8 @@ void WalletTests::walletTests() // framework when it tries to look up unimplemented cocoa functions, // and fails to handle returned nulls // (https://bugreports.qt.io/browse/QTBUG-49686). - QWARN("Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " - "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build."); + qWarning() << "Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " + "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build."; return; } #endif 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/utilitydialog.cpp b/src/qt/utilitydialog.cpp index f261c6409d..29b7f5c401 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <qt/utilitydialog.h> diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index c7fe62f4e9..dd093e984a 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -30,6 +30,7 @@ #include <QTimer> #include <QWindow> +using util::Join; using wallet::WALLET_FLAG_BLANK_WALLET; using wallet::WALLET_FLAG_DESCRIPTORS; using wallet::WALLET_FLAG_DISABLE_PRIVATE_KEYS; @@ -64,20 +65,28 @@ 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; } +void WalletController::removeWallet(WalletModel* wallet_model) +{ + // Once the wallet is successfully removed from the node, the model will emit the 'WalletModel::unload' signal. + // This signal is already connected and will complete the removal of the view from the GUI. + // Look at 'WalletController::getOrCreateWallet' for the signal connection. + wallet_model->wallet().remove(); +} + void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent) { QMessageBox box(parent); @@ -88,10 +97,7 @@ void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent) box.setDefaultButton(QMessageBox::Yes); if (box.exec() != QMessageBox::Yes) return; - // First remove wallet from node. - wallet_model->wallet().remove(); - // Now release the model. - removeAndDeleteWallet(wallet_model); + removeWallet(wallet_model); } void WalletController::closeAllWallets(QWidget* parent) @@ -104,11 +110,8 @@ void WalletController::closeAllWallets(QWidget* parent) QMutexLocker locker(&m_mutex); for (WalletModel* wallet_model : m_wallets) { - wallet_model->wallet().remove(); - Q_EMIT walletRemoved(wallet_model); - delete wallet_model; + removeWallet(wallet_model); } - m_wallets.clear(); } WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet) @@ -149,9 +152,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); @@ -342,7 +346,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. @@ -435,12 +439,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" @@ -451,31 +455,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..4d2ba43539 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); @@ -87,6 +85,9 @@ private: friend class WalletControllerActivity; friend class MigrateWalletActivity; + + //! Starts the wallet closure procedure + void removeWallet(WalletModel* wallet_model); }; class WalletControllerActivity : public QObject @@ -186,7 +187,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 87ad98a4cc..0a01c0a45b 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -19,6 +19,7 @@ #include <interfaces/node.h> #include <key_io.h> #include <node/interface_ui.h> +#include <node/types.h> #include <psbt.h> #include <util/translation.h> #include <wallet/coincontrol.h> @@ -534,8 +535,8 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) // "Create Unsigned" clicked PartiallySignedTransaction psbtx(mtx); bool complete = false; - const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, nullptr, psbtx, complete); - if (err != TransactionError::OK || complete) { + const auto err{wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, nullptr, psbtx, complete)}; + if (err || complete) { QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't draft transaction.")); return false; } @@ -593,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/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index 0b5278c192..9ccd7028da 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -12,7 +12,11 @@ // If we don't want a message to be processed by Qt, return true and set result to // the value that the window procedure should return. Otherwise return false. +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pMessage, qintptr *pnResult) +#else bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult) +#endif { Q_UNUSED(eventType); diff --git a/src/qt/winshutdownmonitor.h b/src/qt/winshutdownmonitor.h index 060d8546e3..a8b626065d 100644 --- a/src/qt/winshutdownmonitor.h +++ b/src/qt/winshutdownmonitor.h @@ -20,7 +20,11 @@ public: WinShutdownMonitor(std::function<void()> shutdown_fn) : m_shutdown_fn{std::move(shutdown_fn)} {} /** Implements QAbstractNativeEventFilter interface for processing Windows messages */ +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + bool nativeEventFilter(const QByteArray &eventType, void *pMessage, qintptr *pnResult) override; +#else bool nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult) override; +#endif /** Register the reason for blocking shutdown on Windows to allow clean client exit */ static void registerShutdownBlockReason(const QString& strReason, const HWND& mainWinId); diff --git a/src/random.cpp b/src/random.cpp index 239d5bc6fe..163112585a 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <random.h> @@ -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); @@ -572,13 +602,13 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept // Dynamic environment data (performance monitoring, ...) auto old_size = hasher.Size(); RandAddDynamicEnv(hasher); - LogPrint(BCLog::RAND, "Feeding %i bytes of dynamic environment data into RNG\n", hasher.Size() - old_size); + LogDebug(BCLog::RAND, "Feeding %i bytes of dynamic environment data into RNG\n", hasher.Size() - old_size); // Strengthen for 10 ms 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); @@ -592,7 +622,7 @@ static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept // Static environment data RandAddStaticEnv(hasher); - LogPrint(BCLog::RAND, "Feeding %i bytes of environment data into RNG\n", hasher.Size() - old_size); + LogDebug(BCLog::RAND, "Feeding %i bytes of environment data into RNG\n", hasher.Size() - old_size); // Strengthen for 100 ms SeedStrengthen(hasher, rng, 100ms); @@ -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 aeec959c28..dee48481c5 100644 --- a/src/randomenv.cpp +++ b/src/randomenv.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <randomenv.h> @@ -42,15 +42,15 @@ #if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS #include <ifaddrs.h> #endif -#if HAVE_SYSCTL +#ifdef HAVE_SYSCTL #include <sys/sysctl.h> -#if HAVE_VM_VM_PARAM_H +#ifdef HAVE_VM_VM_PARAM_H #include <vm/vm_param.h> #endif -#if HAVE_SYS_RESOURCES_H +#ifdef HAVE_SYS_RESOURCES_H #include <sys/resources.h> #endif -#if HAVE_SYS_VMMETER_H +#ifdef HAVE_SYS_VMMETER_H #include <sys/vmmeter.h> #endif #endif @@ -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); @@ -162,7 +164,7 @@ void AddPath(CSHA512& hasher, const char *path) } #endif -#if HAVE_SYSCTL +#ifdef HAVE_SYSCTL template<int... S> void AddSysctl(CSHA512& hasher) { @@ -274,7 +276,7 @@ void RandAddDynamicEnv(CSHA512& hasher) AddFile(hasher, "/proc/self/status"); #endif -#if HAVE_SYSCTL +#ifdef HAVE_SYSCTL # ifdef CTL_KERN # if defined(KERN_PROC) && defined(KERN_PROC_ALL) AddSysctl<CTL_KERN, KERN_PROC, KERN_PROC_ALL>(hasher); @@ -419,7 +421,7 @@ void RandAddStaticEnv(CSHA512& hasher) // For MacOS/BSDs, gather data through sysctl instead of /proc. Not all of these // will exist on every system. -#if HAVE_SYSCTL +#ifdef HAVE_SYSCTL # ifdef CTL_HW # ifdef HW_MACHINE AddSysctl<CTL_HW, HW_MACHINE>(hasher); diff --git a/src/rest.cpp b/src/rest.cpp index 4e9d8fd2b1..ca26c699b5 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <rest.h> @@ -39,6 +39,7 @@ using node::GetTransaction; using node::NodeContext; +using util::SplitString; static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once static constexpr unsigned int MAX_REST_HEADERS_RESULTS = 2000; @@ -216,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; @@ -230,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) { @@ -247,9 +249,8 @@ static bool rest_headers(const std::any& context, ssHeader << pindex->GetBlockHeader(); } - std::string binaryHeader = ssHeader.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryHeader); + req->WriteReply(HTTP_OK, ssHeader); return true; } @@ -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,12 +305,15 @@ 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"); } - if (chainman.m_blockman.IsBlockPruned(*pblockindex)) { - return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); + if (!(pblockindex->nStatus & BLOCK_HAVE_DATA)) { + if (chainman.m_blockman.IsBlockPruned(*pblockindex)) { + return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); + } + return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (not fully downloaded)"); } pos = pblockindex->GetBlockPos(); } @@ -320,9 +325,8 @@ static bool rest_block(const std::any& context, switch (rf) { case RESTResponseFormat::BINARY: { - const std::string binaryBlock{block_data.begin(), block_data.end()}; req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryBlock); + req->WriteReply(HTTP_OK, std::as_bytes(std::span{block_data})); return true; } @@ -391,8 +395,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); } @@ -414,7 +418,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) @@ -450,9 +454,8 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const ssHeader << header; } - std::string binaryHeader = ssHeader.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryHeader); + req->WriteReply(HTTP_OK, ssHeader); return true; } case RESTResponseFormat::HEX: { @@ -496,8 +499,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]); } @@ -518,7 +521,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"); } @@ -547,9 +550,8 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s DataStream ssResp{}; ssResp << filter; - std::string binaryResp = ssResp.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryResp); + req->WriteReply(HTTP_OK, ssResp); return true; } case RESTResponseFormat::HEX: { @@ -619,14 +621,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"); } @@ -707,9 +709,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(); @@ -718,7 +721,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"); } @@ -728,9 +731,8 @@ static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string DataStream ssTx; ssTx << TX_WITH_WITNESS(tx); - std::string binaryTx = ssTx.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryTx); + req->WriteReply(HTTP_OK, ssTx); return true; } @@ -792,14 +794,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) @@ -899,10 +905,9 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: // use exact same output as mentioned in Bip64 DataStream ssGetUTXOResponse{}; ssGetUTXOResponse << active_height << active_hash << bitmap << outs; - std::string ssGetUTXOResponseString = ssGetUTXOResponse.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, ssGetUTXOResponseString); + req->WriteReply(HTTP_OK, ssGetUTXOResponse); return true; } @@ -980,7 +985,7 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req, DataStream ss_blockhash{}; ss_blockhash << pblockindex->GetBlockHash(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, ss_blockhash.str()); + req->WriteReply(HTTP_OK, ss_blockhash); return true; } case RESTResponseFormat::HEX: { 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 3e3e91927c..360f24ec55 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> @@ -21,6 +22,7 @@ #include <hash.h> #include <index/blockfilterindex.h> #include <index/coinstatsindex.h> +#include <interfaces/mining.h> #include <kernel/coinstats.h> #include <logging/timer.h> #include <net.h> @@ -29,6 +31,7 @@ #include <node/context.h> #include <node/transaction.h> #include <node/utxo_snapshot.h> +#include <node/warnings.h> #include <primitives/transaction.h> #include <rpc/server.h> #include <rpc/server_util.h> @@ -54,23 +57,32 @@ #include <condition_variable> #include <memory> #include <mutex> +#include <optional> using kernel::CCoinsStats; using kernel::CoinStatsHashType; +using interfaces::Mining; using node::BlockManager; using node::NodeContext; using node::SnapshotMetadata; +using util::MakeUnorderedList; -struct CUpdatedBlock -{ - uint256 hash; - int height; -}; +std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*> +PrepareUTXOSnapshot( + Chainstate& chainstate, + const std::function<void()>& interruption_point = {}) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); -static GlobalMutex cs_blockchange; -static std::condition_variable cond_blockchange; -static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange); +UniValue WriteUTXOSnapshot( + Chainstate& chainstate, + CCoinsViewCursor* pcursor, + CCoinsStats* maybe_stats, + const CBlockIndex* tip, + AutoFile& afile, + const fs::path& path, + const fs::path& temppath, + const std::function<void()>& interruption_point = {}); /* Calculate the difficulty for a given block index. */ @@ -181,8 +193,10 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn case TxVerbosity::SHOW_DETAILS_AND_PREVOUT: CBlockUndo blockUndo; const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))}; - const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, blockindex)}; - + bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)}; + if (have_undo && !blockman.UndoReadFromDisk(blockUndo, blockindex)) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); + } for (size_t i = 0; i < block.vtx.size(); ++i) { const CTransactionRef& tx = block.vtx.at(i); // coinbase transaction (i.e. i == 0) doesn't have undo data @@ -240,21 +254,12 @@ static RPCHelpMan getbestblockhash() }; } -void RPCNotifyBlockChange(const CBlockIndex* pindex) -{ - if(pindex) { - LOCK(cs_blockchange); - latestblock.hash = pindex->GetBlockHash(); - latestblock.height = pindex->nHeight; - } - cond_blockchange.notify_all(); -} - static RPCHelpMan waitfornewblock() { return RPCHelpMan{"waitfornewblock", - "\nWaits for a specific new block and returns useful info about it.\n" - "\nReturns the current block on timeout or exit.\n", + "\nWaits for any new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", { {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."}, }, @@ -273,17 +278,16 @@ static RPCHelpMan waitfornewblock() int timeout = 0; if (!request.params[0].isNull()) timeout = request.params[0].getInt<int>(); + if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout"); - CUpdatedBlock block; - { - WAIT_LOCK(cs_blockchange, lock); - block = latestblock; - if(timeout) - cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); - else - cond_blockchange.wait(lock, [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); - block = latestblock; + NodeContext& node = EnsureAnyNodeContext(request.context); + Mining& miner = EnsureMining(node); + + auto block{CHECK_NONFATAL(miner.getTip()).value()}; + if (IsRPCRunning()) { + block = timeout ? miner.waitTipChanged(block.hash, std::chrono::milliseconds(timeout)) : miner.waitTipChanged(block.hash); } + UniValue ret(UniValue::VOBJ); ret.pushKV("hash", block.hash.GetHex()); ret.pushKV("height", block.height); @@ -296,7 +300,8 @@ static RPCHelpMan waitforblock() { return RPCHelpMan{"waitforblock", "\nWaits for a specific new block and returns useful info about it.\n" - "\nReturns the current block on timeout or exit.\n", + "\nReturns the current block on timeout or exit.\n" + "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."}, {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."}, @@ -319,15 +324,22 @@ static RPCHelpMan waitforblock() if (!request.params[1].isNull()) timeout = request.params[1].getInt<int>(); + if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout"); - CUpdatedBlock block; - { - WAIT_LOCK(cs_blockchange, lock); - if(timeout) - cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning();}); - else - cond_blockchange.wait(lock, [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning(); }); - block = latestblock; + NodeContext& node = EnsureAnyNodeContext(request.context); + Mining& miner = EnsureMining(node); + + auto block{CHECK_NONFATAL(miner.getTip()).value()}; + const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout}; + while (IsRPCRunning() && block.hash != hash) { + if (timeout) { + auto now{std::chrono::steady_clock::now()}; + if (now >= deadline) break; + const MillisecondsDouble remaining{deadline - now}; + block = miner.waitTipChanged(block.hash, remaining); + } else { + block = miner.waitTipChanged(block.hash); + } } UniValue ret(UniValue::VOBJ); @@ -343,7 +355,8 @@ static RPCHelpMan waitforblockheight() return RPCHelpMan{"waitforblockheight", "\nWaits for (at least) block height and returns the height and hash\n" "of the current tip.\n" - "\nReturns the current block on timeout or exit.\n", + "\nReturns the current block on timeout or exit.\n" + "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", { {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."}, {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."}, @@ -366,16 +379,25 @@ static RPCHelpMan waitforblockheight() if (!request.params[1].isNull()) timeout = request.params[1].getInt<int>(); + if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout"); - CUpdatedBlock block; - { - WAIT_LOCK(cs_blockchange, lock); - if(timeout) - cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning();}); - else - cond_blockchange.wait(lock, [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning(); }); - block = latestblock; + NodeContext& node = EnsureAnyNodeContext(request.context); + Mining& miner = EnsureMining(node); + + auto block{CHECK_NONFATAL(miner.getTip()).value()}; + const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout}; + + while (IsRPCRunning() && block.height < height) { + if (timeout) { + auto now{std::chrono::steady_clock::now()}; + if (now >= deadline) break; + const MillisecondsDouble remaining{deadline - now}; + block = miner.waitTipChanged(block.hash, remaining); + } else { + block = miner.waitTipChanged(block.hash); + } } + UniValue ret(UniValue::VOBJ); ret.pushKV("hash", block.hash.GetHex()); ret.pushKV("height", block.height); @@ -429,6 +451,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" @@ -576,20 +599,32 @@ static RPCHelpMan getblockheader() }; } +void CheckBlockDataAvailability(BlockManager& blockman, const CBlockIndex& blockindex, bool check_for_undo) +{ + AssertLockHeld(cs_main); + uint32_t flag = check_for_undo ? BLOCK_HAVE_UNDO : BLOCK_HAVE_DATA; + if (!(blockindex.nStatus & flag)) { + if (blockman.IsBlockPruned(blockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, strprintf("%s not available (pruned data)", check_for_undo ? "Undo data" : "Block")); + } + if (check_for_undo) { + throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available"); + } + throw JSONRPCError(RPC_MISC_ERROR, "Block not available (not fully downloaded)"); + } +} + static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex) { CBlock block; { LOCK(cs_main); - if (blockman.IsBlockPruned(blockindex)) { - throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); - } + CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false); } if (!blockman.ReadBlockFromDisk(block, blockindex)) { - // Block not found on disk. This could be because we have the block - // header in our index but not yet have the block or did not accept the - // block. Or if the block was pruned right after we released the lock above. + // Block not found on disk. This shouldn't normally happen unless the block was + // pruned right after we released the lock above. throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); } @@ -602,16 +637,13 @@ static std::vector<uint8_t> GetRawBlockChecked(BlockManager& blockman, const CBl FlatFilePos pos{}; { LOCK(cs_main); - if (blockman.IsBlockPruned(blockindex)) { - throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); - } + CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false); pos = blockindex.GetBlockPos(); } if (!blockman.ReadRawBlockFromDisk(data, pos)) { - // Block not found on disk. This could be because we have the block - // header in our index but not yet have the block or did not accept the - // block. Or if the block was pruned right after we released the lock above. + // Block not found on disk. This shouldn't normally happen unless the block was + // pruned right after we released the lock above. throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); } @@ -627,9 +659,7 @@ static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& bloc { LOCK(cs_main); - if (blockman.IsBlockPruned(blockindex)) { - throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); - } + CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/true); } if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) { @@ -652,9 +682,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() + ")"}, }}, @@ -736,14 +766,7 @@ static RPCHelpMan getblock() { uint256 hash(ParseHashV(request.params[0], "blockhash")); - int verbosity = 1; - if (!request.params[1].isNull()) { - if (request.params[1].isBool()) { - verbosity = request.params[1].get_bool() ? 1 : 0; - } else { - verbosity = request.params[1].getInt<int>(); - } - } + int verbosity{ParseVerbosity(request.params[1], /*default_verbosity=*/1)}; const CBlockIndex* pblockindex; const CBlockIndex* tip; @@ -782,6 +805,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", "", @@ -829,13 +878,12 @@ static RPCHelpMan pruneblockchain() } else if (height > chainHeight) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { - LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n"); + LogDebug(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n"); height = chainHeight - MIN_BLOCKS_TO_KEEP; } 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); }, }; } @@ -1054,9 +1102,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)"}, }}, @@ -1245,7 +1293,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"}, @@ -1295,8 +1343,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); @@ -1305,7 +1353,8 @@ RPCHelpMan getblockchaininfo() } } - obj.pushKV("warnings", GetNodeWarnings(IsDeprecatedRPCEnabled("warnings"))); + NodeContext& node = EnsureAnyNodeContext(request.context); + obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings"))); return obj; }, }; @@ -1547,6 +1596,27 @@ static RPCHelpMan preciousblock() }; } +void InvalidateBlock(ChainstateManager& chainman, const uint256 block_hash) { + BlockValidationState state; + CBlockIndex* pblockindex; + { + LOCK(chainman.GetMutex()); + pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash); + if (!pblockindex) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + } + chainman.ActiveChainstate().InvalidateBlock(state, pblockindex); + + if (state.IsValid()) { + chainman.ActiveChainstate().ActivateBestChain(state); + } + + if (!state.IsValid()) { + throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); + } +} + static RPCHelpMan invalidateblock() { return RPCHelpMan{"invalidateblock", @@ -1561,31 +1631,33 @@ static RPCHelpMan invalidateblock() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + ChainstateManager& chainman = EnsureAnyChainman(request.context); uint256 hash(ParseHashV(request.params[0], "blockhash")); - BlockValidationState state; - ChainstateManager& chainman = EnsureAnyChainman(request.context); - CBlockIndex* pblockindex; + InvalidateBlock(chainman, hash); + + return UniValue::VNULL; +}, + }; +} + +void ReconsiderBlock(ChainstateManager& chainman, uint256 block_hash) { { - LOCK(cs_main); - pblockindex = chainman.m_blockman.LookupBlockIndex(hash); + LOCK(chainman.GetMutex()); + CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - } - chainman.ActiveChainstate().InvalidateBlock(state, pblockindex); - if (state.IsValid()) { - chainman.ActiveChainstate().ActivateBestChain(state); + chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex); } + BlockValidationState state; + chainman.ActiveChainstate().ActivateBestChain(state); + if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); } - - return UniValue::VNULL; -}, - }; } static RPCHelpMan reconsiderblock() @@ -1606,22 +1678,7 @@ static RPCHelpMan reconsiderblock() ChainstateManager& chainman = EnsureAnyChainman(request.context); uint256 hash(ParseHashV(request.params[0], "blockhash")); - { - LOCK(cs_main); - CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(hash); - if (!pblockindex) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - } - - chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex); - } - - BlockValidationState state; - chainman.ActiveChainstate().ActivateBestChain(state); - - if (!state.IsValid()) { - throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); - } + ReconsiderBlock(chainman, hash); return UniValue::VNULL; }, @@ -1640,13 +1697,19 @@ static RPCHelpMan getchaintxstats() RPCResult::Type::OBJ, "", "", { {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME}, - {RPCResult::Type::NUM, "txcount", "The total number of transactions in the chain up to that point"}, + {RPCResult::Type::NUM, "txcount", /*optional=*/true, + "The total number of transactions in the chain up to that point, if known. " + "It may be unknown when using assumeutxo."}, {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"}, {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."}, {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"}, - {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true, "The number of transactions in the window. Only returned if \"window_block_count\" is > 0"}, {RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"}, - {RPCResult::Type::NUM, "txrate", /*optional=*/true, "The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0"}, + {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true, + "The number of transactions in the window. " + "Only returned if \"window_block_count\" is > 0 and if txcount exists for the start and end of the window."}, + {RPCResult::Type::NUM, "txrate", /*optional=*/true, + "The average rate of transactions per second in the window. " + "Only returned if \"window_interval\" is > 0 and if window_tx_count exists."}, }}, RPCExamples{ HelpExampleCli("getchaintxstats", "") @@ -1687,19 +1750,23 @@ static RPCHelpMan getchaintxstats() const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))}; const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()}; - const int nTxDiff = pindex->nChainTx - past_block.nChainTx; UniValue ret(UniValue::VOBJ); ret.pushKV("time", (int64_t)pindex->nTime); - ret.pushKV("txcount", (int64_t)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_tx_count", nTxDiff); ret.pushKV("window_interval", nTimeDiff); - if (nTimeDiff > 0) { - ret.pushKV("txrate", ((double)nTxDiff) / nTimeDiff); + 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); + } } } @@ -2121,14 +2188,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" @@ -2149,7 +2216,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", "", { @@ -2157,11 +2224,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}, @@ -2251,17 +2320,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)); } @@ -2596,6 +2668,42 @@ static RPCHelpMan getblockfilter() } /** + * RAII class that disables the network in its constructor and enables it in its + * destructor. + */ +class NetworkDisable +{ + CConnman& m_connman; +public: + NetworkDisable(CConnman& connman) : m_connman(connman) { + m_connman.SetNetworkActive(false); + if (m_connman.GetNetworkActive()) { + throw JSONRPCError(RPC_MISC_ERROR, "Network activity could not be suspended."); + } + }; + ~NetworkDisable() { + m_connman.SetNetworkActive(true); + }; +}; + +/** + * RAII class that temporarily rolls back the local chain in it's constructor + * and rolls it forward again in it's destructor. + */ +class TemporaryRollback +{ + ChainstateManager& m_chainman; + const CBlockIndex& m_invalidate_index; +public: + TemporaryRollback(ChainstateManager& chainman, const CBlockIndex& index) : m_chainman(chainman), m_invalidate_index(index) { + InvalidateBlock(m_chainman, m_invalidate_index.GetBlockHash()); + }; + ~TemporaryRollback() { + ReconsiderBlock(m_chainman, m_invalidate_index.GetBlockHash()); + }; +}; + +/** * Serialize the UTXO set to a file for loading elsewhere. * * @see SnapshotMetadata @@ -2604,9 +2712,20 @@ static RPCHelpMan dumptxoutset() { return RPCHelpMan{ "dumptxoutset", - "Write the serialized UTXO set to a file.", + "Write the serialized UTXO set to a file. This can be used in loadtxoutset afterwards if this snapshot height is supported in the chainparams as well.\n\n" + "Unless the the \"latest\" type is requested, the node will roll back to the requested height and network activity will be suspended during this process. " + "Because of this it is discouraged to interact with the node in any other way during the execution of this call to avoid inconsistent results and race conditions, particularly RPCs that interact with blockstorage.\n\n" + "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", { {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."}, + {"type", RPCArg::Type::STR, RPCArg::Default(""), "The type of snapshot to create. Can be \"latest\" to create a snapshot of the current UTXO set or \"rollback\" to temporarily roll back the state of the node to a historical block before creating the snapshot of a historical UTXO set. This parameter can be omitted if a separate \"rollback\" named parameter is specified indicating the height or hash of a specific historical block. If \"rollback\" is specified and separate \"rollback\" named parameter is not specified, this will roll back to the latest valid snapshot block that can currently be loaded with loadtxoutset."}, + {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", + { + {"rollback", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, + "Height or hash of the block to roll back to before creating the snapshot. Note: The further this number is from the tip, the longer this process will take. Consider setting a higher -rpcclienttimeout value in this case.", + RPCArgOptions{.skip_type_check = true, .type_str = {"", "string or numeric"}}}, + }, + }, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2620,10 +2739,33 @@ static RPCHelpMan dumptxoutset() } }, RPCExamples{ - HelpExampleCli("dumptxoutset", "utxo.dat") + HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat latest") + + HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat rollback") + + HelpExampleCli("-rpcclienttimeout=0 -named dumptxoutset", R"(utxo.dat rollback=853456)") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + NodeContext& node = EnsureAnyNodeContext(request.context); + const CBlockIndex* tip{WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Tip())}; + const CBlockIndex* target_index{nullptr}; + const std::string snapshot_type{self.Arg<std::string>("type")}; + const UniValue options{request.params[2].isNull() ? UniValue::VOBJ : request.params[2]}; + if (options.exists("rollback")) { + if (!snapshot_type.empty() && snapshot_type != "rollback") { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified with rollback option", snapshot_type)); + } + target_index = ParseHashOrHeight(options["rollback"], *node.chainman); + } else if (snapshot_type == "rollback") { + auto snapshot_heights = node.chainman->GetParams().GetAvailableSnapshotHeights(); + CHECK_NONFATAL(snapshot_heights.size() > 0); + auto max_height = std::max_element(snapshot_heights.begin(), snapshot_heights.end()); + target_index = ParseHashOrHeight(*max_height, *node.chainman); + } else if (snapshot_type == "latest") { + target_index = tip; + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified. Please specify \"rollback\" or \"latest\"", snapshot_type)); + } + const ArgsManager& args{EnsureAnyArgsman(request.context)}; const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str())); // Write to a temporary path and then move into `path` on completion @@ -2645,9 +2787,68 @@ static RPCHelpMan dumptxoutset() "Couldn't open file " + temppath.utf8string() + " for writing."); } - NodeContext& node = EnsureAnyNodeContext(request.context); - UniValue result = CreateUTXOSnapshot( - node, node.chainman->ActiveChainstate(), afile, path, temppath); + CConnman& connman = EnsureConnman(node); + const CBlockIndex* invalidate_index{nullptr}; + std::optional<NetworkDisable> disable_network; + std::optional<TemporaryRollback> temporary_rollback; + + // If the user wants to dump the txoutset of the current tip, we don't have + // to roll back at all + if (target_index != tip) { + // If the node is running in pruned mode we ensure all necessary block + // data is available before starting to roll back. + if (node.chainman->m_blockman.IsPruneMode()) { + LOCK(node.chainman->GetMutex()); + const CBlockIndex* current_tip{node.chainman->ActiveChain().Tip()}; + const CBlockIndex* first_block{node.chainman->m_blockman.GetFirstBlock(*current_tip, /*status_mask=*/BLOCK_HAVE_MASK)}; + if (first_block->nHeight > target_index->nHeight) { + throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height since necessary block data is already pruned."); + } + } + + // Suspend network activity for the duration of the process when we are + // rolling back the chain to get a utxo set from a past height. We do + // this so we don't punish peers that send us that send us data that + // seems wrong in this temporary state. For example a normal new block + // would be classified as a block connecting an invalid block. + // Skip if the network is already disabled because this + // automatically re-enables the network activity at the end of the + // process which may not be what the user wants. + if (connman.GetNetworkActive()) { + disable_network.emplace(connman); + } + + invalidate_index = WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Next(target_index)); + temporary_rollback.emplace(*node.chainman, *invalidate_index); + } + + Chainstate* chainstate; + std::unique_ptr<CCoinsViewCursor> cursor; + CCoinsStats stats; + { + // Lock the chainstate before calling PrepareUtxoSnapshot, to be able + // to get a UTXO database cursor while the chain is pointing at the + // target block. After that, release the lock while calling + // WriteUTXOSnapshot. The cursor will remain valid and be used by + // WriteUTXOSnapshot to write a consistent snapshot even if the + // chainstate changes. + LOCK(node.chainman->GetMutex()); + chainstate = &node.chainman->ActiveChainstate(); + // In case there is any issue with a block being read from disk we need + // to stop here, otherwise the dump could still be created for the wrong + // height. + // The new tip could also not be the target block if we have a stale + // sister block of invalidate_index. This block (or a descendant) would + // be activated as the new tip and we would not get to new_tip_index. + if (target_index != chainstate->m_chain.Tip()) { + LogWarning("dumptxoutset failed to roll back to requested height, reverting to tip.\n"); + throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height."); + } else { + std::tie(cursor, stats, tip) = PrepareUTXOSnapshot(*chainstate, node.rpc_interruption_point); + } + } + + UniValue result = WriteUTXOSnapshot(*chainstate, cursor.get(), &stats, tip, afile, path, temppath, node.rpc_interruption_point); fs::rename(temppath, path); result.pushKV("path", path.utf8string()); @@ -2656,12 +2857,10 @@ static RPCHelpMan dumptxoutset() }; } -UniValue CreateUTXOSnapshot( - NodeContext& node, +std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*> +PrepareUTXOSnapshot( Chainstate& chainstate, - AutoFile& afile, - const fs::path& path, - const fs::path& temppath) + const std::function<void()>& interruption_point) { std::unique_ptr<CCoinsViewCursor> pcursor; std::optional<CCoinsStats> maybe_stats; @@ -2671,7 +2870,7 @@ UniValue CreateUTXOSnapshot( // We need to lock cs_main to ensure that the coinsdb isn't written to // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats // based upon the coinsdb, and (iii) constructing a cursor to the - // coinsdb for use below this block. + // coinsdb for use in WriteUTXOSnapshot. // // Cursors returned by leveldb iterate over snapshots, so the contents // of the pcursor will not be affected by simultaneous writes during @@ -2680,11 +2879,11 @@ UniValue CreateUTXOSnapshot( // See discussion here: // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369 // - LOCK(::cs_main); + AssertLockHeld(::cs_main); chainstate.ForceFlushStateToDisk(); - maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, node.rpc_interruption_point); + maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, interruption_point); if (!maybe_stats) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); } @@ -2693,11 +2892,24 @@ UniValue CreateUTXOSnapshot( tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock)); } + return {std::move(pcursor), *CHECK_NONFATAL(maybe_stats), tip}; +} + +UniValue WriteUTXOSnapshot( + Chainstate& chainstate, + CCoinsViewCursor* pcursor, + CCoinsStats* maybe_stats, + const CBlockIndex* tip, + AutoFile& afile, + const fs::path& path, + const fs::path& temppath, + const std::function<void()>& interruption_point) +{ LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)", 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; @@ -2728,7 +2940,7 @@ UniValue CreateUTXOSnapshot( pcursor->GetKey(key); last_hash = key.hash; while (pcursor->Valid()) { - if (iter % 5000 == 0) node.rpc_interruption_point(); + if (iter % 5000 == 0) interruption_point(); ++iter; if (pcursor->GetKey(key) && pcursor->GetValue(coin)) { if (key.hash != last_hash) { @@ -2755,10 +2967,21 @@ 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; } +UniValue CreateUTXOSnapshot( + node::NodeContext& node, + Chainstate& chainstate, + AutoFile& afile, + const fs::path& path, + const fs::path& tmppath) +{ + auto [cursor, stats, tip]{WITH_LOCK(::cs_main, return PrepareUTXOSnapshot(chainstate, node.rpc_interruption_point))}; + return WriteUTXOSnapshot(chainstate, cursor.get(), &stats, tip, afile, path, tmppath, node.rpc_interruption_point); +} + static RPCHelpMan loadtxoutset() { return RPCHelpMan{ @@ -2793,13 +3016,13 @@ static RPCHelpMan loadtxoutset() } }, RPCExamples{ - HelpExampleCli("loadtxoutset", "utxo.dat") + HelpExampleCli("-rpcclienttimeout=0 loadtxoutset", "utxo.dat") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { 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}; @@ -2816,34 +3039,24 @@ static RPCHelpMan loadtxoutset() throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Unable to parse metadata: %s", e.what())); } - uint256 base_blockhash = metadata.m_base_blockhash; - int base_blockheight = metadata.m_base_blockheight; - if (!chainman.GetParams().AssumeutxoForBlockhash(base_blockhash).has_value()) { - auto available_heights = chainman.GetParams().GetAvailableSnapshotHeights(); - std::string heights_formatted = Join(available_heights, ", ", [&](const auto& i) { return ToString(i); }); - throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot, " - "assumeutxo block hash in snapshot metadata not recognized (hash: %s, height: %s). The following snapshot heights are available: %s.", - base_blockhash.ToString(), - base_blockheight, - heights_formatted)); + auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)}; + if (!activation_result) { + throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot: %s. (%s)", util::ErrorString(activation_result).original, path.utf8string())); } - CBlockIndex* snapshot_start_block = WITH_LOCK(::cs_main, - return chainman.m_blockman.LookupBlockIndex(base_blockhash)); - if (!snapshot_start_block) { - throw JSONRPCError( - RPC_INTERNAL_ERROR, - strprintf("The base block header (%s) must appear in the headers chain. Make sure all headers are syncing, and call this RPC again.", - base_blockhash.ToString())); - } - if (!chainman.ActivateSnapshot(afile, metadata, false)) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to load UTXO snapshot " + fs::PathToString(path)); - } + // Because we can't provide historical blocks during tip or background sync. + // Update local services to reflect we are a limited peer until we are fully sync. + node.connman->RemoveLocalServices(NODE_NETWORK); + // Setting the limited state is usually redundant because the node can always + // provide the last 288 blocks, but it doesn't hurt to set it. + node.connman->AddLocalServices(NODE_NETWORK_LIMITED); + + CBlockIndex& snapshot_index{*CHECK_NONFATAL(*activation_result)}; UniValue result(UniValue::VOBJ); result.pushKV("coins_loaded", metadata.m_coins_count); - result.pushKV("tip_hash", snapshot_start_block->GetBlockHash().ToString()); - result.pushKV("base_height", snapshot_start_block->nHeight); + 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..89b9921d55 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 @@ -34,9 +35,6 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; */ double GetDifficulty(const CBlockIndex& blockindex); -/** Callback for when block tip changed. */ -void RPCNotifyBlockChange(const CBlockIndex*); - /** Block description to JSON */ UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main); @@ -47,7 +45,7 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight); /** - * Helper to create UTXO snapshots given a chainstate and a file handle. + * Test-only helper to create UTXO snapshots given a chainstate and a file handle. * @return a UniValue map containing metadata about the snapshot. */ UniValue CreateUTXOSnapshot( @@ -57,4 +55,8 @@ 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); +void CheckBlockDataAvailability(node::BlockManager& blockman, const CBlockIndex& blockindex, bool check_for_undo) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + #endif // BITCOIN_RPC_BLOCKCHAIN_H diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 7dfe69a6c5..601e4fa7bf 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" }, @@ -185,6 +187,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "gettxoutproof", 0, "txids" }, { "gettxoutsetinfo", 1, "hash_or_height" }, { "gettxoutsetinfo", 2, "use_index"}, + { "dumptxoutset", 2, "options" }, + { "dumptxoutset", 2, "rollback" }, { "lockunspent", 0, "unlock" }, { "lockunspent", 1, "transactions" }, { "lockunspent", 2, "persistent" }, @@ -208,6 +212,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"}, @@ -249,6 +254,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "keypoolrefill", 0, "newsize" }, { "getrawmempool", 0, "verbose" }, { "getrawmempool", 1, "mempool_sequence" }, + { "getorphantxs", 0, "verbosity" }, + { "getorphantxs", 0, "verbose" }, { "estimatesmartfee", 0, "conf_target" }, { "estimaterawfee", 0, "conf_target" }, { "estimaterawfee", 1, "threshold" }, diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp index 3ad7a940e0..44de5443fa 100644 --- a/src/rpc/external_signer.cpp +++ b/src/rpc/external_signer.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <common/args.h> #include <common/system.h> diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp index a7cec96746..10caa9ed2e 100644 --- a/src/rpc/fees.cpp +++ b/src/rpc/fees.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/messages.h> #include <core_io.h> #include <node/context.h> #include <policy/feerate.h> @@ -14,7 +15,6 @@ #include <rpc/util.h> #include <txmempool.h> #include <univalue.h> -#include <util/fees.h> #include <validationinterface.h> #include <algorithm> @@ -22,6 +22,9 @@ #include <cmath> #include <string> +using common::FeeModeFromString; +using common::FeeModesDetail; +using common::InvalidEstimateModeErrorMessage; using node::NodeContext; static RPCHelpMan estimatesmartfee() @@ -33,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, "", "", @@ -68,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 4a0e96fd75..27a00c5d91 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -5,12 +5,15 @@ #include <rpc/blockchain.h> -#include <kernel/mempool_persist.h> +#include <node/mempool_persist.h> #include <chainparams.h> +#include <consensus/validation.h> #include <core_io.h> #include <kernel/mempool_entry.h> +#include <net_processing.h> #include <node/mempool_persist_args.h> +#include <node/types.h> #include <policy/rbf.h> #include <policy/settings.h> #include <primitives/transaction.h> @@ -23,15 +26,18 @@ #include <util/moneystr.h> #include <util/strencodings.h> #include <util/time.h> +#include <util/vector.h> #include <utility> -using kernel::DumpMempool; +using node::DumpMempool; using node::DEFAULT_MAX_BURN_AMOUNT; using node::DEFAULT_MAX_RAW_TX_FEE_RATE; using node::MempoolPath; using node::NodeContext; +using node::TransactionError; +using util::ToString; static RPCHelpMan sendrawtransaction() { @@ -40,7 +46,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"}, @@ -756,13 +762,13 @@ static RPCHelpMan importmempool() const UniValue& use_current_time{request.params[1]["use_current_time"]}; const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]}; const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]}; - kernel::ImportMempoolOptions opts{ + node::ImportMempoolOptions opts{ .use_current_time = use_current_time.isNull() ? true : use_current_time.get_bool(), .apply_fee_delta_priority = apply_fee_delta.isNull() ? false : apply_fee_delta.get_bool(), .apply_unbroadcast_set = apply_unbroadcast.isNull() ? false : apply_unbroadcast.get_bool(), }; - if (!kernel::LoadMempool(mempool, load_path, chainstate, std::move(opts))) { + if (!node::LoadMempool(mempool, load_path, chainstate, std::move(opts))) { throw JSONRPCError(RPC_MISC_ERROR, "Unable to import mempool file, see debug.log for details."); } @@ -809,6 +815,104 @@ static RPCHelpMan savemempool() }; } +static std::vector<RPCResult> OrphanDescription() +{ + return { + RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, + RPCResult{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"}, + RPCResult{RPCResult::Type::NUM, "bytes", "The serialized transaction size in bytes"}, + RPCResult{RPCResult::Type::NUM, "vsize", "The virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."}, + RPCResult{RPCResult::Type::NUM, "weight", "The transaction weight as defined in BIP 141."}, + RPCResult{RPCResult::Type::NUM_TIME, "expiration", "The orphan expiration time expressed in " + UNIX_EPOCH_TIME}, + RPCResult{RPCResult::Type::ARR, "from", "", + { + RPCResult{RPCResult::Type::NUM, "peer_id", "Peer ID"}, + }}, + }; +} + +static UniValue OrphanToJSON(const TxOrphanage::OrphanTxBase& orphan) +{ + UniValue o(UniValue::VOBJ); + o.pushKV("txid", orphan.tx->GetHash().ToString()); + o.pushKV("wtxid", orphan.tx->GetWitnessHash().ToString()); + o.pushKV("bytes", orphan.tx->GetTotalSize()); + o.pushKV("vsize", GetVirtualTransactionSize(*orphan.tx)); + o.pushKV("weight", GetTransactionWeight(*orphan.tx)); + o.pushKV("expiration", int64_t{TicksSinceEpoch<std::chrono::seconds>(orphan.nTimeExpire)}); + UniValue from(UniValue::VARR); + from.push_back(orphan.fromPeer); // only one fromPeer for now + o.pushKV("from", from); + return o; +} + +static RPCHelpMan getorphantxs() +{ + return RPCHelpMan{"getorphantxs", + "\nShows transactions in the tx orphanage.\n" + "\nEXPERIMENTAL warning: this call may be changed in future releases.\n", + { + {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{0}, "0 for an array of txids (may contain duplicates), 1 for an array of objects with tx details, and 2 for details from (1) and tx hex", + RPCArgOptions{.skip_type_check = true}}, + }, + { + RPCResult{"for verbose = 0", + RPCResult::Type::ARR, "", "", + { + {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, + }}, + RPCResult{"for verbose = 1", + RPCResult::Type::ARR, "", "", + { + {RPCResult::Type::OBJ, "", "", OrphanDescription()}, + }}, + RPCResult{"for verbose = 2", + RPCResult::Type::ARR, "", "", + { + {RPCResult::Type::OBJ, "", "", + Cat<std::vector<RPCResult>>( + OrphanDescription(), + {{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"}} + ) + }, + }}, + }, + RPCExamples{ + HelpExampleCli("getorphantxs", "2") + + HelpExampleRpc("getorphantxs", "2") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { + const NodeContext& node = EnsureAnyNodeContext(request.context); + PeerManager& peerman = EnsurePeerman(node); + std::vector<TxOrphanage::OrphanTxBase> orphanage = peerman.GetOrphanTransactions(); + + int verbosity{ParseVerbosity(request.params[0], /*default_verbosity=*/0)}; + + UniValue ret(UniValue::VARR); + + if (verbosity <= 0) { + for (auto const& orphan : orphanage) { + ret.push_back(orphan.tx->GetHash().ToString()); + } + } else if (verbosity == 1) { + for (auto const& orphan : orphanage) { + ret.push_back(OrphanToJSON(orphan)); + } + } else { + // >= 2 + for (auto const& orphan : orphanage) { + UniValue o{OrphanToJSON(orphan)}; + o.pushKV("hex", EncodeHexTx(*orphan.tx)); + ret.push_back(o); + } + } + + return ret; + }, + }; +} + static RPCHelpMan submitpackage() { return RPCHelpMan{"submitpackage", @@ -1024,6 +1128,7 @@ void RegisterMempoolRPCCommands(CRPCTable& t) {"blockchain", &getrawmempool}, {"blockchain", &importmempool}, {"blockchain", &savemempool}, + {"hidden", &getorphantxs}, {"rawtransactions", &submitpackage}, }; for (const auto& c : commands) { diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 63daa3da3a..44605cbc89 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -3,10 +3,11 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chain.h> #include <chainparams.h> +#include <chainparamsbase.h> #include <common/system.h> #include <consensus/amount.h> #include <consensus/consensus.h> @@ -16,10 +17,12 @@ #include <core_io.h> #include <deploymentinfo.h> #include <deploymentstatus.h> +#include <interfaces/mining.h> #include <key_io.h> #include <net.h> #include <node/context.h> #include <node/miner.h> +#include <node/warnings.h> #include <pow.h> #include <rpc/blockchain.h> #include <rpc/mining.h> @@ -42,11 +45,13 @@ #include <memory> #include <stdint.h> +using interfaces::BlockTemplate; +using interfaces::Mining; using node::BlockAssembler; -using node::CBlockTemplate; using node::NodeContext; using node::RegenerateCommitments; using node::UpdateTime; +using util::ToString; /** * Return average network hashes per second based on the last 'lookup' blocks, @@ -125,7 +130,7 @@ static RPCHelpMan getnetworkhashps() }; } -static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block) +static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block) { block_out.reset(); block.hashMerkleRoot = BlockMerkleRoot(block); @@ -141,27 +146,26 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& return true; } - block_out = std::make_shared<const CBlock>(block); + block_out = std::make_shared<const CBlock>(std::move(block)); if (!process_new_block) return true; - if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) { + if (!miner.processNewBlock(block_out, nullptr)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); } return true; } -static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries) +static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries) { UniValue blockHashes(UniValue::VARR); while (nGenerate > 0 && !chainman.m_interrupt) { - std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler{chainman.ActiveChainstate(), &mempool}.CreateNewBlock(coinbase_script)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); + std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock(coinbase_script)); + CHECK_NONFATAL(block_template); std::shared_ptr<const CBlock> block_out; - if (!GenerateBlock(chainman, pblocktemplate->block, nMaxTries, block_out, /*process_new_block=*/true)) { + if (!GenerateBlock(chainman, miner, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) { break; } @@ -176,35 +180,36 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me static bool getScriptFromDescriptor(const std::string& descriptor, CScript& script, std::string& error) { FlatSigningProvider key_provider; - const auto desc = Parse(descriptor, key_provider, error, /* require_checksum = */ false); - if (desc) { - if (desc->IsRange()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?"); - } - - FlatSigningProvider provider; - std::vector<CScript> scripts; - if (!desc->Expand(0, key_provider, scripts, provider)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys"); - } + const auto descs = Parse(descriptor, key_provider, error, /* require_checksum = */ false); + if (descs.empty()) return false; + if (descs.size() > 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Multipath descriptor not accepted"); + } + const auto& desc = descs.at(0); + if (desc->IsRange()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?"); + } - // Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1 - CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4); + FlatSigningProvider provider; + std::vector<CScript> scripts; + if (!desc->Expand(0, key_provider, scripts, provider)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys"); + } - if (scripts.size() == 1) { - script = scripts.at(0); - } else if (scripts.size() == 4) { - // For uncompressed keys, take the 3rd script, since it is p2wpkh - script = scripts.at(2); - } else { - // Else take the 2nd script, since it is p2pkh - script = scripts.at(1); - } + // Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1 + CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4); - return true; + if (scripts.size() == 1) { + script = scripts.at(0); + } else if (scripts.size() == 4) { + // For uncompressed keys, take the 3rd script, since it is p2wpkh + script = scripts.at(2); } else { - return false; + // Else take the 2nd script, since it is p2pkh + script = scripts.at(1); } + + return true; } static RPCHelpMan generatetodescriptor() @@ -237,10 +242,10 @@ static RPCHelpMan generatetodescriptor() } NodeContext& node = EnsureAnyNodeContext(request.context); - const CTxMemPool& mempool = EnsureMemPool(node); + Mining& miner = EnsureMining(node); ChainstateManager& chainman = EnsureChainman(node); - return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries); + return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries); }, }; } @@ -283,12 +288,12 @@ static RPCHelpMan generatetoaddress() } NodeContext& node = EnsureAnyNodeContext(request.context); - const CTxMemPool& mempool = EnsureMemPool(node); + Mining& miner = EnsureMining(node); ChainstateManager& chainman = EnsureChainman(node); CScript coinbase_script = GetScriptForDestination(destination); - return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries); + return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries); }, }; } @@ -335,18 +340,17 @@ static RPCHelpMan generateblock() } NodeContext& node = EnsureAnyNodeContext(request.context); + Mining& miner = EnsureMining(node); const CTxMemPool& mempool = EnsureMemPool(node); 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)); } @@ -366,13 +370,10 @@ static RPCHelpMan generateblock() ChainstateManager& chainman = EnsureChainman(node); { - LOCK(cs_main); + std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock(coinbase_script, {.use_mempool = false})}; + CHECK_NONFATAL(block_template); - std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler{chainman.ActiveChainstate(), nullptr}.CreateNewBlock(coinbase_script)); - if (!blocktemplate) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); - } - block = blocktemplate->block; + block = block_template->getBlock(); } CHECK_NONFATAL(block.vtx.size() == 1); @@ -382,18 +383,16 @@ static RPCHelpMan generateblock() RegenerateCommitments(block, chainman); { - LOCK(cs_main); - BlockValidationState state; - if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) { - throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString())); + if (!miner.testBlockValidity(block, /*check_merkle_root=*/false, state)) { + throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("testBlockValidity failed: %s", state.ToString())); } } std::shared_ptr<const CBlock> block_out; uint64_t max_tries{DEFAULT_MAX_TRIES}; - if (!GenerateBlock(chainman, block, max_tries, block_out, process_new_block) || !block_out) { + if (!GenerateBlock(chainman, miner, std::move(block), max_tries, block_out, process_new_block) || !block_out) { throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block."); } @@ -423,7 +422,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)", @@ -453,7 +452,7 @@ static RPCHelpMan getmininginfo() obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request)); obj.pushKV("pooledtx", (uint64_t)mempool.size()); obj.pushKV("chain", chainman.GetParams().GetChainTypeString()); - obj.pushKV("warnings", GetNodeWarnings(IsDeprecatedRPCEnabled("warnings"))); + obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings"))); return obj; }, }; @@ -660,13 +659,13 @@ static RPCHelpMan getblocktemplate() { NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); + Mining& miner = EnsureMining(node); LOCK(cs_main); + uint256 tip{CHECK_NONFATAL(miner.getTip()).value().hash}; std::string strMode = "template"; UniValue lpval = NullUniValue; std::set<std::string> setClientRules; - Chainstate& active_chainstate = chainman.ActiveChainstate(); - CChain& active_chain = active_chainstate.m_chain; if (!request.params[0].isNull()) { const UniValue& oparam = request.params[0].get_obj(); @@ -701,12 +700,12 @@ static RPCHelpMan getblocktemplate() return "duplicate-inconclusive"; } - CBlockIndex* const pindexPrev = active_chain.Tip(); - // TestBlockValidity only supports blocks built on the current Tip - if (block.hashPrevBlock != pindexPrev->GetBlockHash()) + // testBlockValidity only supports blocks built on the current Tip + if (block.hashPrevBlock != tip) { return "inconclusive-not-best-prevblk"; + } BlockValidationState state; - TestBlockValidity(state, chainman.GetParams(), active_chainstate, block, pindexPrev, false, true); + miner.testBlockValidity(block, /*check_merkle_root=*/true, state); return BIP22ValidationResult(state); } @@ -722,25 +721,23 @@ static RPCHelpMan getblocktemplate() if (strMode != "template") throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - if (!chainman.GetParams().IsTestChain()) { + if (!miner.isTestChain()) { const CConnman& connman = EnsureConnman(node); if (connman.GetNodeCount(ConnectionDirection::Both) == 0) { throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!"); } - if (chainman.IsInitialBlockDownload()) { + if (miner.isInitialBlockDownload()) { throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); } } static unsigned int nTransactionsUpdatedLast; - const CTxMemPool& mempool = EnsureMemPool(node); if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; - std::chrono::steady_clock::time_point checktxtime; unsigned int nTransactionsUpdatedLastLP; if (lpval.isStr()) @@ -754,30 +751,27 @@ static RPCHelpMan getblocktemplate() else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier - hashWatchedChain = active_chain.Tip()->GetBlockHash(); + hashWatchedChain = tip; nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } // Release lock while waiting LEAVE_CRITICAL_SECTION(cs_main); { - checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - - WAIT_LOCK(g_best_block_mutex, lock); - while (g_best_block == hashWatchedChain && IsRPCRunning()) - { - if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) - { - // Timeout: Check transactions for update - // without holding the mempool lock to avoid deadlocks - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) - break; - checktxtime += std::chrono::seconds(10); - } + MillisecondsDouble checktxtime{std::chrono::minutes(1)}; + while (tip == hashWatchedChain && IsRPCRunning()) { + tip = miner.waitTipChanged(hashWatchedChain, checktxtime).hash; + // Timeout: Check transactions for update + // without holding the mempool lock to avoid deadlocks + if (miner.getTransactionsUpdated() != nTransactionsUpdatedLastLP) + break; + checktxtime = std::chrono::seconds(10); } } ENTER_CRITICAL_SECTION(cs_main); + tip = CHECK_NONFATAL(miner.getTip()).value().hash; + if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? @@ -798,33 +792,33 @@ static RPCHelpMan getblocktemplate() // Update block static CBlockIndex* pindexPrev; static int64_t time_start; - static std::unique_ptr<CBlockTemplate> pblocktemplate; - if (pindexPrev != active_chain.Tip() || - (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5)) + static std::unique_ptr<BlockTemplate> block_template; + if (!pindexPrev || pindexPrev->GetBlockHash() != tip || + (miner.getTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on pindexPrev = nullptr; - // Store the pindexBest used before CreateNewBlock, to avoid races - nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = active_chain.Tip(); + // Store the pindexBest used before createNewBlock, to avoid races + nTransactionsUpdatedLast = miner.getTransactionsUpdated(); + CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(tip); time_start = GetTime(); // Create new block CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = BlockAssembler{active_chainstate, &mempool}.CreateNewBlock(scriptDummy); - if (!pblocktemplate) - throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + block_template = miner.createNewBlock(scriptDummy); + CHECK_NONFATAL(block_template); + - // Need to update only after we know CreateNewBlock succeeded + // Need to update only after we know createNewBlock succeeded pindexPrev = pindexPrevNew; } CHECK_NONFATAL(pindexPrev); - CBlock* pblock = &pblocktemplate->block; // pointer for convenience + CBlock block{block_template->getBlock()}; // Update nTime - UpdateTime(pblock, consensusParams, pindexPrev); - pblock->nNonce = 0; + UpdateTime(&block, consensusParams, pindexPrev); + block.nNonce = 0; // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration const bool fPreSegWit = !DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_SEGWIT); @@ -833,8 +827,11 @@ static RPCHelpMan getblocktemplate() UniValue transactions(UniValue::VARR); std::map<uint256, int64_t> setTxIndex; + std::vector<CAmount> tx_fees{block_template->getTxFees()}; + std::vector<CAmount> tx_sigops{block_template->getTxSigops()}; + int i = 0; - for (const auto& it : pblock->vtx) { + for (const auto& it : block.vtx) { const CTransaction& tx = *it; uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; @@ -857,8 +854,8 @@ static RPCHelpMan getblocktemplate() entry.pushKV("depends", std::move(deps)); int index_in_template = i - 1; - entry.pushKV("fee", pblocktemplate->vTxFees[index_in_template]); - int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template]; + entry.pushKV("fee", tx_fees.at(index_in_template)); + int64_t nTxSigOps{tx_sigops.at(index_in_template)}; if (fPreSegWit) { CHECK_NONFATAL(nTxSigOps % WITNESS_SCALE_FACTOR == 0); nTxSigOps /= WITNESS_SCALE_FACTOR; @@ -871,7 +868,7 @@ static RPCHelpMan getblocktemplate() UniValue aux(UniValue::VOBJ); - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + arith_uint256 hashTarget = arith_uint256().SetCompact(block.nBits); UniValue aMutable(UniValue::VARR); aMutable.push_back("time"); @@ -901,7 +898,7 @@ static RPCHelpMan getblocktemplate() break; case ThresholdState::LOCKED_IN: // Ensure bit is set in block version - pblock->nVersion |= chainman.m_versionbitscache.Mask(consensusParams, pos); + block.nVersion |= chainman.m_versionbitscache.Mask(consensusParams, pos); [[fallthrough]]; case ThresholdState::STARTED: { @@ -910,7 +907,7 @@ static RPCHelpMan getblocktemplate() if (setClientRules.find(vbinfo.name) == setClientRules.end()) { if (!vbinfo.gbt_force) { // If the client doesn't support this, don't indicate it in the [default] version - pblock->nVersion &= ~chainman.m_versionbitscache.Mask(consensusParams, pos); + block.nVersion &= ~chainman.m_versionbitscache.Mask(consensusParams, pos); } } break; @@ -930,16 +927,16 @@ static RPCHelpMan getblocktemplate() } } } - result.pushKV("version", pblock->nVersion); + result.pushKV("version", block.nVersion); result.pushKV("rules", std::move(aRules)); result.pushKV("vbavailable", std::move(vbavailable)); result.pushKV("vbrequired", int(0)); - result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex()); + result.pushKV("previousblockhash", block.hashPrevBlock.GetHex()); result.pushKV("transactions", std::move(transactions)); result.pushKV("coinbaseaux", std::move(aux)); - result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue); - result.pushKV("longpollid", active_chain.Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast)); + result.pushKV("coinbasevalue", (int64_t)block.vtx[0]->vout[0].nValue); + result.pushKV("longpollid", tip.GetHex() + ToString(nTransactionsUpdatedLast)); result.pushKV("target", hashTarget.GetHex()); result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1); result.pushKV("mutable", std::move(aMutable)); @@ -957,16 +954,16 @@ static RPCHelpMan getblocktemplate() if (!fPreSegWit) { result.pushKV("weightlimit", (int64_t)MAX_BLOCK_WEIGHT); } - result.pushKV("curtime", pblock->GetBlockTime()); - result.pushKV("bits", strprintf("%08x", pblock->nBits)); + result.pushKV("curtime", block.GetBlockTime()); + result.pushKV("bits", strprintf("%08x", block.nBits)); result.pushKV("height", (int64_t)(pindexPrev->nHeight+1)); if (consensusParams.signet_blocks) { result.pushKV("signet_challenge", HexStr(consensusParams.signet_challenge)); } - if (!pblocktemplate->vchCoinbaseCommitment.empty()) { - result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment)); + if (!block_template->getCoinbaseCommitment().empty()) { + result.pushKV("default_witness_commitment", HexStr(block_template->getCoinbaseCommitment())); } return result; @@ -1045,10 +1042,13 @@ static RPCHelpMan submitblock() } } + NodeContext& node = EnsureAnyNodeContext(request.context); + Mining& miner = EnsureMining(node); + bool new_block; auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash()); CHECK_NONFATAL(chainman.m_options.signals)->RegisterSharedValidationInterface(sc); - bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block); + bool accepted = miner.processNewBlock(blockptr, /*new_block=*/&new_block); CHECK_NONFATAL(chainman.m_options.signals)->UnregisterSharedValidationInterface(sc); if (!new_block && accepted) { return "duplicate"; @@ -1090,7 +1090,7 @@ static RPCHelpMan submitheader() } BlockValidationState state; - chainman.ProcessNewBlockHeaders({h}, /*min_pow_checked=*/true, state); + chainman.ProcessNewBlockHeaders({{h}}, /*min_pow_checked=*/true, state); if (state.IsValid()) return UniValue::VNULL; if (state.IsError()) { throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString()); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 034dbdc914..5398685074 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -16,6 +16,7 @@ #include <netbase.h> #include <node/context.h> #include <node/protocol_version.h> +#include <node/warnings.h> #include <policy/settings.h> #include <protocol.h> #include <rpc/blockchain.h> @@ -35,6 +36,8 @@ #include <univalue.h> using node::NodeContext; +using util::Join; +using util::TrimString; const std::vector<std::string> CONNECTION_TYPE_DOC{ "outbound-full-relay (default automatic connections)", @@ -126,8 +129,8 @@ static RPCHelpMan getpeerinfo() {RPCResult::Type::STR, "addrbind", /*optional=*/true, "(ip:port) Bind address of the connection to the peer"}, {RPCResult::Type::STR, "addrlocal", /*optional=*/true, "(ip:port) Local address as reported by the peer"}, {RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/*append_unroutable=*/true), ", ") + ")"}, - {RPCResult::Type::NUM, "mapped_as", /*optional=*/true, "The AS in the BGP route to the peer used for diversifying\n" - "peer selection (only available if the asmap config flag is set)"}, + {RPCResult::Type::NUM, "mapped_as", /*optional=*/true, "Mapped AS (Autonomous System) number at the end of the BGP route to the peer, used for diversifying\n" + "peer selection (only displayed if the -asmap config option is set)"}, {RPCResult::Type::STR_HEX, "services", "The services offered"}, {RPCResult::Type::ARR, "servicesnames", "the services offered, in human-readable form", { @@ -713,7 +716,7 @@ static RPCHelpMan getnetworkinfo() } } obj.pushKV("localaddresses", std::move(localAddresses)); - obj.pushKV("warnings", GetNodeWarnings(IsDeprecatedRPCEnabled("warnings"))); + obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings"))); return obj; }, }; @@ -1099,12 +1102,12 @@ static RPCHelpMan getaddrmaninfo() }; } -UniValue AddrmanEntryToJSON(const AddrInfo& info, CConnman& connman) +UniValue AddrmanEntryToJSON(const AddrInfo& info, const CConnman& connman) { UniValue ret(UniValue::VOBJ); ret.pushKV("address", info.ToStringAddr()); - const auto mapped_as{connman.GetMappedAS(info)}; - if (mapped_as != 0) { + const uint32_t mapped_as{connman.GetMappedAS(info)}; + if (mapped_as) { ret.pushKV("mapped_as", mapped_as); } ret.pushKV("port", info.GetPort()); @@ -1113,14 +1116,14 @@ UniValue AddrmanEntryToJSON(const AddrInfo& info, CConnman& connman) ret.pushKV("network", GetNetworkName(info.GetNetClass())); ret.pushKV("source", info.source.ToStringAddr()); ret.pushKV("source_network", GetNetworkName(info.source.GetNetClass())); - const auto source_mapped_as{connman.GetMappedAS(info.source)}; - if (source_mapped_as != 0) { + const uint32_t source_mapped_as{connman.GetMappedAS(info.source)}; + if (source_mapped_as) { ret.pushKV("source_mapped_as", source_mapped_as); } return ret; } -UniValue AddrmanTableToJSON(const std::vector<std::pair<AddrInfo, AddressPosition>>& tableInfos, CConnman& connman) +UniValue AddrmanTableToJSON(const std::vector<std::pair<AddrInfo, AddressPosition>>& tableInfos, const CConnman& connman) { UniValue table(UniValue::VOBJ); for (const auto& e : tableInfos) { @@ -1147,14 +1150,14 @@ static RPCHelpMan getrawaddrman() {RPCResult::Type::OBJ_DYN, "table", "buckets with addresses in the address manager table ( new, tried )", { {RPCResult::Type::OBJ, "bucket/position", "the location in the address manager table (<bucket>/<position>)", { {RPCResult::Type::STR, "address", "The address of the node"}, - {RPCResult::Type::NUM, "mapped_as", /*optional=*/true, "The ASN mapped to the IP of this peer per our current ASMap"}, + {RPCResult::Type::NUM, "mapped_as", /*optional=*/true, "Mapped AS (Autonomous System) number at the end of the BGP route to the peer, used for diversifying peer selection (only displayed if the -asmap config option is set)"}, {RPCResult::Type::NUM, "port", "The port number of the node"}, {RPCResult::Type::STR, "network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the address"}, {RPCResult::Type::NUM, "services", "The services offered by the node"}, {RPCResult::Type::NUM_TIME, "time", "The " + UNIX_EPOCH_TIME + " when the node was last seen"}, {RPCResult::Type::STR, "source", "The address that relayed the address to us"}, {RPCResult::Type::STR, "source_network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the source address"}, - {RPCResult::Type::NUM, "source_mapped_as", /*optional=*/true, "The ASN mapped to the IP of this peer's source per our current ASMap"} + {RPCResult::Type::NUM, "source_mapped_as", /*optional=*/true, "Mapped AS (Autonomous System) number at the end of the BGP route to the source, used for diversifying peer selection (only displayed if the -asmap config option is set)"} }} }} } diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index 65b0a93cdd..5e36273cf4 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chainparams.h> #include <httpserver.h> @@ -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", @@ -245,15 +244,15 @@ static RPCHelpMan logging() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - uint32_t original_log_categories = LogInstance().GetCategoryMask(); + BCLog::CategoryMask original_log_categories = LogInstance().GetCategoryMask(); if (request.params[0].isArray()) { EnableOrDisableLogCategories(request.params[0], true); } if (request.params[1].isArray()) { EnableOrDisableLogCategories(request.params[1], false); } - uint32_t updated_log_categories = LogInstance().GetCategoryMask(); - uint32_t changed_log_categories = original_log_categories ^ updated_log_categories; + BCLog::CategoryMask updated_log_categories = LogInstance().GetCategoryMask(); + BCLog::CategoryMask changed_log_categories = original_log_categories ^ updated_log_categories; // Update libevent logging if BCLog::LIBEVENT has changed. if (changed_log_categories & BCLog::LIBEVENT) { diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp index 65a9be2762..49f3a81243 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"}, @@ -175,7 +175,11 @@ static RPCHelpMan getdescriptorinfo() RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys"}, + {RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys. For a multipath descriptor, only the first will be returned."}, + {RPCResult::Type::ARR, "multipath_expansion", /*optional=*/true, "All descriptors produced by expanding multipath derivation elements. Only if the provided descriptor specifies multipath derivation elements.", + { + {RPCResult::Type::STR, "", ""}, + }}, {RPCResult::Type::STR, "checksum", "The checksum for the input descriptor"}, {RPCResult::Type::BOOL, "isrange", "Whether the descriptor is ranged"}, {RPCResult::Type::BOOL, "issolvable", "Whether the descriptor is solvable"}, @@ -191,22 +195,65 @@ static RPCHelpMan getdescriptorinfo() { FlatSigningProvider provider; std::string error; - auto desc = Parse(request.params[0].get_str(), provider, error); - if (!desc) { + auto descs = Parse(request.params[0].get_str(), provider, error); + if (descs.empty()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } UniValue result(UniValue::VOBJ); - result.pushKV("descriptor", desc->ToString()); + result.pushKV("descriptor", descs.at(0)->ToString()); + + if (descs.size() > 1) { + UniValue multipath_descs(UniValue::VARR); + for (const auto& d : descs) { + multipath_descs.push_back(d->ToString()); + } + result.pushKV("multipath_expansion", multipath_descs); + } + result.pushKV("checksum", GetDescriptorChecksum(request.params[0].get_str())); - result.pushKV("isrange", desc->IsRange()); - result.pushKV("issolvable", desc->IsSolvable()); + result.pushKV("isrange", descs.at(0)->IsRange()); + result.pushKV("issolvable", descs.at(0)->IsSolvable()); result.pushKV("hasprivatekeys", provider.keys.size() > 0); return result; }, }; } +static UniValue DeriveAddresses(const Descriptor* desc, int64_t range_begin, int64_t range_end, FlatSigningProvider& key_provider) +{ + UniValue addresses(UniValue::VARR); + + for (int64_t i = range_begin; i <= range_end; ++i) { + FlatSigningProvider provider; + std::vector<CScript> scripts; + if (!desc->Expand(i, key_provider, scripts, provider)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys"); + } + + for (const CScript& script : scripts) { + CTxDestination dest; + if (!ExtractDestination(script, dest)) { + // ExtractDestination no longer returns true for P2PK since it doesn't have a corresponding address + // However combo will output P2PK and should just ignore that script + if (scripts.size() > 1 && std::get_if<PubKeyDestination>(&dest)) { + continue; + } + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor does not have a corresponding address"); + } + + addresses.push_back(EncodeDestination(dest)); + } + } + + // This should not be possible, but an assert seems overkill: + if (addresses.empty()) { + throw JSONRPCError(RPC_MISC_ERROR, "Unexpected empty result"); + } + + return addresses; +} + static RPCHelpMan deriveaddresses() { const std::string EXAMPLE_DESCRIPTOR = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu"; @@ -217,7 +264,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" @@ -226,11 +273,24 @@ static RPCHelpMan deriveaddresses() {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."}, {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."}, }, - RPCResult{ - RPCResult::Type::ARR, "", "", - { - {RPCResult::Type::STR, "address", "the derived addresses"}, - } + { + RPCResult{"for single derivation descriptors", + RPCResult::Type::ARR, "", "", + { + {RPCResult::Type::STR, "address", "the derived addresses"}, + } + }, + RPCResult{"for multipath descriptors", + RPCResult::Type::ARR, "", "The derived addresses for each of the multipath expansions of the descriptor, in multipath specifier order", + { + { + RPCResult::Type::ARR, "", "The derived addresses for a multipath descriptor expansion", + { + {RPCResult::Type::STR, "address", "the derived address"}, + }, + }, + }, + }, }, RPCExamples{ "First three native segwit receive addresses\n" + @@ -250,11 +310,11 @@ static RPCHelpMan deriveaddresses() FlatSigningProvider key_provider; std::string error; - auto desc = Parse(desc_str, key_provider, error, /* require_checksum = */ true); - if (!desc) { + auto descs = Parse(desc_str, key_provider, error, /* require_checksum = */ true); + if (descs.empty()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } - + auto& desc = descs.at(0); if (!desc->IsRange() && request.params.size() > 1) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor"); } @@ -263,36 +323,18 @@ static RPCHelpMan deriveaddresses() throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified for a ranged descriptor"); } - UniValue addresses(UniValue::VARR); - - for (int64_t i = range_begin; i <= range_end; ++i) { - FlatSigningProvider provider; - std::vector<CScript> scripts; - if (!desc->Expand(i, key_provider, scripts, provider)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys"); - } + UniValue addresses = DeriveAddresses(desc.get(), range_begin, range_end, key_provider); - for (const CScript& script : scripts) { - CTxDestination dest; - if (!ExtractDestination(script, dest)) { - // ExtractDestination no longer returns true for P2PK since it doesn't have a corresponding address - // However combo will output P2PK and should just ignore that script - if (scripts.size() > 1 && std::get_if<PubKeyDestination>(&dest)) { - continue; - } - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor does not have a corresponding address"); - } - - addresses.push_back(EncodeDestination(dest)); - } + if (descs.size() == 1) { + return addresses; } - // This should not be possible, but an assert seems overkill: - if (addresses.empty()) { - throw JSONRPCError(RPC_MISC_ERROR, "Unexpected empty result"); + UniValue ret(UniValue::VARR); + ret.push_back(addresses); + for (size_t i = 1; i < descs.size(); ++i) { + ret.push_back(DeriveAddresses(descs.at(i).get(), range_begin, range_end, key_provider)); } - - return addresses; + return ret; }, }; } 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 2ecaeeaf40..65e6e40b0d 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -16,6 +16,7 @@ #include <node/context.h> #include <node/psbt.h> #include <node/transaction.h> +#include <node/types.h> #include <policy/packages.h> #include <policy/policy.h> #include <policy/rbf.h> @@ -84,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() + ")"}, }; @@ -337,15 +338,7 @@ static RPCHelpMan getrawtransaction() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved"); } - // Accept either a bool (true) or a num (>=0) to indicate verbosity. - int verbosity{0}; - if (!request.params[1].isNull()) { - if (request.params[1].isBool()) { - verbosity = request.params[1].get_bool(); - } else { - verbosity = request.params[1].getInt<int>(); - } - } + int verbosity{ParseVerbosity(request.params[1], /*default_verbosity=*/0)}; if (!request.params[2].isNull()) { LOCK(cs_main); @@ -404,11 +397,16 @@ static RPCHelpMan getrawtransaction() CBlockUndo blockUndo; CBlock block; - if (tx->IsCoinBase() || !blockindex || WITH_LOCK(::cs_main, return chainman.m_blockman.IsBlockPruned(*blockindex)) || - !(chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex) && chainman.m_blockman.ReadBlockFromDisk(block, *blockindex))) { + if (tx->IsCoinBase() || !blockindex || WITH_LOCK(::cs_main, return !(blockindex->nStatus & BLOCK_HAVE_MASK))) { TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); return result; } + if (!chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex)) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); + } + if (!chainman.m_blockman.ReadBlockFromDisk(block, *blockindex)) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); + } CTxUndo* undoTX {nullptr}; auto it = std::find_if(block.vtx.begin(), block.vtx.end(), [tx](CTransactionRef t){ return *t == *tx; }); @@ -505,18 +503,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"}, @@ -556,6 +554,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 @@ -598,6 +597,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 @@ -734,7 +734,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"}, @@ -832,9 +832,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)"}, }}, @@ -1489,9 +1489,8 @@ static RPCHelpMan combinepsbt() } PartiallySignedTransaction merged_psbt; - const TransactionError error = CombinePSBTs(merged_psbt, psbtxs); - if (error != TransactionError::OK) { - throw JSONRPCTransactionError(error); + if (!CombinePSBTs(merged_psbt, psbtxs)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "PSBTs not compatible (different transactions)"); } DataStream ssTx{}; @@ -1748,8 +1747,8 @@ static RPCHelpMan joinpsbts() } psbtxs.push_back(psbtx); // Choose the highest version number - if (static_cast<uint32_t>(psbtx.tx->nVersion) > best_version) { - best_version = static_cast<uint32_t>(psbtx.tx->nVersion); + if (psbtx.tx->version > best_version) { + best_version = psbtx.tx->version; } // Choose the lowest lock time if (psbtx.tx->nLockTime < best_locktime) { @@ -1760,7 +1759,7 @@ static RPCHelpMan joinpsbts() // Create a blank psbt where everything will be added PartiallySignedTransaction merged_psbt; merged_psbt.tx = CMutableTransaction(); - merged_psbt.tx->nVersion = static_cast<int32_t>(best_version); + merged_psbt.tx->version = best_version; merged_psbt.tx->nLockTime = best_locktime; // Merge @@ -1790,12 +1789,12 @@ 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(); - shuffled_psbt.tx->nVersion = merged_psbt.tx->nVersion; + shuffled_psbt.tx->version = merged_psbt.tx->version; shuffled_psbt.tx->nLockTime = merged_psbt.tx->nLockTime; for (int i : input_indices) { shuffled_psbt.AddInput(merged_psbt.tx->vin[i], merged_psbt.inputs[i]); @@ -1838,8 +1837,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/register.h b/src/rpc/register.h index 65fd29ff08..17ed6c142c 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_RPC_REGISTER_H #define BITCOIN_RPC_REGISTER_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep /** These are in one header file to avoid creating tons of single-function * headers for everything under src/rpc/ */ diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index d35782189e..afd98f8875 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -5,12 +5,11 @@ #include <rpc/request.h> -#include <util/fs.h> - #include <common/args.h> #include <logging.h> #include <random.h> #include <rpc/protocol.h> +#include <util/fs.h> #include <util/fs_helpers.h> #include <util/strencodings.h> @@ -45,6 +44,7 @@ UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, request.pushKV("method", strMethod); request.pushKV("params", params); request.pushKV("id", id); + request.pushKV("jsonrpc", "2.0"); return request; } @@ -94,7 +94,7 @@ static fs::path GetAuthCookieFile(bool temp=false) static bool g_generated_cookie = false; -bool GenerateAuthCookie(std::string *cookie_out) +bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms) { const size_t COOKIE_SIZE = 32; unsigned char rand_pwd[COOKIE_SIZE]; @@ -108,7 +108,7 @@ bool GenerateAuthCookie(std::string *cookie_out) fs::path filepath_tmp = GetAuthCookieFile(true); file.open(filepath_tmp); if (!file.is_open()) { - LogPrintf("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp)); + LogInfo("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp)); return false; } file << cookie; @@ -116,11 +116,21 @@ bool GenerateAuthCookie(std::string *cookie_out) fs::path filepath = GetAuthCookieFile(false); if (!RenameOver(filepath_tmp, filepath)) { - LogPrintf("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath)); + LogInfo("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath)); return false; } + if (cookie_perms) { + std::error_code code; + fs::permissions(filepath, cookie_perms.value(), fs::perm_options::replace, code); + if (code) { + LogInfo("Unable to set permissions on cookie authentication file %s\n", fs::PathToString(filepath_tmp)); + return false; + } + } + g_generated_cookie = true; - LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath)); + LogInfo("Generated RPC authentication cookie %s\n", fs::PathToString(filepath)); + LogInfo("Permissions used for cookie: %s\n", PermsToSymbolicString(fs::status(filepath).permissions())); if (cookie_out) *cookie_out = cookie; @@ -216,10 +226,10 @@ void JSONRPCRequest::parse(const UniValue& valRequest) throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string"); strMethod = valMethod.get_str(); if (fLogIPs) - LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod), + LogDebug(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod), this->authUser, this->peerAddr); else - LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser); + LogDebug(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser); // Parse params const UniValue& valParams{request.find_value("params")}; diff --git a/src/rpc/request.h b/src/rpc/request.h index e47f90af86..24887e8691 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -11,18 +11,20 @@ #include <string> #include <univalue.h> +#include <util/fs.h> enum class JSONRPCVersion { V1_LEGACY, V2 }; +/** JSON-RPC 2.0 request, only used in bitcoin-cli **/ UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id); UniValue JSONRPCReplyObj(UniValue result, UniValue error, std::optional<UniValue> id, JSONRPCVersion jsonrpc_version); UniValue JSONRPCError(int code, const std::string& message); /** Generate a new RPC authentication cookie and write it to disk */ -bool GenerateAuthCookie(std::string *cookie_out); +bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms=std::nullopt); /** Read the RPC authentication cookie from disk */ bool GetAuthCookie(std::string *cookie_out); /** Delete RPC authentication cookie from disk */ diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 838068bc19..01f2dc0c0e 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <rpc/server.h> @@ -11,6 +11,7 @@ #include <common/system.h> #include <logging.h> #include <node/context.h> +#include <node/kernel_notifications.h> #include <rpc/server_util.h> #include <rpc/util.h> #include <sync.h> @@ -18,8 +19,7 @@ #include <util/strencodings.h> #include <util/string.h> #include <util/time.h> - -#include <boost/signals2/signal.hpp> +#include <validation.h> #include <cassert> #include <chrono> @@ -27,6 +27,8 @@ #include <mutex> #include <unordered_map> +using util::SplitString; + static GlobalMutex g_rpc_warmup_mutex; static std::atomic<bool> g_rpc_running{false}; static bool fRPCInWarmup GUARDED_BY(g_rpc_warmup_mutex) = true; @@ -67,22 +69,6 @@ struct RPCCommandExecution } }; -static struct CRPCSignals -{ - boost::signals2::signal<void ()> Started; - boost::signals2::signal<void ()> Stopped; -} g_rpcSignals; - -void RPCServer::OnStarted(std::function<void ()> slot) -{ - g_rpcSignals.Started.connect(slot); -} - -void RPCServer::OnStopped(std::function<void ()> slot) -{ - g_rpcSignals.Stopped.connect(slot); -} - std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const { std::string strRet; @@ -183,7 +169,7 @@ static RPCHelpMan stop() { // Event loop will exit after current HTTP requests have been handled, so // this reply will get back to the client. - CHECK_NONFATAL((*CHECK_NONFATAL(EnsureAnyNodeContext(jsonRequest.context).shutdown))()); + CHECK_NONFATAL((CHECK_NONFATAL(EnsureAnyNodeContext(jsonRequest.context).shutdown_request))()); if (jsonRequest.params[0].isNum()) { UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].getInt<int>()}); } @@ -293,9 +279,8 @@ bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd) void StartRPC() { - LogPrint(BCLog::RPC, "Starting RPC\n"); + LogDebug(BCLog::RPC, "Starting RPC\n"); g_rpc_running = true; - g_rpcSignals.Started(); } void InterruptRPC() @@ -303,7 +288,7 @@ void InterruptRPC() static std::once_flag g_rpc_interrupt_flag; // This function could be called twice if the GUI has been started with -server=1. std::call_once(g_rpc_interrupt_flag, []() { - LogPrint(BCLog::RPC, "Interrupting RPC\n"); + LogDebug(BCLog::RPC, "Interrupting RPC\n"); // Interrupt e.g. running longpolls g_rpc_running = false; }); @@ -314,11 +299,11 @@ void StopRPC() static std::once_flag g_rpc_stop_flag; // This function could be called twice if the GUI has been started with -server=1. assert(!g_rpc_running); - std::call_once(g_rpc_stop_flag, []() { - LogPrint(BCLog::RPC, "Stopping RPC\n"); + std::call_once(g_rpc_stop_flag, [&]() { + LogDebug(BCLog::RPC, "Stopping RPC\n"); WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear()); DeleteAuthCookie(); - g_rpcSignals.Stopped(); + LogDebug(BCLog::RPC, "RPC stopped.\n"); }); } @@ -581,7 +566,7 @@ void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nS throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); LOCK(g_deadline_timers_mutex); deadlineTimers.erase(name); - LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); + LogDebug(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))); } diff --git a/src/rpc/server.h b/src/rpc/server.h index 5735aff821..5a22279a58 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -18,12 +18,6 @@ class CRPCCommand; -namespace RPCServer -{ - void OnStarted(std::function<void ()> slot); - void OnStopped(std::function<void ()> slot); -} - /** Query whether RPC is running */ bool IsRPCRunning(); @@ -48,7 +42,7 @@ bool RPCIsInWarmup(std::string *outStatus); class RPCTimerBase { public: - virtual ~RPCTimerBase() {} + virtual ~RPCTimerBase() = default; }; /** @@ -57,7 +51,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/server_util.cpp b/src/rpc/server_util.cpp index efd4a43c28..0387cbb8e2 100644 --- a/src/rpc/server_util.cpp +++ b/src/rpc/server_util.cpp @@ -101,6 +101,14 @@ CConnman& EnsureConnman(const NodeContext& node) return *node.connman; } +interfaces::Mining& EnsureMining(const NodeContext& node) +{ + if (!node.mining) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Node miner not found"); + } + return *node.mining; +} + PeerManager& EnsurePeerman(const NodeContext& node) { if (!node.peerman) { diff --git a/src/rpc/server_util.h b/src/rpc/server_util.h index a4a53166b4..1e6fb7e6a6 100644 --- a/src/rpc/server_util.h +++ b/src/rpc/server_util.h @@ -18,6 +18,9 @@ class BanMan; namespace node { struct NodeContext; } // namespace node +namespace interfaces { +class Mining; +} // namespace interfaces node::NodeContext& EnsureAnyNodeContext(const std::any& context); CTxMemPool& EnsureMemPool(const node::NodeContext& node); @@ -31,6 +34,7 @@ ChainstateManager& EnsureAnyChainman(const std::any& context); CBlockPolicyEstimator& EnsureFeeEstimator(const node::NodeContext& node); CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context); CConnman& EnsureConnman(const node::NodeContext& node); +interfaces::Mining& EnsureMining(const node::NodeContext& node); PeerManager& EnsurePeerman(const node::NodeContext& node); AddrMan& EnsureAddrman(const node::NodeContext& node); AddrMan& EnsureAnyAddrman(const std::any& context); diff --git a/src/rpc/signmessage.cpp b/src/rpc/signmessage.cpp index 9f3c24efcf..83462738c5 100644 --- a/src/rpc/signmessage.cpp +++ b/src/rpc/signmessage.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/signmessage.h> #include <key.h> #include <key_io.h> #include <rpc/protocol.h> @@ -10,7 +11,6 @@ #include <rpc/server.h> #include <rpc/util.h> #include <univalue.h> -#include <util/message.h> #include <string> diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp index 7958deb677..40294fda06 100644 --- a/src/rpc/txoutproof.cpp +++ b/src/rpc/txoutproof.cpp @@ -10,6 +10,7 @@ #include <merkleblock.h> #include <node/blockstorage.h> #include <primitives/transaction.h> +#include <rpc/blockchain.h> #include <rpc/server.h> #include <rpc/server_util.h> #include <rpc/util.h> @@ -96,6 +97,10 @@ static RPCHelpMan gettxoutproof() } } + { + LOCK(cs_main); + CheckBlockDataAvailability(chainman.m_blockman, *pblockindex, /*check_for_undo=*/false); + } CBlock block; if (!chainman.m_blockman.ReadBlockFromDisk(block, *pblockindex)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 9600258de9..d71d7d737b 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -2,27 +2,30 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <clientversion.h> -#include <core_io.h> #include <common/args.h> +#include <common/messages.h> +#include <common/types.h> #include <consensus/amount.h> -#include <script/interpreter.h> +#include <core_io.h> #include <key_io.h> +#include <node/types.h> #include <outputtype.h> #include <rpc/util.h> #include <script/descriptor.h> +#include <script/interpreter.h> #include <script/signingprovider.h> #include <script/solver.h> #include <tinyformat.h> +#include <uint256.h> #include <univalue.h> #include <util/check.h> #include <util/result.h> #include <util/strencodings.h> #include <util/string.h> #include <util/translation.h> -#include <warnings.h> #include <algorithm> #include <iterator> @@ -30,6 +33,14 @@ #include <tuple> #include <utility> +using common::PSBTError; +using common::PSBTErrorString; +using common::TransactionErrorString; +using node::TransactionError; +using util::Join; +using util::SplitString; +using util::TrimString; + const std::string UNIX_EPOCH_TIME = "UNIX epoch time"; const std::string EXAMPLE_ADDRESS[2] = {"bc1q09vm5lfy0j5reeulh4x5752q25uqqvz34hufdl", "bc1q02ad21edsxd23d32dfgqqsz4vv4nmtfzuklhy3"}; @@ -70,6 +81,18 @@ void RPCTypeCheckObj(const UniValue& o, } } +int ParseVerbosity(const UniValue& arg, int default_verbosity) +{ + if (!arg.isNull()) { + if (arg.isBool()) { + return arg.get_bool(); // true = 1 + } else { + return arg.getInt<int>(); + } + } + return default_verbosity; +} + CAmount AmountFromValue(const UniValue& value, int decimals) { if (!value.isNum() && !value.isStr()) @@ -92,11 +115,11 @@ CFeeRate ParseFeeRate(const UniValue& json) uint256 ParseHashV(const UniValue& v, std::string_view name) { const std::string& strHex(v.get_str()); - if (64 != strHex.length()) - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", name, 64, strHex.length(), strHex)); - if (!IsHex(strHex)) // Note: IsHex("") is false - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be hexadecimal string (not '%s')", name, strHex)); - return uint256S(strHex); + if (auto rv{uint256::FromHex(strHex)}) return *rv; + if (auto expected_len{uint256::size() * 2}; strHex.length() != expected_len) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", name, expected_len, strHex.length(), strHex)); + } + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be hexadecimal string (not '%s')", name, strHex)); } uint256 ParseHashO(const UniValue& o, std::string_view strKey) { @@ -176,7 +199,7 @@ std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& std::string HelpExampleRpc(const std::string& methodname, const std::string& args) { return "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", " - "\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: application/json;' http://127.0.0.1:8332/\n"; + "\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: application/json' http://127.0.0.1:8332/\n"; } std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args) @@ -187,7 +210,7 @@ std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& } return "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", " - "\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: application/json;' http://127.0.0.1:8332/\n"; + "\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: application/json' http://127.0.0.1:8332/\n"; } // Converts a hex string to a public key if possible @@ -322,6 +345,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); @@ -364,25 +395,35 @@ unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target) return unsigned_target; } +RPCErrorCode RPCErrorFromPSBTError(PSBTError err) +{ + switch (err) { + case PSBTError::UNSUPPORTED: + return RPC_INVALID_PARAMETER; + case PSBTError::SIGHASH_MISMATCH: + return RPC_DESERIALIZATION_ERROR; + default: break; + } + return RPC_TRANSACTION_ERROR; +} + 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::P2P_DISABLED: - return RPC_CLIENT_P2P_DISABLED; - case TransactionError::INVALID_PSBT: - case TransactionError::PSBT_MISMATCH: - return RPC_INVALID_PARAMETER; - case TransactionError::SIGHASH_MISMATCH: - return RPC_DESERIALIZATION_ERROR; + case TransactionError::ALREADY_IN_UTXO_SET: + return RPC_VERIFY_ALREADY_IN_UTXO_SET; default: break; } return RPC_TRANSACTION_ERROR; } +UniValue JSONRPCPSBTError(PSBTError err) +{ + return JSONRPCError(RPCErrorFromPSBTError(err), PSBTErrorString(err).original); +} + UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string) { if (err_string.length() > 0) { @@ -778,7 +819,7 @@ std::string RPCHelpMan::ToString() const if (arg.m_opts.hidden) break; // Any arg that follows is also hidden // Push named argument name and description - sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true)); + sections.m_sections.emplace_back(util::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true)); sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size()); // Recursively push nested args @@ -1317,24 +1358,26 @@ std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, Fl } std::string error; - auto desc = Parse(desc_str, provider, error); - if (!desc) { + auto descs = Parse(desc_str, provider, error); + if (descs.empty()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } - if (!desc->IsRange()) { + if (!descs.at(0)->IsRange()) { range.first = 0; range.second = 0; } std::vector<CScript> ret; for (int i = range.first; i <= range.second; ++i) { - std::vector<CScript> scripts; - if (!desc->Expand(i, provider, scripts, provider)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str)); - } - if (expand_priv) { - desc->ExpandPrivate(/*pos=*/i, provider, /*out=*/provider); + for (const auto& desc : descs) { + std::vector<CScript> scripts; + if (!desc->Expand(i, provider, scripts, provider)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str)); + } + if (expand_priv) { + desc->ExpandPrivate(/*pos=*/i, provider, /*out=*/provider); + } + std::move(scripts.begin(), scripts.end(), std::back_inserter(ret)); } - std::move(scripts.begin(), scripts.end(), std::back_inserter(ret)); } return ret; } @@ -1361,17 +1404,3 @@ void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj) if (warnings.empty()) return; obj.pushKV("warnings", BilingualStringsToUniValue(warnings)); } - -UniValue GetNodeWarnings(bool use_deprecated) -{ - if (use_deprecated) { - const auto all_warnings{GetWarnings()}; - return all_warnings.empty() ? "" : all_warnings.back().original; - } - - UniValue warnings{UniValue::VARR}; - for (auto&& warning : GetWarnings()) { - warnings.push_back(std::move(warning.original)); - } - return warnings; -} diff --git a/src/rpc/util.h b/src/rpc/util.h index 51ecaff13c..b8e6759768 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -34,9 +34,14 @@ class JSONRPCRequest; enum ServiceFlags : uint64_t; enum class OutputType; -enum class TransactionError; struct FlatSigningProvider; struct bilingual_str; +namespace common { +enum class PSBTError; +} // namespace common +namespace node { +enum class TransactionError; +} // namespace node static constexpr bool DEFAULT_RPC_DOC_CHECK{ #ifdef RPC_DOC_CHECK @@ -96,6 +101,15 @@ std::vector<unsigned char> ParseHexV(const UniValue& v, std::string_view name); std::vector<unsigned char> ParseHexO(const UniValue& o, std::string_view strKey); /** + * Parses verbosity from provided UniValue. + * + * @param[in] arg The verbosity argument as a bool (true) or int (0, 1, 2,...) + * @param[in] default_verbosity The value to return if verbosity argument is null + * @returns An integer describing the verbosity level (e.g. 0, 1, 2, etc.) + */ +int ParseVerbosity(const UniValue& arg, int default_verbosity); + +/** * Validate and return a CAmount from a UniValue number or string. * * @param[in] value UniValue number or string to parse. @@ -127,8 +141,9 @@ int ParseSighashString(const UniValue& sighash); //! Parse a confirm target option and raise an RPC error if it is invalid. unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target); -RPCErrorCode RPCErrorFromTransactionError(TransactionError terr); -UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = ""); +RPCErrorCode RPCErrorFromTransactionError(node::TransactionError terr); +UniValue JSONRPCPSBTError(common::PSBTError err); +UniValue JSONRPCTransactionError(node::TransactionError terr, const std::string& err_string = ""); //! Parse a JSON range specified as int64, or [int64, int64] std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value); @@ -497,6 +512,4 @@ private: void PushWarnings(const UniValue& warnings, UniValue& obj); void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj); -UniValue GetNodeWarnings(bool use_deprecated); - #endif // BITCOIN_RPC_UTIL_H diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index a11d4dcbd5..5026470edc 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -8,6 +8,7 @@ #include <key_io.h> #include <pubkey.h> #include <script/miniscript.h> +#include <script/parsing.h> #include <script/script.h> #include <script/signingprovider.h> #include <script/solver.h> @@ -17,16 +18,18 @@ #include <span.h> #include <util/bip32.h> #include <util/check.h> -#include <util/spanparsing.h> #include <util/strencodings.h> #include <util/vector.h> +#include <algorithm> #include <memory> #include <numeric> #include <optional> #include <string> #include <vector> +using util::Split; + namespace { //////////////////////////////////////////////////////////////////////////// @@ -114,13 +117,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; @@ -217,6 +220,9 @@ public: virtual std::optional<CPubKey> GetRootPubKey() const = 0; /** Return the extended public key for this PubkeyProvider, if it has one. */ virtual std::optional<CExtPubKey> GetRootExtPubKey() const = 0; + + /** Make a deep copy of this PubkeyProvider */ + virtual std::unique_ptr<PubkeyProvider> Clone() const = 0; }; class OriginPubkeyProvider final : public PubkeyProvider @@ -278,6 +284,10 @@ public: { return m_provider->GetRootExtPubKey(); } + std::unique_ptr<PubkeyProvider> Clone() const override + { + return std::make_unique<OriginPubkeyProvider>(m_expr_index, m_origin, m_provider->Clone(), m_apostrophe); + } }; /** An object representing a parsed constant public key in a descriptor. */ @@ -331,6 +341,10 @@ public: { return std::nullopt; } + std::unique_ptr<PubkeyProvider> Clone() const override + { + return std::make_unique<ConstPubkeyProvider>(m_expr_index, m_pubkey, m_xonly); + } }; enum class DeriveType { @@ -554,6 +568,10 @@ public: { return m_root_extkey; } + std::unique_ptr<PubkeyProvider> Clone() const override + { + return std::make_unique<BIP32PubkeyProvider>(m_expr_index, m_root_extkey, m_path, m_derive, m_apostrophe); + } }; /** Base class for all Descriptor implementations. */ @@ -769,6 +787,8 @@ public: arg->GetPubKeys(pubkeys, ext_pubs); } } + + virtual std::unique_ptr<DescriptorImpl> Clone() const = 0; }; /** A parsed addr(A) descriptor. */ @@ -790,6 +810,10 @@ public: bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; } std::optional<int64_t> ScriptSize() const override { return GetScriptForDestination(m_destination).size(); } + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<AddressDescriptor>(m_destination); + } }; /** A parsed raw(H) descriptor. */ @@ -813,6 +837,11 @@ public: bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; } std::optional<int64_t> ScriptSize() const override { return m_script.size(); } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<RawDescriptor>(m_script); + } }; /** A parsed pk(P) descriptor. */ @@ -848,6 +877,11 @@ public: } std::optional<int64_t> MaxSatisfactionElems() const override { return 1; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<PKDescriptor>(m_pubkey_args.at(0)->Clone(), m_xonly); + } }; /** A parsed pkh(P) descriptor. */ @@ -877,6 +911,11 @@ public: } std::optional<int64_t> MaxSatisfactionElems() const override { return 2; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<PKHDescriptor>(m_pubkey_args.at(0)->Clone()); + } }; /** A parsed wpkh(P) descriptor. */ @@ -906,6 +945,11 @@ public: } std::optional<int64_t> MaxSatisfactionElems() const override { return 2; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<WPKHDescriptor>(m_pubkey_args.at(0)->Clone()); + } }; /** A parsed combo(P) descriptor. */ @@ -930,6 +974,10 @@ protected: public: ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {} bool IsSingleType() const final { return false; } + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<ComboDescriptor>(m_pubkey_args.at(0)->Clone()); + } }; /** A parsed multi(...) or sortedmulti(...) descriptor */ @@ -968,6 +1016,14 @@ public: } std::optional<int64_t> MaxSatisfactionElems() const override { return 1 + m_threshold; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + std::vector<std::unique_ptr<PubkeyProvider>> providers; + providers.reserve(m_pubkey_args.size()); + std::transform(m_pubkey_args.begin(), m_pubkey_args.end(), providers.begin(), [](const std::unique_ptr<PubkeyProvider>& p) { return p->Clone(); }); + return std::make_unique<MultisigDescriptor>(m_threshold, std::move(providers), m_sorted); + } }; /** A parsed (sorted)multi_a(...) descriptor. Always uses x-only pubkeys. */ @@ -1004,6 +1060,16 @@ public: } std::optional<int64_t> MaxSatisfactionElems() const override { return m_pubkey_args.size(); } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + std::vector<std::unique_ptr<PubkeyProvider>> providers; + providers.reserve(m_pubkey_args.size()); + for (const auto& arg : m_pubkey_args) { + providers.push_back(arg->Clone()); + } + return std::make_unique<MultiADescriptor>(m_threshold, std::move(providers), m_sorted); + } }; /** A parsed sh(...) descriptor. */ @@ -1049,6 +1115,11 @@ public: if (const auto sub_elems = m_subdescriptor_args[0]->MaxSatisfactionElems()) return 1 + *sub_elems; return {}; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<SHDescriptor>(m_subdescriptor_args.at(0)->Clone()); + } }; /** A parsed wsh(...) descriptor. */ @@ -1085,6 +1156,11 @@ public: if (const auto sub_elems = m_subdescriptor_args[0]->MaxSatisfactionElems()) return 1 + *sub_elems; return {}; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<WSHDescriptor>(m_subdescriptor_args.at(0)->Clone()); + } }; /** A parsed tr(...) descriptor. */ @@ -1150,6 +1226,14 @@ public: // FIXME: See above, we assume keypath spend. return 1; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + std::vector<std::unique_ptr<DescriptorImpl>> subdescs; + subdescs.reserve(m_subdescriptor_args.size()); + std::transform(m_subdescriptor_args.begin(), m_subdescriptor_args.end(), subdescs.begin(), [](const std::unique_ptr<DescriptorImpl>& d) { return d->Clone(); }); + return std::make_unique<TRDescriptor>(m_pubkey_args.at(0)->Clone(), std::move(subdescs), m_depths); + } }; /* We instantiate Miniscript here with a simple integer as key type. @@ -1268,6 +1352,16 @@ public: std::optional<int64_t> MaxSatisfactionElems() const override { return m_node->GetStackSize(); } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + std::vector<std::unique_ptr<PubkeyProvider>> providers; + providers.reserve(m_pubkey_args.size()); + for (const auto& arg : m_pubkey_args) { + providers.push_back(arg->Clone()); + } + return std::make_unique<MiniscriptDescriptor>(std::move(providers), miniscript::MakeNodeRef<uint32_t>(*m_node)); + } }; /** A parsed rawtr(...) descriptor. */ @@ -1298,6 +1392,11 @@ public: // See above, we assume keypath spend. return 1; } + + std::unique_ptr<DescriptorImpl> Clone() const override + { + return std::make_unique<RawTRDescriptor>(m_pubkey_args.at(0)->Clone()); + } }; //////////////////////////////////////////////////////////////////////////// @@ -1312,52 +1411,110 @@ enum class ParseScriptContext { P2TR, //!< Inside tr() (either internal key, or BIP342 script leaf) }; +std::optional<uint32_t> ParseKeyPathNum(Span<const char> elem, bool& apostrophe, std::string& error) +{ + bool hardened = false; + if (elem.size() > 0) { + const char last = elem[elem.size() - 1]; + if (last == '\'' || last == 'h') { + elem = elem.first(elem.size() - 1); + hardened = true; + apostrophe = last == '\''; + } + } + uint32_t p; + if (!ParseUInt32(std::string(elem.begin(), elem.end()), &p)) { + error = strprintf("Key path value '%s' is not a valid uint32", std::string(elem.begin(), elem.end())); + return std::nullopt; + } else if (p > 0x7FFFFFFFUL) { + error = strprintf("Key path value %u is out of range", p); + return std::nullopt; + } + + return std::make_optional<uint32_t>(p | (((uint32_t)hardened) << 31)); +} + /** - * Parse a key path, being passed a split list of elements (the first element is ignored). + * Parse a key path, being passed a split list of elements (the first element is ignored because it is always the key). * * @param[in] split BIP32 path string, using either ' or h for hardened derivation - * @param[out] out the key path + * @param[out] out Vector of parsed key paths * @param[out] apostrophe only updated if hardened derivation is found * @param[out] error parsing error message + * @param[in] allow_multipath Allows the parsed path to use the multipath specifier * @returns false if parsing failed **/ -[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, bool& apostrophe, std::string& error) +[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, std::vector<KeyPath>& out, bool& apostrophe, std::string& error, bool allow_multipath) { + KeyPath path; + std::optional<size_t> multipath_segment_index; + std::vector<uint32_t> multipath_values; + std::unordered_set<uint32_t> seen_multipath; + for (size_t i = 1; i < split.size(); ++i) { - Span<const char> elem = split[i]; - bool hardened = false; - if (elem.size() > 0) { - const char last = elem[elem.size() - 1]; - if (last == '\'' || last == 'h') { - elem = elem.first(elem.size() - 1); - hardened = true; - apostrophe = last == '\''; + const Span<const char>& elem = split[i]; + + // Check if element contain multipath specifier + if (!elem.empty() && elem.front() == '<' && elem.back() == '>') { + if (!allow_multipath) { + error = strprintf("Key path value '%s' specifies multipath in a section where multipath is not allowed", std::string(elem.begin(), elem.end())); + return false; + } + if (multipath_segment_index) { + error = "Multiple multipath key path specifiers found"; + return false; + } + + // Parse each possible value + std::vector<Span<const char>> nums = Split(Span(elem.begin()+1, elem.end()-1), ";"); + if (nums.size() < 2) { + error = "Multipath key path specifiers must have at least two items"; + return false; } + + for (const auto& num : nums) { + const auto& op_num = ParseKeyPathNum(num, apostrophe, error); + if (!op_num) return false; + auto [_, inserted] = seen_multipath.insert(*op_num); + if (!inserted) { + error = strprintf("Duplicated key path value %u in multipath specifier", *op_num); + return false; + } + multipath_values.emplace_back(*op_num); + } + + path.emplace_back(); // Placeholder for multipath segment + multipath_segment_index = path.size()-1; + } else { + const auto& op_num = ParseKeyPathNum(elem, apostrophe, error); + if (!op_num) return false; + path.emplace_back(*op_num); } - uint32_t p; - if (!ParseUInt32(std::string(elem.begin(), elem.end()), &p)) { - error = strprintf("Key path value '%s' is not a valid uint32", std::string(elem.begin(), elem.end())); - return false; - } else if (p > 0x7FFFFFFFUL) { - error = strprintf("Key path value %u is out of range", p); - return false; + } + + if (!multipath_segment_index) { + out.emplace_back(std::move(path)); + } else { + // Replace the multipath placeholder with each value while generating paths + for (size_t i = 0; i < multipath_values.size(); i++) { + KeyPath branch_path = path; + branch_path[*multipath_segment_index] = multipath_values[i]; + out.emplace_back(std::move(branch_path)); } - out.push_back(p | (((uint32_t)hardened) << 31)); } return true; } /** Parse a public key that excludes origin information. */ -std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, bool& apostrophe, std::string& error) +std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, bool& apostrophe, std::string& error) { - using namespace spanparsing; - + std::vector<std::unique_ptr<PubkeyProvider>> ret; bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH; auto split = Split(sp, '/'); std::string str(split[0].begin(), split[0].end()); if (str.size() == 0) { error = "No key provided"; - return nullptr; + return {}; } if (split.size() == 1) { if (IsHex(str)) { @@ -1365,35 +1522,38 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S CPubKey pubkey(data); if (pubkey.IsValid() && !pubkey.IsValidNonHybrid()) { error = "Hybrid public keys are not allowed"; - return nullptr; + return {}; } if (pubkey.IsFullyValid()) { if (permit_uncompressed || pubkey.IsCompressed()) { - return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false); + ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false)); + return ret; } else { error = "Uncompressed keys are not allowed"; - return nullptr; + return {}; } } else if (data.size() == 32 && ctx == ParseScriptContext::P2TR) { unsigned char fullkey[33] = {0x02}; std::copy(data.begin(), data.end(), fullkey + 1); pubkey.Set(std::begin(fullkey), std::end(fullkey)); if (pubkey.IsFullyValid()) { - return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, true); + ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, true)); + return ret; } } error = strprintf("Pubkey '%s' is invalid", str); - return nullptr; + return {}; } CKey key = DecodeSecret(str); if (key.IsValid()) { if (permit_uncompressed || key.IsCompressed()) { CPubKey pubkey = key.GetPubKey(); out.keys.emplace(pubkey.GetID(), key); - return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR); + ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR)); + return ret; } else { error = "Uncompressed keys are not allowed"; - return nullptr; + return {}; } } } @@ -1401,35 +1561,37 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S CExtPubKey extpubkey = DecodeExtPubKey(str); if (!extkey.key.IsValid() && !extpubkey.pubkey.IsValid()) { error = strprintf("key '%s' is not valid", str); - return nullptr; + return {}; } - KeyPath path; + std::vector<KeyPath> paths; DeriveType type = DeriveType::NO; - if (split.back() == Span{"*"}.first(1)) { + if (std::ranges::equal(split.back(), Span{"*"}.first(1))) { split.pop_back(); type = DeriveType::UNHARDENED; - } else if (split.back() == Span{"*'"}.first(2) || split.back() == Span{"*h"}.first(2)) { - apostrophe = split.back() == Span{"*'"}.first(2); + } else if (std::ranges::equal(split.back(), Span{"*'"}.first(2)) || std::ranges::equal(split.back(), Span{"*h"}.first(2))) { + apostrophe = std::ranges::equal(split.back(), Span{"*'"}.first(2)); split.pop_back(); type = DeriveType::HARDENED; } - if (!ParseKeyPath(split, path, apostrophe, error)) return nullptr; + if (!ParseKeyPath(split, paths, apostrophe, error, /*allow_multipath=*/true)) return {}; if (extkey.key.IsValid()) { extpubkey = extkey.Neuter(); out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key); } - return std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type, apostrophe); + for (auto& path : paths) { + ret.emplace_back(std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type, apostrophe)); + } + return ret; } /** Parse a public key including origin information (if enabled). */ -std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) +std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) { - using namespace spanparsing; - + std::vector<std::unique_ptr<PubkeyProvider>> ret; auto origin_split = Split(sp, ']'); if (origin_split.size() > 2) { error = "Multiple ']' characters found for a single pubkey"; - return nullptr; + return {}; } // This is set if either the origin or path suffix contains a hardened derivation. bool apostrophe = false; @@ -1439,27 +1601,33 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c if (origin_split[0].empty() || origin_split[0][0] != '[') { error = strprintf("Key origin start '[ character expected but not found, got '%c' instead", origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]); - return nullptr; + return {}; } auto slash_split = Split(origin_split[0].subspan(1), '/'); if (slash_split[0].size() != 8) { error = strprintf("Fingerprint is not 4 bytes (%u characters instead of 8 characters)", slash_split[0].size()); - return nullptr; + return {}; } std::string fpr_hex = std::string(slash_split[0].begin(), slash_split[0].end()); if (!IsHex(fpr_hex)) { error = strprintf("Fingerprint '%s' is not hex", fpr_hex); - return nullptr; + return {}; } auto fpr_bytes = ParseHex(fpr_hex); KeyOriginInfo info; static_assert(sizeof(info.fingerprint) == 4, "Fingerprint must be 4 bytes"); assert(fpr_bytes.size() == 4); std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint); - if (!ParseKeyPath(slash_split, info.path, apostrophe, error)) return nullptr; - auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, apostrophe, error); - if (!provider) return nullptr; - return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider), apostrophe); + std::vector<KeyPath> path; + if (!ParseKeyPath(slash_split, path, apostrophe, error, /*allow_multipath=*/false)) return {}; + info.path = path.at(0); + auto providers = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, apostrophe, error); + if (providers.empty()) return {}; + ret.reserve(providers.size()); + for (auto& prov : providers) { + ret.emplace_back(std::make_unique<OriginPubkeyProvider>(key_exp_index, info, std::move(prov), apostrophe)); + } + return ret; } std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext ctx, const SigningProvider& provider) @@ -1501,8 +1669,8 @@ struct KeyParser { FlatSigningProvider* m_out; //! Must not be nullptr if parsing from Script. const SigningProvider* m_in; - //! List of keys contained in the Miniscript. - mutable std::vector<std::unique_ptr<PubkeyProvider>> m_keys; + //! List of multipath expanded keys contained in the Miniscript. + mutable std::vector<std::vector<std::unique_ptr<PubkeyProvider>>> m_keys; //! Used to detect key parsing errors within a Miniscript. mutable std::string m_key_parsing_error; //! The script context we're operating within (Tapscript or P2WSH). @@ -1515,7 +1683,7 @@ struct KeyParser { : m_out(out), m_in(in), m_script_ctx(ctx), m_offset(offset) {} bool KeyCompare(const Key& a, const Key& b) const { - return *m_keys.at(a) < *m_keys.at(b); + return *m_keys.at(a).at(0) < *m_keys.at(b).at(0); } ParseScriptContext ParseContext() const { @@ -1531,14 +1699,14 @@ struct KeyParser { assert(m_out); Key key = m_keys.size(); auto pk = ParsePubkey(m_offset + key, {&*begin, &*end}, ParseContext(), *m_out, m_key_parsing_error); - if (!pk) return {}; - m_keys.push_back(std::move(pk)); + if (pk.empty()) return {}; + m_keys.emplace_back(std::move(pk)); return key; } std::optional<std::string> ToString(const Key& key) const { - return m_keys.at(key)->ToString(); + return m_keys.at(key).at(0)->ToString(); } template<typename I> std::optional<Key> FromPKBytes(I begin, I end) const @@ -1549,13 +1717,15 @@ struct KeyParser { XOnlyPubKey pubkey; std::copy(begin, end, pubkey.begin()); if (auto pubkey_provider = InferPubkey(pubkey.GetEvenCorrespondingCPubKey(), ParseContext(), *m_in)) { - m_keys.push_back(std::move(pubkey_provider)); + m_keys.emplace_back(); + m_keys.back().push_back(std::move(pubkey_provider)); return key; } } else if (!miniscript::IsTapscript(m_script_ctx)) { CPubKey pubkey(begin, end); if (auto pubkey_provider = InferPubkey(pubkey, ParseContext(), *m_in)) { - m_keys.push_back(std::move(pubkey_provider)); + m_keys.emplace_back(); + m_keys.back().push_back(std::move(pubkey_provider)); return key; } } @@ -1573,7 +1743,8 @@ struct KeyParser { if (m_in->GetPubKey(keyid, pubkey)) { if (auto pubkey_provider = InferPubkey(pubkey, ParseContext(), *m_in)) { Key key = m_keys.size(); - m_keys.push_back(std::move(pubkey_provider)); + m_keys.emplace_back(); + m_keys.back().push_back(std::move(pubkey_provider)); return key; } } @@ -1587,44 +1758,54 @@ struct KeyParser { /** Parse a script in a particular context. */ // NOLINTNEXTLINE(misc-no-recursion) -std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) +std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) { - using namespace spanparsing; + using namespace script; + std::vector<std::unique_ptr<DescriptorImpl>> ret; auto expr = Expr(sp); if (Func("pk", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); - if (!pubkey) { + auto pubkeys = ParsePubkey(key_exp_index, expr, ctx, out, error); + if (pubkeys.empty()) { error = strprintf("pk(): %s", error); - return nullptr; + return {}; } ++key_exp_index; - return std::make_unique<PKDescriptor>(std::move(pubkey), ctx == ParseScriptContext::P2TR); + for (auto& pubkey : pubkeys) { + ret.emplace_back(std::make_unique<PKDescriptor>(std::move(pubkey), ctx == ParseScriptContext::P2TR)); + } + return ret; } if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && Func("pkh", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); - if (!pubkey) { + auto pubkeys = ParsePubkey(key_exp_index, expr, ctx, out, error); + if (pubkeys.empty()) { error = strprintf("pkh(): %s", error); - return nullptr; + return {}; } ++key_exp_index; - return std::make_unique<PKHDescriptor>(std::move(pubkey)); + for (auto& pubkey : pubkeys) { + ret.emplace_back(std::make_unique<PKHDescriptor>(std::move(pubkey))); + } + return ret; } else if (ctx != ParseScriptContext::P2TR && Func("pkh", expr)) { // Under Taproot, always the Miniscript parser deal with it. error = "Can only have pkh at top level, in sh(), wsh(), or in tr()"; - return nullptr; + return {}; } if (ctx == ParseScriptContext::TOP && Func("combo", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); - if (!pubkey) { + auto pubkeys = ParsePubkey(key_exp_index, expr, ctx, out, error); + if (pubkeys.empty()) { error = strprintf("combo(): %s", error); - return nullptr; + return {}; } ++key_exp_index; - return std::make_unique<ComboDescriptor>(std::move(pubkey)); + for (auto& pubkey : pubkeys) { + ret.emplace_back(std::make_unique<ComboDescriptor>(std::move(pubkey))); + } + return ret; } else if (Func("combo", expr)) { error = "Can only have combo() at top level"; - return nullptr; + return {}; } const bool multi = Func("multi", expr); const bool sortedmulti = !multi && Func("sortedmulti", expr); @@ -1634,118 +1815,157 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const (ctx == ParseScriptContext::P2TR && (multi_a || sortedmulti_a))) { auto threshold = Expr(expr); uint32_t thres; - std::vector<std::unique_ptr<PubkeyProvider>> providers; + std::vector<std::vector<std::unique_ptr<PubkeyProvider>>> providers; // List of multipath expanded pubkeys if (!ParseUInt32(std::string(threshold.begin(), threshold.end()), &thres)) { error = strprintf("Multi threshold '%s' is not valid", std::string(threshold.begin(), threshold.end())); - return nullptr; + return {}; } size_t script_size = 0; + size_t max_providers_len = 0; while (expr.size()) { if (!Const(",", expr)) { error = strprintf("Multi: expected ',', got '%c'", expr[0]); - return nullptr; + return {}; } auto arg = Expr(expr); - auto pk = ParsePubkey(key_exp_index, arg, ctx, out, error); - if (!pk) { + auto pks = ParsePubkey(key_exp_index, arg, ctx, out, error); + if (pks.empty()) { error = strprintf("Multi: %s", error); - return nullptr; + return {}; } - script_size += pk->GetSize() + 1; - providers.emplace_back(std::move(pk)); + script_size += pks.at(0)->GetSize() + 1; + max_providers_len = std::max(max_providers_len, pks.size()); + providers.emplace_back(std::move(pks)); key_exp_index++; } if ((multi || sortedmulti) && (providers.empty() || providers.size() > MAX_PUBKEYS_PER_MULTISIG)) { error = strprintf("Cannot have %u keys in multisig; must have between 1 and %d keys, inclusive", providers.size(), MAX_PUBKEYS_PER_MULTISIG); - return nullptr; + return {}; } else if ((multi_a || sortedmulti_a) && (providers.empty() || providers.size() > MAX_PUBKEYS_PER_MULTI_A)) { error = strprintf("Cannot have %u keys in multi_a; must have between 1 and %d keys, inclusive", providers.size(), MAX_PUBKEYS_PER_MULTI_A); - return nullptr; + return {}; } else if (thres < 1) { error = strprintf("Multisig threshold cannot be %d, must be at least 1", thres); - return nullptr; + return {}; } else if (thres > providers.size()) { error = strprintf("Multisig threshold cannot be larger than the number of keys; threshold is %d but only %u keys specified", thres, providers.size()); - return nullptr; + return {}; } if (ctx == ParseScriptContext::TOP) { if (providers.size() > 3) { error = strprintf("Cannot have %u pubkeys in bare multisig; only at most 3 pubkeys", providers.size()); - return nullptr; + return {}; } } if (ctx == ParseScriptContext::P2SH) { // This limits the maximum number of compressed pubkeys to 15. if (script_size + 3 > MAX_SCRIPT_ELEMENT_SIZE) { error = strprintf("P2SH script is too large, %d bytes is larger than %d bytes", script_size + 3, MAX_SCRIPT_ELEMENT_SIZE); - return nullptr; + return {}; } } - if (multi || sortedmulti) { - return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sortedmulti); - } else { - return std::make_unique<MultiADescriptor>(thres, std::move(providers), sortedmulti_a); + + // Make sure all vecs are of the same length, or exactly length 1 + // For length 1 vectors, clone key providers until vector is the same length + for (auto& vec : providers) { + if (vec.size() == 1) { + for (size_t i = 1; i < max_providers_len; ++i) { + vec.emplace_back(vec.at(0)->Clone()); + } + } else if (vec.size() != max_providers_len) { + error = strprintf("multi(): Multipath derivation paths have mismatched lengths"); + return {}; + } } + + // Build the final descriptors vector + for (size_t i = 0; i < max_providers_len; ++i) { + // Build final pubkeys vectors by retrieving the i'th subscript for each vector in subscripts + std::vector<std::unique_ptr<PubkeyProvider>> pubs; + pubs.reserve(providers.size()); + for (auto& pub : providers) { + pubs.emplace_back(std::move(pub.at(i))); + } + if (multi || sortedmulti) { + ret.emplace_back(std::make_unique<MultisigDescriptor>(thres, std::move(pubs), sortedmulti)); + } else { + ret.emplace_back(std::make_unique<MultiADescriptor>(thres, std::move(pubs), sortedmulti_a)); + } + } + return ret; } else if (multi || sortedmulti) { error = "Can only have multi/sortedmulti at top level, in sh(), or in wsh()"; - return nullptr; + return {}; } else if (multi_a || sortedmulti_a) { error = "Can only have multi_a/sortedmulti_a inside tr()"; - return nullptr; + return {}; } if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) { - auto pubkey = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error); - if (!pubkey) { + auto pubkeys = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error); + if (pubkeys.empty()) { error = strprintf("wpkh(): %s", error); - return nullptr; + return {}; } key_exp_index++; - return std::make_unique<WPKHDescriptor>(std::move(pubkey)); + for (auto& pubkey : pubkeys) { + ret.emplace_back(std::make_unique<WPKHDescriptor>(std::move(pubkey))); + } + return ret; } else if (Func("wpkh", expr)) { error = "Can only have wpkh() at top level or inside sh()"; - return nullptr; + return {}; } if (ctx == ParseScriptContext::TOP && Func("sh", expr)) { - auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error); - if (!desc || expr.size()) return nullptr; - return std::make_unique<SHDescriptor>(std::move(desc)); + auto descs = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error); + if (descs.empty() || expr.size()) return {}; + std::vector<std::unique_ptr<DescriptorImpl>> ret; + ret.reserve(descs.size()); + for (auto& desc : descs) { + ret.push_back(std::make_unique<SHDescriptor>(std::move(desc))); + } + return ret; } else if (Func("sh", expr)) { error = "Can only have sh() at top level"; - return nullptr; + return {}; } if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wsh", expr)) { - auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error); - if (!desc || expr.size()) return nullptr; - return std::make_unique<WSHDescriptor>(std::move(desc)); + auto descs = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error); + if (descs.empty() || expr.size()) return {}; + for (auto& desc : descs) { + ret.emplace_back(std::make_unique<WSHDescriptor>(std::move(desc))); + } + return ret; } else if (Func("wsh", expr)) { error = "Can only have wsh() at top level or inside sh()"; - return nullptr; + return {}; } if (ctx == ParseScriptContext::TOP && Func("addr", expr)) { CTxDestination dest = DecodeDestination(std::string(expr.begin(), expr.end())); if (!IsValidDestination(dest)) { error = "Address is not valid"; - return nullptr; + return {}; } - return std::make_unique<AddressDescriptor>(std::move(dest)); + ret.emplace_back(std::make_unique<AddressDescriptor>(std::move(dest))); + return ret; } else if (Func("addr", expr)) { error = "Can only have addr() at top level"; - return nullptr; + return {}; } if (ctx == ParseScriptContext::TOP && Func("tr", expr)) { auto arg = Expr(expr); - auto internal_key = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); - if (!internal_key) { + auto internal_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); + if (internal_keys.empty()) { error = strprintf("tr(): %s", error); - return nullptr; + return {}; } + size_t max_providers_len = internal_keys.size(); ++key_exp_index; - std::vector<std::unique_ptr<DescriptorImpl>> subscripts; //!< list of script subexpressions + std::vector<std::vector<std::unique_ptr<DescriptorImpl>>> subscripts; //!< list of multipath expanded script subexpressions std::vector<int> depths; //!< depth in the tree of each subexpression (same length subscripts) if (expr.size()) { if (!Const(",", expr)) { error = strprintf("tr: expected ',', got '%c'", expr[0]); - return nullptr; + return {}; } /** The path from the top of the tree to what we're currently processing. * branches[i] == false: left branch in the i'th step from the top; true: right branch. @@ -1759,19 +1979,20 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const branches.push_back(false); // new left branch if (branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT) { error = strprintf("tr() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT); - return nullptr; + return {}; } } // Process the actual script expression. auto sarg = Expr(expr); subscripts.emplace_back(ParseScript(key_exp_index, sarg, ParseScriptContext::P2TR, out, error)); - if (!subscripts.back()) return nullptr; + if (subscripts.back().empty()) return {}; + max_providers_len = std::max(max_providers_len, subscripts.back().size()); depths.push_back(branches.size()); // Process closing braces; one is expected for every right branch we were in. while (branches.size() && branches.back()) { if (!Const("}", expr)) { error = strprintf("tr(): expected '}' after script expression"); - return nullptr; + return {}; } branches.pop_back(); // move up one level after encountering '}' } @@ -1779,7 +2000,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const if (branches.size() && !branches.back()) { if (!Const(",", expr)) { error = strprintf("tr(): expected ',' after script expression"); - return nullptr; + return {}; } branches.back() = true; // And now we're in a right branch. } @@ -1787,40 +2008,82 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const // After we've explored a whole tree, we must be at the end of the expression. if (expr.size()) { error = strprintf("tr(): expected ')' after script expression"); - return nullptr; + return {}; } } assert(TaprootBuilder::ValidDepths(depths)); - return std::make_unique<TRDescriptor>(std::move(internal_key), std::move(subscripts), std::move(depths)); + + // Make sure all vecs are of the same length, or exactly length 1 + // For length 1 vectors, clone subdescs until vector is the same length + for (auto& vec : subscripts) { + if (vec.size() == 1) { + for (size_t i = 1; i < max_providers_len; ++i) { + vec.emplace_back(vec.at(0)->Clone()); + } + } else if (vec.size() != max_providers_len) { + error = strprintf("tr(): Multipath subscripts have mismatched lengths"); + return {}; + } + } + + if (internal_keys.size() > 1 && internal_keys.size() != max_providers_len) { + error = strprintf("tr(): Multipath internal key mismatches multipath subscripts lengths"); + return {}; + } + + while (internal_keys.size() < max_providers_len) { + internal_keys.emplace_back(internal_keys.at(0)->Clone()); + } + + // Build the final descriptors vector + for (size_t i = 0; i < max_providers_len; ++i) { + // Build final subscripts vectors by retrieving the i'th subscript for each vector in subscripts + std::vector<std::unique_ptr<DescriptorImpl>> this_subs; + this_subs.reserve(subscripts.size()); + for (auto& subs : subscripts) { + this_subs.emplace_back(std::move(subs.at(i))); + } + ret.emplace_back(std::make_unique<TRDescriptor>(std::move(internal_keys.at(i)), std::move(this_subs), depths)); + } + return ret; + + } else if (Func("tr", expr)) { error = "Can only have tr at top level"; - return nullptr; + return {}; } if (ctx == ParseScriptContext::TOP && Func("rawtr", expr)) { auto arg = Expr(expr); if (expr.size()) { error = strprintf("rawtr(): only one key expected."); - return nullptr; + return {}; + } + auto output_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); + if (output_keys.empty()) { + error = strprintf("rawtr(): %s", error); + return {}; } - auto output_key = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); - if (!output_key) return nullptr; ++key_exp_index; - return std::make_unique<RawTRDescriptor>(std::move(output_key)); + for (auto& pubkey : output_keys) { + ret.emplace_back(std::make_unique<RawTRDescriptor>(std::move(pubkey))); + } + return ret; } else if (Func("rawtr", expr)) { error = "Can only have rawtr at top level"; - return nullptr; + return {}; } if (ctx == ParseScriptContext::TOP && Func("raw", expr)) { std::string str(expr.begin(), expr.end()); if (!IsHex(str)) { error = "Raw script is not hex"; - return nullptr; + return {}; } auto bytes = ParseHex(str); - return std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end())); + ret.emplace_back(std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end()))); + return ret; } else if (Func("raw", expr)) { error = "Can only have raw() at top level"; - return nullptr; + return {}; } // Process miniscript expressions. { @@ -1829,12 +2092,12 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const auto node = miniscript::FromString(std::string(expr.begin(), expr.end()), parser); if (parser.m_key_parsing_error != "") { error = std::move(parser.m_key_parsing_error); - return nullptr; + return {}; } if (node) { if (ctx != ParseScriptContext::P2WSH && ctx != ParseScriptContext::P2TR) { error = "Miniscript expressions can only be used in wsh or tr."; - return nullptr; + return {}; } if (!node->IsSane() || node->IsNotSatisfiable()) { // Try to find the first insane sub for better error reporting. @@ -1859,24 +2122,52 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const } else { error += " is not satisfiable"; } - return nullptr; + return {}; } // A signature check is required for a miniscript to be sane. Therefore no sane miniscript // may have an empty list of public keys. CHECK_NONFATAL(!parser.m_keys.empty()); key_exp_index += parser.m_keys.size(); - return std::make_unique<MiniscriptDescriptor>(std::move(parser.m_keys), std::move(node)); + // Make sure all vecs are of the same length, or exactly length 1 + // For length 1 vectors, clone subdescs until vector is the same length + size_t num_multipath = std::max_element(parser.m_keys.begin(), parser.m_keys.end(), + [](const std::vector<std::unique_ptr<PubkeyProvider>>& a, const std::vector<std::unique_ptr<PubkeyProvider>>& b) { + return a.size() < b.size(); + })->size(); + + for (auto& vec : parser.m_keys) { + if (vec.size() == 1) { + for (size_t i = 1; i < num_multipath; ++i) { + vec.emplace_back(vec.at(0)->Clone()); + } + } else if (vec.size() != num_multipath) { + error = strprintf("Miniscript: Multipath derivation paths have mismatched lengths"); + return {}; + } + } + + // Build the final descriptors vector + for (size_t i = 0; i < num_multipath; ++i) { + // Build final pubkeys vectors by retrieving the i'th subscript for each vector in subscripts + std::vector<std::unique_ptr<PubkeyProvider>> pubs; + pubs.reserve(parser.m_keys.size()); + for (auto& pub : parser.m_keys) { + pubs.emplace_back(std::move(pub.at(i))); + } + ret.emplace_back(std::make_unique<MiniscriptDescriptor>(std::move(pubs), node)); + } + return ret; } } if (ctx == ParseScriptContext::P2SH) { error = "A function is needed within P2SH"; - return nullptr; + return {}; } else if (ctx == ParseScriptContext::P2WSH) { error = "A function is needed within P2WSH"; - return nullptr; + return {}; } error = strprintf("'%s' is not a valid descriptor function", std::string(expr.begin(), expr.end())); - return nullptr; + return {}; } std::unique_ptr<DescriptorImpl> InferMultiA(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider) @@ -2014,7 +2305,12 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo KeyParser parser(/* out = */nullptr, /* in = */&provider, /* ctx = */script_ctx); auto node = miniscript::FromScript(script, parser); if (node && node->IsSane()) { - return std::make_unique<MiniscriptDescriptor>(std::move(parser.m_keys), std::move(node)); + std::vector<std::unique_ptr<PubkeyProvider>> keys; + keys.reserve(parser.m_keys.size()); + for (auto& key : parser.m_keys) { + keys.emplace_back(std::move(key.at(0))); + } + return std::make_unique<MiniscriptDescriptor>(std::move(keys), std::move(node)); } } @@ -2038,8 +2334,6 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo /** Check a descriptor checksum, and update desc to be the checksum-less part. */ bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string& error, std::string* out_checksum = nullptr) { - using namespace spanparsing; - auto check_split = Split(sp, '#'); if (check_split.size() > 2) { error = "Multiple '#' symbols"; @@ -2071,14 +2365,21 @@ bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string& err return true; } -std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum) +std::vector<std::unique_ptr<Descriptor>> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum) { Span<const char> sp{descriptor}; - if (!CheckChecksum(sp, require_checksum, error)) return nullptr; + if (!CheckChecksum(sp, require_checksum, error)) return {}; uint32_t key_exp_index = 0; auto ret = ParseScript(key_exp_index, sp, ParseScriptContext::TOP, out, error); - if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret)); - return nullptr; + if (sp.size() == 0 && !ret.empty()) { + std::vector<std::unique_ptr<Descriptor>> descs; + descs.reserve(ret.size()); + for (auto& r : ret) { + descs.emplace_back(std::unique_ptr<Descriptor>(std::move(r))); + } + return descs; + } + return {}; } std::string GetDescriptorChecksum(const std::string& descriptor) diff --git a/src/script/descriptor.h b/src/script/descriptor.h index e78a775330..473649a314 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -173,9 +173,9 @@ struct Descriptor { * is set, the checksum is mandatory - otherwise it is optional. * * If a parse error occurs, or the checksum is missing/invalid, or anything - * else is wrong, `nullptr` is returned. + * else is wrong, an empty vector is returned. */ -std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum = false); +std::vector<std::unique_ptr<Descriptor>> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum = false); /** Get the checksum for a `descriptor`. * diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index c969ce45f1..dcdddb88e9 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1303,7 +1303,7 @@ public: // Serialize the nSequence if (nInput != nIn && (fHashSingle || fHashNone)) // let the others update at will - ::Serialize(s, int{0}); + ::Serialize(s, int32_t{0}); else ::Serialize(s, txTo.vin[nInput].nSequence); } @@ -1321,8 +1321,8 @@ public: /** Serialize txTo */ template<typename S> void Serialize(S &s) const { - // Serialize nVersion - ::Serialize(s, txTo.nVersion); + // Serialize version + ::Serialize(s, txTo.version); // Serialize vin unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); ::WriteCompactSize(s, nInputs); @@ -1512,7 +1512,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons ss << hash_type; // Transaction level data - ss << tx_to.nVersion; + ss << tx_to.version; ss << tx_to.nLockTime; if (input_type != SIGHASH_ANYONECANPAY) { ss << cache.m_prevouts_single_hash; @@ -1565,7 +1565,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons } template <class T> -uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) +uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { assert(nIn < txTo.vin.size()); @@ -1594,7 +1594,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn HashWriter ss{}; // Version - ss << txTo.nVersion; + ss << txTo.version; // Input prevouts/nSequence (none/all, depending on flags) ss << hashPrevouts; ss << hashSequence; @@ -1743,7 +1743,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq // Fail if the transaction's version number is not set high // enough to trigger BIP 68 rules. - if (static_cast<uint32_t>(txTo->nVersion) < 2) + if (txTo->version < 2) return false; // Sequence numbers with their most significant bit set are not @@ -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 4880f32410..58f24434f0 100644 --- a/src/script/miniscript.h +++ b/src/script/miniscript.h @@ -18,10 +18,10 @@ #include <policy/policy.h> #include <primitives/transaction.h> +#include <script/parsing.h> #include <script/script.h> #include <span.h> #include <util/check.h> -#include <util/spanparsing.h> #include <util/strencodings.h> #include <util/string.h> #include <util/vector.h> @@ -251,7 +251,7 @@ namespace internal { //! The maximum size of a witness item for a Miniscript under Tapscript context. (A BIP340 signature with a sighash type byte.) static constexpr uint32_t MAX_TAPMINISCRIPT_STACK_ELEM_SIZE{65}; -//! nVersion + nLockTime +//! version + nLockTime constexpr uint32_t TX_OVERHEAD{4 + 4}; //! prevout + nSequence + scriptSig constexpr uint32_t TXIN_BYTES_NO_WITNESS{36 + 4 + 1}; @@ -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 @@ -863,8 +863,8 @@ public: if (!key_str) return {}; return std::move(ret) + "pk_h(" + std::move(*key_str) + ")"; } - case Fragment::AFTER: return std::move(ret) + "after(" + ::ToString(node.k) + ")"; - case Fragment::OLDER: return std::move(ret) + "older(" + ::ToString(node.k) + ")"; + case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")"; + case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")"; case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")"; case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")"; case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")"; @@ -883,7 +883,7 @@ public: return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")"; case Fragment::MULTI: { CHECK_NONFATAL(!is_tapscript); - auto str = std::move(ret) + "multi(" + ::ToString(node.k); + auto str = std::move(ret) + "multi(" + util::ToString(node.k); for (const auto& key : node.keys) { auto key_str = ctx.ToString(key); if (!key_str) return {}; @@ -893,7 +893,7 @@ public: } case Fragment::MULTI_A: { CHECK_NONFATAL(is_tapscript); - auto str = std::move(ret) + "multi_a(" + ::ToString(node.k); + auto str = std::move(ret) + "multi_a(" + util::ToString(node.k); for (const auto& key : node.keys) { auto key_str = ctx.ToString(key); if (!key_str) return {}; @@ -902,7 +902,7 @@ public: return std::move(str) + ")"; } case Fragment::THRESH: { - auto str = std::move(ret) + "thresh(" + ::ToString(node.k); + auto str = std::move(ret) + "thresh(" + util::ToString(node.k); for (auto& sub : subs) { str += "," + std::move(sub); } @@ -1764,7 +1764,7 @@ void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector<Node template<typename Key, typename Ctx> inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) { - using namespace spanparsing; + using namespace script; // Account for the minimum script size for all parsed fragments so far. It "borrows" 1 // script byte from all leaf nodes, counting it instead whenever a space for a recursive @@ -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/util/spanparsing.cpp b/src/script/parsing.cpp index c464fc2b87..3528ac9bfa 100644 --- a/src/util/spanparsing.cpp +++ b/src/script/parsing.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <util/spanparsing.h> +#include <script/parsing.h> #include <span.h> @@ -10,7 +10,7 @@ #include <cstddef> #include <string> -namespace spanparsing { +namespace script { bool Const(const std::string& str, Span<const char>& sp) { @@ -49,4 +49,4 @@ Span<const char> Expr(Span<const char>& sp) return ret; } -} // namespace spanparsing +} // namespace script diff --git a/src/script/parsing.h b/src/script/parsing.h new file mode 100644 index 0000000000..850faea041 --- /dev/null +++ b/src/script/parsing.h @@ -0,0 +1,40 @@ +// Copyright (c) 2018-2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SCRIPT_PARSING_H +#define BITCOIN_SCRIPT_PARSING_H + +#include <span.h> + +#include <string> + +namespace script { + +/** Parse a constant. + * + * If sp's initial part matches str, sp is updated to skip that part, and true is returned. + * Otherwise sp is unmodified and false is returned. + */ +bool Const(const std::string& str, Span<const char>& sp); + +/** Parse a function call. + * + * If sp's initial part matches str + "(", and sp ends with ")", sp is updated to be the + * section between the braces, and true is returned. Otherwise sp is unmodified and false + * is returned. + */ +bool Func(const std::string& str, Span<const char>& sp); + +/** Extract the expression that sp begins with. + * + * This function will return the initial part of sp, up to (but not including) the first + * comma or closing brace, skipping ones that are surrounded by braces. So for example, + * for "foo(bar(1),2),3" the initial part "foo(bar(1),2)" will be returned. sp will be + * updated to skip the initial part that is returned. + */ +Span<const char> Expr(Span<const char>& sp); + +} // namespace script + +#endif // BITCOIN_SCRIPT_PARSING_H diff --git a/src/script/script.cpp b/src/script/script.cpp index 80e8d26bcf..d650db9a0d 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -6,10 +6,10 @@ #include <script/script.h> #include <crypto/common.h> +#include <crypto/hex_base.h> #include <hash.h> #include <uint256.h> #include <util/hash_type.h> -#include <util/strencodings.h> #include <string> @@ -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..f457984980 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -17,6 +17,7 @@ #include <cstdint> #include <cstring> #include <limits> +#include <span> #include <stdexcept> #include <string> #include <type_traits> @@ -412,6 +413,32 @@ bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator en /** Serialized script, used inside transaction inputs and outputs */ class CScript : public CScriptBase { +private: + inline void AppendDataSize(const uint32_t size) + { + if (size < OP_PUSHDATA1) { + insert(end(), static_cast<value_type>(size)); + } else if (size <= 0xff) { + insert(end(), OP_PUSHDATA1); + insert(end(), static_cast<value_type>(size)); + } else if (size <= 0xffff) { + insert(end(), OP_PUSHDATA2); + value_type data[2]; + WriteLE16(data, size); + insert(end(), std::cbegin(data), std::cend(data)); + } else { + insert(end(), OP_PUSHDATA4); + value_type data[4]; + WriteLE32(data, size); + insert(end(), std::cbegin(data), std::cend(data)); + } + } + + void AppendData(std::span<const value_type> data) + { + insert(end(), data.begin(), data.end()); + } + protected: CScript& push_int64(int64_t n) { @@ -429,11 +456,11 @@ protected: } return *this; } + public: - CScript() { } - 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) { } + CScript() = default; + template <std::input_iterator InputIterator> + CScript(InputIterator first, InputIterator last) : CScriptBase{first, last} { } SERIALIZE_METHODS(CScript, obj) { READWRITE(AsBase<CScriptBase>(obj)); } @@ -463,35 +490,19 @@ public: return *this; } - CScript& operator<<(const std::vector<unsigned char>& b) LIFETIMEBOUND + CScript& operator<<(std::span<const std::byte> b) LIFETIMEBOUND { - if (b.size() < OP_PUSHDATA1) - { - insert(end(), (unsigned char)b.size()); - } - else if (b.size() <= 0xff) - { - insert(end(), OP_PUSHDATA1); - insert(end(), (unsigned char)b.size()); - } - else if (b.size() <= 0xffff) - { - insert(end(), OP_PUSHDATA2); - uint8_t _data[2]; - WriteLE16(_data, b.size()); - insert(end(), _data, _data + sizeof(_data)); - } - else - { - insert(end(), OP_PUSHDATA4); - uint8_t _data[4]; - WriteLE32(_data, b.size()); - insert(end(), _data, _data + sizeof(_data)); - } - insert(end(), b.begin(), b.end()); + AppendDataSize(b.size()); + AppendData({reinterpret_cast<const value_type*>(b.data()), b.size()}); return *this; } + // For compatibility reasons. In new code, prefer using std::byte instead of uint8_t. + CScript& operator<<(std::span<const value_type> b) LIFETIMEBOUND + { + return *this << std::as_bytes(b); + } + bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const { return GetScriptOp(pc, end(), opcodeRet, &vchRet); @@ -533,6 +544,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 +588,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..42db251359 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); } @@ -691,27 +694,6 @@ void SignatureData::MergeSignatureData(SignatureData sigdata) signatures.insert(std::make_move_iterator(sigdata.signatures.begin()), std::make_move_iterator(sigdata.signatures.end())); } -bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data) -{ - assert(nIn < txTo.vin.size()); - - MutableTransactionSignatureCreator creator(txTo, nIn, amount, nHashType); - - bool ret = ProduceSignature(provider, creator, fromPubKey, sig_data); - UpdateInput(txTo.vin.at(nIn), sig_data); - return ret; -} - -bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, SignatureData& sig_data) -{ - assert(nIn < txTo.vin.size()); - const CTxIn& txin = txTo.vin[nIn]; - assert(txin.prevout.n < txFrom.vout.size()); - const CTxOut& txout = txFrom.vout[txin.prevout.n]; - - return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, sig_data); -} - namespace { /** Dummy signature checker which accepts all signatures. */ class DummySignatureChecker final : public BaseSignatureChecker @@ -831,7 +813,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..fe2c470bc6 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); }; @@ -97,25 +97,6 @@ struct SignatureData { /** Produce a script signature using a generic signature creator. */ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata); -/** - * Produce a satisfying script (scriptSig or witness). - * - * @param provider Utility containing the information necessary to solve a script. - * @param fromPubKey The script to produce a satisfaction for. - * @param txTo The spending transaction. - * @param nIn The index of the input in `txTo` referring the output being spent. - * @param amount The value of the output being spent. - * @param nHashType Signature hash type. - * @param sig_data Additional data provided to solve a script. Filled with the resulting satisfying - * script and whether the satisfaction is complete. - * - * @return True if the produced script is entirely satisfying `fromPubKey`. - **/ -bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, - unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data); -bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, - unsigned int nIn, int nHashType, SignatureData& sig_data); - /** Extract signature data from a transaction input, and insert it. */ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout); void UpdateInput(CTxIn& input, const SignatureData& data); 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 6e77403bf5..0c1e01dc95 100644 --- a/src/secp256k1/.cirrus.yml +++ b/src/secp256k1/.cirrus.yml @@ -10,8 +10,8 @@ env: MAKEFLAGS: -j4 BUILD: check ### secp256k1 config - ECMULTWINDOW: auto - ECMULTGENKB: auto + ECMULTWINDOW: 15 + ECMULTGENKB: 22 ASM: no WIDEMUL: auto WITH_VALGRIND: yes @@ -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 d246682044..0fc104d29b 100644 --- a/src/secp256k1/.github/workflows/ci.yml +++ b/src/secp256k1/.github/workflows/ci.yml @@ -21,8 +21,8 @@ env: MAKEFLAGS: '-j4' BUILD: 'check' ### secp256k1 config - ECMULTWINDOW: 'auto' - ECMULTGENKB: 'auto' + ECMULTWINDOW: 15 + 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' @@ -485,18 +493,25 @@ jobs: matrix: configuration: - env_vars: + CTIMETESTS: 'yes' CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g' - env_vars: ECMULTGENKB: 2 ECMULTWINDOW: 2 + CTIMETESTS: 'yes' CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3' + - env_vars: + # -fsanitize-memory-param-retval is clang's default, but our build system disables it + # when ctime_tests when enabled. + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -fsanitize-memory-param-retval -g' + CTIMETESTS: 'no' env: ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' - CTIMETESTS: 'yes' CC: 'clang' SECP256K1_TEST_ITERS: 32 ASM: 'no' @@ -541,6 +556,7 @@ jobs: WITH_VALGRIND: 'no' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -585,10 +601,10 @@ jobs: run: env if: ${{ always() }} - macos-native: - name: "x86_64: macOS Monterey" + x86_64-macos-native: + name: "x86_64: macOS Monterey, Valgrind" # See: https://github.com/actions/runner-images#available-images. - runs-on: macos-12 # Use M1 once available https://github.com/github/roadmap/issues/528 + runs-on: macos-12 env: CC: 'clang' @@ -599,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: @@ -616,7 +632,7 @@ jobs: - name: Install Homebrew packages run: | - brew install automake libtool gcc + brew install --quiet automake libtool gcc ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc - name: Install and cache Valgrind @@ -644,6 +660,62 @@ jobs: run: env if: ${{ always() }} + arm64-macos-native: + name: "ARM64: macOS Sonoma" + # See: https://github.com/actions/runner-images#available-images. + runs-on: macos-14 + + env: + CC: 'clang' + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + WITH_VALGRIND: 'no' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + env_vars: + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes' } + - { 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: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Homebrew packages + run: | + brew install --quiet automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc + + - name: CI script + env: ${{ matrix.env_vars }} + run: ./ci/ci.sh + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + win64-native: name: ${{ matrix.configuration.job_name }} # See: https://github.com/actions/runner-images#available-images. @@ -716,6 +788,7 @@ jobs: WERROR_CFLAGS: ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' @@ -802,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..fb82940627 100644 --- a/src/secp256k1/CHANGELOG.md +++ b/src/secp256k1/CHANGELOG.md @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [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 #### Added @@ -14,7 +29,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 +143,8 @@ 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 +[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...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 88994d828a..d5a7a2de39 100644 --- a/src/secp256k1/CMakeLists.txt +++ b/src/secp256k1/CMakeLists.txt @@ -1,32 +1,24 @@ -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 # the API. All changes in experimental modules are treated as # backwards-compatible and therefore at most increase the minor version. - VERSION 0.5.1 + VERSION 0.5.2 DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" LANGUAGES C ) if(CMAKE_VERSION VERSION_LESS 3.21) - get_directory_property(parent_directory PARENT_DIRECTORY) - if(parent_directory) - set(PROJECT_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.") - set(${PROJECT_NAME}_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.") + # Emulates CMake 3.21+ behavior. + if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(PROJECT_IS_TOP_LEVEL ON) + set(${PROJECT_NAME}_IS_TOP_LEVEL ON) else() - set(PROJECT_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.") - set(${PROJECT_NAME}_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.") + set(PROJECT_IS_TOP_LEVEL OFF) + set(${PROJECT_NAME}_IS_TOP_LEVEL OFF) endif() - unset(parent_directory) endif() # The library version is based on libtool versioning of the ABI. The set of @@ -35,7 +27,7 @@ endif() # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. set(${PROJECT_NAME}_LIB_VERSION_CURRENT 4) -set(${PROJECT_NAME}_LIB_VERSION_REVISION 1) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 2) set(${PROJECT_NAME}_LIB_VERSION_AGE 2) set(CMAKE_C_STANDARD 90) @@ -92,21 +84,15 @@ if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS) add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1) endif() -set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]") -set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS "AUTO" 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) +set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]") +set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) include(CheckStringOptionValue) check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) -if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO") - set(SECP256K1_ECMULT_WINDOW_SIZE 15) -endif() add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) -set(SECP256K1_ECMULT_GEN_KB "AUTO" 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. \"AUTO\" is a reasonable setting for desktop machines (currently 22). [default=AUTO]") -set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS "AUTO" 2 22 86) +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 STREQUAL "AUTO") - set(SECP256K1_ECMULT_GEN_KB 22) -endif() if(SECP256K1_ECMULT_GEN_KB EQUAL 2) add_compile_definitions(COMB_BLOCKS=2) add_compile_definitions(COMB_TEETH=5) @@ -192,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. @@ -214,23 +200,25 @@ mark_as_advanced( CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) -get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -set(default_build_type "RelWithDebInfo") -if(is_multi_config) - set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING - "Supported configuration types." - FORCE - ) -else() - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY - STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" - ) - if(NOT CMAKE_BUILD_TYPE) - message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING - "Choose the type of build." +if(PROJECT_IS_TOP_LEVEL) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + set(default_build_type "RelWithDebInfo") + if(is_multi_config) + set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING + "Supported configuration types." FORCE ) + else() + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" + ) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING + "Choose the type of build." + FORCE + ) + endif() endif() endif() @@ -263,10 +251,17 @@ endif() set(CMAKE_C_VISIBILITY_PRESET hidden) -# Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target. -# CTEST_TEST_TARGET_ALIAS is not documented but supposed to be user-facing. -# See: https://gitlab.kitware.com/cmake/cmake/-/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d2 -set(CTEST_TEST_TARGET_ALIAS check) +set(print_msan_notice) +if(SECP256K1_BUILD_CTIME_TESTS) + include(CheckMemorySanitizer) + check_memory_sanitizer(msan_enabled) + if(msan_enabled) + try_append_c_flags(-fno-sanitize-memory-param-retval) + set(print_msan_notice YES) + endif() + unset(msan_enabled) +endif() + include(CTest) # We do not use CTest's BUILD_TESTING because a single toggle for all tests is too coarse for our needs. mark_as_advanced(BUILD_TESTING) @@ -274,14 +269,24 @@ if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUST enable_testing() endif() -set(SECP256K1_LATE_CFLAGS "" CACHE STRING "Compiler flags that are added to the command line after all other flags added by the build system.") -include(AllTargetsCompileOptions) +set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_CFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}") +endif() + +set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_LDFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${SECP256K1_APPEND_LDFLAGS}") + string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}") +endif() add_subdirectory(src) -all_targets_compile_options(src "${SECP256K1_LATE_CFLAGS}") if(SECP256K1_BUILD_EXAMPLES) add_subdirectory(examples) - all_targets_compile_options(examples "${SECP256K1_LATE_CFLAGS}") endif() message("\n") @@ -332,7 +337,7 @@ message("Valgrind .............................. ${SECP256K1_VALGRIND}") get_directory_property(definitions COMPILE_DEFINITIONS) string(REPLACE ";" " " definitions "${definitions}") message("Preprocessor defined macros ........... ${definitions}") -message("C compiler ............................ ${CMAKE_C_COMPILER}") +message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}") message("CFLAGS ................................ ${CMAKE_C_FLAGS}") get_directory_property(compile_options COMPILE_OPTIONS) string(REPLACE ";" " " compile_options "${compile_options}") @@ -355,10 +360,20 @@ else() message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") endif() -if(SECP256K1_LATE_CFLAGS) - message("SECP256K1_LATE_CFLAGS ................. ${SECP256K1_LATE_CFLAGS}") +if(SECP256K1_APPEND_CFLAGS) + message("SECP256K1_APPEND_CFLAGS ............... ${SECP256K1_APPEND_CFLAGS}") +endif() +if(SECP256K1_APPEND_LDFLAGS) + message("SECP256K1_APPEND_LDFLAGS .............. ${SECP256K1_APPEND_LDFLAGS}") +endif() +message("") +if(print_msan_notice) + message( + "Note:\n" + " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n" + " to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n" + ) endif() -message("\n") if(SECP256K1_EXPERIMENTAL) message( " ******\n" 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 6e88eb4ecb..ed93e0519e 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -20,6 +20,7 @@ Features: * Optional module for public key recovery. * Optional module for ECDH key exchange. * Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). +* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki). Implementation details ---------------------- @@ -81,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. @@ -113,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/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 index 11adef4f22..048267fa6e 100644 --- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -45,6 +45,22 @@ fi AC_MSG_RESULT($has_valgrind) ]) +AC_DEFUN([SECP_MSAN_CHECK], [ +AC_MSG_CHECKING(whether MemorySanitizer is enabled) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error "MemorySanitizer is disabled." + # endif + #else + # error "__has_feature is not defined." + #endif + ]])], [msan_enabled=yes], [msan_enabled=no]) +AC_MSG_RESULT([$msan_enabled]) +]) + dnl SECP_TRY_APPEND_CFLAGS(flags, VAR) dnl Append flags to VAR if CC accepts them. AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [ 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/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile index 5ce715b41b..241bfa9719 100644 --- a/src/secp256k1/ci/linux-debian.Dockerfile +++ b/src/secp256k1/ci/linux-debian.Dockerfile @@ -40,7 +40,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ apt-get clean && rm -rf /var/lib/apt/lists/* # Build and install gcc snapshot -ARG GCC_SNAPSHOT_MAJOR=14 +ARG GCC_SNAPSHOT_MAJOR=15 RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ mkdir gcc && cd gcc && \ wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \ diff --git a/src/secp256k1/cmake/AllTargetsCompileOptions.cmake b/src/secp256k1/cmake/AllTargetsCompileOptions.cmake deleted file mode 100644 index 6e420e0fde..0000000000 --- a/src/secp256k1/cmake/AllTargetsCompileOptions.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# Add compile options to all targets added in the subdirectory. -function(all_targets_compile_options dir options) - get_directory_property(targets DIRECTORY ${dir} BUILDSYSTEM_TARGETS) - separate_arguments(options) - set(compiled_target_types STATIC_LIBRARY SHARED_LIBRARY OBJECT_LIBRARY EXECUTABLE) - foreach(target ${targets}) - get_target_property(type ${target} TYPE) - if(type IN_LIST compiled_target_types) - target_compile_options(${target} PRIVATE ${options}) - endif() - endforeach() -endfunction() diff --git a/src/secp256k1/cmake/CheckMemorySanitizer.cmake b/src/secp256k1/cmake/CheckMemorySanitizer.cmake new file mode 100644 index 0000000000..d9ef681e65 --- /dev/null +++ b/src/secp256k1/cmake/CheckMemorySanitizer.cmake @@ -0,0 +1,18 @@ +include_guard(GLOBAL) +include(CheckCSourceCompiles) + +function(check_memory_sanitizer output) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_source_compiles(" + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error \"MemorySanitizer is disabled.\" + # endif + #else + # error \"__has_feature is not defined.\" + #endif + " HAVE_MSAN) + set(${output} ${HAVE_MSAN} PARENT_SCOPE) +endfunction() diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 8b62e1dbfd..6841543f59 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -5,7 +5,7 @@ AC_PREREQ([2.60]) # backwards-compatible and therefore at most increase the minor version. define(_PKG_VERSION_MAJOR, 0) define(_PKG_VERSION_MINOR, 5) -define(_PKG_VERSION_PATCH, 1) +define(_PKG_VERSION_PATCH, 2) define(_PKG_VERSION_IS_RELEASE, false) # The library version is based on libtool versioning of the ABI. The set of @@ -14,7 +14,7 @@ define(_PKG_VERSION_IS_RELEASE, false) # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. define(_LIB_VERSION_CURRENT, 4) -define(_LIB_VERSION_REVISION, 1) +define(_LIB_VERSION_REVISION, 2) define(_LIB_VERSION_AGE, 2) AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) @@ -203,22 +203,22 @@ AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_wide AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto], [assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) -AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], +AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE], [window size for ecmult precomputation for verification, specified as integer in range [2..24].] [Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] [The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] [A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.] [For very large window sizes, use "make -j 1" to reduce memory use during compilation.] -["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]] +[The default value is a reasonable setting for desktop machines (currently 15). [default=15]] )], -[req_ecmult_window=$withval], [req_ecmult_window=auto]) +[set_ecmult_window=$withval], [set_ecmult_window=15]) -AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86|auto], +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.] -["auto" is a reasonable setting for desktop machines (currently 22). [default=auto]] +[The default value is a reasonable setting for desktop machines (currently 86). [default=86]] )], -[req_ecmult_gen_kb=$withval], [req_ecmult_gen_kb=auto]) +[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]] @@ -247,6 +247,20 @@ if test x"$enable_ctime_tests" = x"auto"; then enable_ctime_tests=$enable_valgrind fi +print_msan_notice=no +if test x"$enable_ctime_tests" = x"yes"; then + SECP_MSAN_CHECK + # MSan on Clang >=16 reports unitialized memory in function parameters and return values, even if + # the uninitalized variable is never actually "used". This is called "eager" checking, and it's + # sounds like good idea for normal use of MSan. However, it yields many false positives in the + # ctime_tests because many return values depend on secret (i.e., "uninitialized") values, and + # we're only interested in detecting branches (which count as "uses") on secret data. + if test x"$msan_enabled" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-fno-sanitize-memory-param-retval], SECP_CFLAGS) + print_msan_notice=yes + fi +fi + if test x"$enable_coverage" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1" SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS" @@ -335,14 +349,7 @@ auto) ;; esac -# Set ecmult window size -if test x"$req_ecmult_window" = x"auto"; then - set_ecmult_window=15 -else - set_ecmult_window=$req_ecmult_window -fi - -error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"'] +error_window_size=['window size for ecmult precomputation not an integer in range [2..24]'] case $set_ecmult_window in ''|*[[!0-9]]*) # no valid integer @@ -357,13 +364,6 @@ case $set_ecmult_window in ;; esac -# Set ecmult gen kb -if test x"$req_ecmult_gen_kb" = x"auto"; then - set_ecmult_gen_kb=22 -else - set_ecmult_gen_kb=$req_ecmult_gen_kb -fi - case $set_ecmult_gen_kb in 2) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=2 -DCOMB_TEETH=5" @@ -375,7 +375,7 @@ case $set_ecmult_gen_kb in SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=43 -DCOMB_TEETH=6" ;; *) - AC_MSG_ERROR(['ecmult gen table size not 2, 22, 86 or "auto"']) + AC_MSG_ERROR(['ecmult gen table size not 2, 22 or 86']) ;; esac @@ -426,12 +426,7 @@ fi ### Check for --enable-experimental if necessary ### -if test x"$enable_experimental" = x"yes"; then - AC_MSG_NOTICE([******]) - AC_MSG_NOTICE([WARNING: experimental build]) - AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) - AC_MSG_NOTICE([******]) -else +if test x"$enable_experimental" = x"no"; then if test x"$set_asm" = x"arm32"; then AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.]) fi @@ -492,3 +487,17 @@ echo " CPPFLAGS = $CPPFLAGS" echo " SECP_CFLAGS = $SECP_CFLAGS" echo " CFLAGS = $CFLAGS" echo " LDFLAGS = $LDFLAGS" + +if test x"$print_msan_notice" = x"yes"; then + echo + echo "Note:" + echo " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to SECP_CFLAGS" + echo " to avoid false positives in ctime_tests. Pass --disable-ctime-tests to avoid this." +fi + +if test x"$enable_experimental" = x"yes"; then + echo + echo "WARNING: Experimental build" + echo " Experimental features do not have stable APIs or properties, and may not be safe for" + echo " production use." +fi 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..8d5d14bdaf 100644 --- a/src/secp256k1/examples/schnorr.c +++ b/src/secp256k1/examples/schnorr.c @@ -18,9 +18,9 @@ #include "examples_util.h" int main(void) { - unsigned char msg[12] = "Hello World!"; + unsigned char msg[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; unsigned char msg_hash[32]; - unsigned char tag[17] = "my_fancy_protocol"; + unsigned char tag[] = {'m', 'y', '_', 'f', 'a', 'n', 'c', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l'}; unsigned char seckey[32]; unsigned char randomize[32]; unsigned char auxiliary_rand[32]; @@ -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/include/secp256k1_ellswift.h b/src/secp256k1/include/secp256k1_ellswift.h index ae37287f82..0d1293e94f 100644 --- a/src/secp256k1/include/secp256k1_ellswift.h +++ b/src/secp256k1/include/secp256k1_ellswift.h @@ -35,7 +35,7 @@ extern "C" { * * If the Y coordinate is relevant, it is given the same parity as t. * - * Changes w.r.t. the the paper: + * Changes w.r.t. the paper: * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point * at infinity in the paper. Here they are remapped to finite points. * - The paper uses an additional encoding bit for the parity of y. Here the diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h index 6be96eacbe..3c3acdaf8c 100644 --- a/src/secp256k1/src/modules/ecdh/tests_impl.h +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -56,7 +56,7 @@ static void test_ecdh_generator_basepoint(void) { size_t point_ser_len = sizeof(point_ser); secp256k1_scalar s; - random_scalar_order(&s); + testutil_random_scalar_order(&s); secp256k1_scalar_get_b32(s_b32, &s); CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1); @@ -95,7 +95,7 @@ static void test_bad_scalar(void) { secp256k1_pubkey point; /* Create random point */ - random_scalar_order(&rand); + testutil_random_scalar_order(&rand); secp256k1_scalar_get_b32(s_rand, &rand); CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1); @@ -127,7 +127,7 @@ static void test_result_basepoint(void) { CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1); for (i = 0; i < 2 * COUNT; i++) { - random_scalar_order(&rand); + testutil_random_scalar_order(&rand); secp256k1_scalar_get_b32(s, &rand); secp256k1_scalar_inverse(&rand, &rand); secp256k1_scalar_get_b32(s_inv, &rand); diff --git a/src/secp256k1/src/modules/ellswift/tests_impl.h b/src/secp256k1/src/modules/ellswift/tests_impl.h index f96e3a1268..3c314c9b50 100644 --- a/src/secp256k1/src/modules/ellswift/tests_impl.h +++ b/src/secp256k1/src/modules/ellswift/tests_impl.h @@ -229,9 +229,9 @@ void run_ellswift_tests(void) { secp256k1_ge g, g2; secp256k1_pubkey pubkey, pubkey2; /* Generate random public key and random randomizer. */ - random_group_element_test(&g); + testutil_random_ge_test(&g); secp256k1_pubkey_save(&pubkey, &g); - secp256k1_testrand256(rnd32); + testrand256(rnd32); /* Convert the public key to ElligatorSwift and back. */ secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32); secp256k1_ellswift_decode(CTX, &pubkey2, ell64); @@ -249,8 +249,8 @@ void run_ellswift_tests(void) { unsigned char ell64[64]; int ret; /* Generate random secret key and random randomizer. */ - if (i & 1) secp256k1_testrand256_test(auxrnd32); - random_scalar_order_test(&sec); + if (i & 1) testrand256_test(auxrnd32); + testutil_random_scalar_order_test(&sec); secp256k1_scalar_get_b32(sec32, &sec); /* Construct ElligatorSwift-encoded public keys for that key. */ ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL); @@ -271,11 +271,11 @@ void run_ellswift_tests(void) { secp256k1_pubkey pub; int ret; /* Generate random secret key. */ - random_scalar_order_test(&sec); + testutil_random_scalar_order_test(&sec); secp256k1_scalar_get_b32(sec32, &sec); /* Generate random ElligatorSwift encoding for the remote key and decode it. */ - secp256k1_testrand256_test(ell64); - secp256k1_testrand256_test(ell64 + 32); + testrand256_test(ell64); + testrand256_test(ell64 + 32); secp256k1_ellswift_decode(CTX, &pub, ell64); secp256k1_pubkey_load(CTX, &dec, &pub); secp256k1_gej_set_ge(&decj, &dec); @@ -313,18 +313,18 @@ void run_ellswift_tests(void) { data = NULL; } else { hash_function = secp256k1_ellswift_xdh_hash_function_prefix; - secp256k1_testrand256_test(prefix64); - secp256k1_testrand256_test(prefix64 + 32); + testrand256_test(prefix64); + testrand256_test(prefix64 + 32); data = prefix64; } /* Generate random secret keys and random randomizers. */ - secp256k1_testrand256_test(auxrnd32a); - secp256k1_testrand256_test(auxrnd32b); - random_scalar_order_test(&seca); + testrand256_test(auxrnd32a); + testrand256_test(auxrnd32b); + testutil_random_scalar_order_test(&seca); /* Draw secb uniformly at random to make sure that the secret keys * differ */ - random_scalar_order(&secb); + testutil_random_scalar_order(&secb); secp256k1_scalar_get_b32(sec32a, &seca); secp256k1_scalar_get_b32(sec32b, &secb); @@ -349,13 +349,13 @@ void run_ellswift_tests(void) { /* Verify that the shared secret doesn't match if other side's public key is incorrect. */ /* For A (using a bad public key for B): */ memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad)); - secp256k1_testrand_flip(ell64b_bad, sizeof(ell64b_bad)); + testrand_flip(ell64b_bad, sizeof(ell64b_bad)); ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); /* For B (using a bad public key for A): */ memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad)); - secp256k1_testrand_flip(ell64a_bad, sizeof(ell64a_bad)); + testrand_flip(ell64a_bad, sizeof(ell64a_bad)); ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); CHECK(ret); CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); @@ -363,12 +363,12 @@ void run_ellswift_tests(void) { /* Verify that the shared secret doesn't match if the private key is incorrect. */ /* For A: */ memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad)); - secp256k1_testrand_flip(sec32a_bad, sizeof(sec32a_bad)); + testrand_flip(sec32a_bad, sizeof(sec32a_bad)); ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data); CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); /* For B: */ memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad)); - secp256k1_testrand_flip(sec32b_bad, sizeof(sec32b_bad)); + testrand_flip(sec32b_bad, sizeof(sec32b_bad)); ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data); CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); @@ -376,7 +376,7 @@ void run_ellswift_tests(void) { /* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */ /* For A (changing B's public key): */ memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad)); - secp256k1_testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad)); + testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad)); ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad); CHECK(ret); ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); @@ -384,7 +384,7 @@ void run_ellswift_tests(void) { CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); /* For B (changing A's public key): */ memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad)); - secp256k1_testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad)); + testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad)); ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad); CHECK(ret); ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); @@ -406,9 +406,9 @@ void run_ellswift_tests(void) { /* Test hash initializers. */ { secp256k1_sha256 sha, sha_optimized; - static const unsigned char encode_tag[25] = "secp256k1_ellswift_encode"; - static const unsigned char create_tag[25] = "secp256k1_ellswift_create"; - static const unsigned char bip324_tag[26] = "bip324_ellswift_xonly_ecdh"; + static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; + static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'}; + static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'}; /* Check that hash initialized by * secp256k1_ellswift_sha256_init_encode has the expected diff --git a/src/secp256k1/src/modules/extrakeys/tests_impl.h b/src/secp256k1/src/modules/extrakeys/tests_impl.h index 45521d1742..ab4ef4a74b 100644 --- a/src/secp256k1/src/modules/extrakeys/tests_impl.h +++ b/src/secp256k1/src/modules/extrakeys/tests_impl.h @@ -23,9 +23,9 @@ static void test_xonly_pubkey(void) { int pk_parity; int i; - secp256k1_testrand256(sk); + testrand256(sk); memset(ones32, 0xFF, 32); - secp256k1_testrand256(xy_sk); + testrand256(xy_sk); CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); @@ -95,7 +95,7 @@ static void test_xonly_pubkey(void) { * the curve) then xonly_pubkey_parse should fail as well. */ for (i = 0; i < COUNT; i++) { unsigned char rand33[33]; - secp256k1_testrand256(&rand33[1]); + testrand256(&rand33[1]); rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) { memset(&xonly_pk, 1, sizeof(xonly_pk)); @@ -152,8 +152,8 @@ static void test_xonly_pubkey_tweak(void) { int i; memset(overflows, 0xff, sizeof(overflows)); - secp256k1_testrand256(tweak); - secp256k1_testrand256(sk); + testrand256(tweak); + testrand256(sk); CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); @@ -190,7 +190,7 @@ static void test_xonly_pubkey_tweak(void) { /* Invalid pk with a valid tweak */ memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); - secp256k1_testrand256(tweak); + testrand256(tweak); CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak)); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); } @@ -209,8 +209,8 @@ static void test_xonly_pubkey_tweak_check(void) { unsigned char tweak[32]; memset(overflows, 0xff, sizeof(overflows)); - secp256k1_testrand256(tweak); - secp256k1_testrand256(sk); + testrand256(tweak); + testrand256(sk); CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); @@ -256,7 +256,7 @@ static void test_xonly_pubkey_tweak_recursive(void) { unsigned char tweak[N_PUBKEYS - 1][32]; int i; - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1); /* Add tweaks */ for (i = 0; i < N_PUBKEYS - 1; i++) { @@ -292,7 +292,7 @@ static void test_keypair(void) { memset(overflows, 0xFF, sizeof(overflows)); /* Test keypair_create */ - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); @@ -311,7 +311,7 @@ static void test_keypair(void) { CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); /* Test keypair_pub */ - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair)); @@ -330,7 +330,7 @@ static void test_keypair(void) { CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); /** Test keypair_xonly_pub **/ - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair)); @@ -353,7 +353,7 @@ static void test_keypair(void) { CHECK(pk_parity == pk_parity_tmp); /* Test keypair_seckey */ - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair)); @@ -381,8 +381,8 @@ static void test_keypair_add(void) { int i; CHECK(sizeof(zeros96) == sizeof(keypair)); - secp256k1_testrand256(sk); - secp256k1_testrand256(tweak); + testrand256(sk); + testrand256(tweak); memset(overflows, 0xFF, 32); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); @@ -407,7 +407,7 @@ static void test_keypair_add(void) { for (i = 0; i < COUNT; i++) { secp256k1_scalar scalar_tweak; secp256k1_keypair keypair_tmp; - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); memcpy(&keypair_tmp, &keypair, sizeof(keypair)); /* Because sk may be negated before adding, we need to try with tweak = @@ -423,7 +423,7 @@ static void test_keypair_add(void) { /* Invalid keypair with a valid tweak */ memset(&keypair, 0, sizeof(keypair)); - secp256k1_testrand256(tweak); + testrand256(tweak); CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); /* Only seckey part of keypair invalid */ @@ -446,7 +446,7 @@ static void test_keypair_add(void) { unsigned char sk32[32]; int pk_parity; - secp256k1_testrand256(tweak); + testrand256(tweak); CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h index 728ccfed8d..7a28a3ce65 100644 --- a/src/secp256k1/src/modules/recovery/tests_impl.h +++ b/src/secp256k1/src/modules/recovery/tests_impl.h @@ -25,7 +25,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c } /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ memset(nonce32, 1, 32); - return secp256k1_testrand_bits(1); + return testrand_bits(1); } static void test_ecdsa_recovery_api(void) { @@ -106,8 +106,8 @@ static void test_ecdsa_recovery_end_to_end(void) { /* Generate a random key and message. */ { secp256k1_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); secp256k1_scalar_get_b32(message, &msg); } @@ -141,7 +141,7 @@ static void test_ecdsa_recovery_end_to_end(void) { CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); /* Serialize/destroy/parse signature and verify again. */ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); - sig[secp256k1_testrand_bits(6)] += 1 + secp256k1_testrand_int(255); + sig[testrand_bits(6)] += 1 + testrand_int(255); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0); diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h index 26727e4651..57f7eadd3c 100644 --- a/src/secp256k1/src/modules/schnorrsig/main_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h @@ -45,7 +45,7 @@ static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 * /* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340 * by using the correct tagged hash function. */ -static const unsigned char bip340_algo[13] = "BIP0340/nonce"; +static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; diff --git a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h index bc31d81107..601b54975d 100644 --- a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -104,7 +104,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons while (e_count_done < EXHAUSTIVE_TEST_ORDER) { secp256k1_scalar e; unsigned char msg32[32]; - secp256k1_testrand256(msg32); + testrand256(msg32); secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { @@ -120,7 +120,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && (s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); } else { - secp256k1_testrand256(sig64 + 32); + testrand256(sig64 + 32); expect_valid = 0; } valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]); @@ -161,7 +161,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign /* Generate random messages until all challenges have been tried. */ while (e_count_done < EXHAUSTIVE_TEST_ORDER) { secp256k1_scalar e; - secp256k1_testrand256(msg32); + testrand256(msg32); secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h index 8ada90a87b..2d716a01f8 100644 --- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h @@ -15,15 +15,15 @@ static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { unsigned char nonces[2][32]; CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); - secp256k1_testrand_flip(args[n_flip], n_bytes); + testrand_flip(args[n_flip], n_bytes); CHECK(nonce_function_bip340(nonces[1], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0); } static void run_nonce_function_bip340_tests(void) { - unsigned char tag[13] = "BIP0340/nonce"; - unsigned char aux_tag[11] = "BIP0340/aux"; - unsigned char algo[13] = "BIP0340/nonce"; + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'}; + unsigned char algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; size_t algolen = sizeof(algo); secp256k1_sha256 sha; secp256k1_sha256 sha_optimized; @@ -50,10 +50,10 @@ static void run_nonce_function_bip340_tests(void) { secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); test_sha256_eq(&sha, &sha_optimized); - secp256k1_testrand256(msg); - secp256k1_testrand256(key); - secp256k1_testrand256(pk); - secp256k1_testrand256(aux_rand); + testrand256(msg); + testrand256(key); + testrand256(pk); + testrand256(aux_rand); /* Check that a bitflip in an argument results in different nonces. */ args[0] = msg; @@ -76,12 +76,12 @@ static void run_nonce_function_bip340_tests(void) { CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0); CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); /* Other algo is fine */ - secp256k1_testrand_bytes_test(algo, algolen); + testrand_bytes_test(algo, algolen); CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); for (i = 0; i < COUNT; i++) { unsigned char nonce2[32]; - uint32_t offset = secp256k1_testrand_int(msglen - 1); + uint32_t offset = testrand_int(msglen - 1); size_t msglen_tmp = (msglen + offset) % msglen; size_t algolen_tmp; @@ -90,7 +90,7 @@ static void run_nonce_function_bip340_tests(void) { CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); /* Different algolen gives different nonce */ - offset = secp256k1_testrand_int(algolen - 1); + offset = testrand_int(algolen - 1); algolen_tmp = (algolen + offset) % algolen; CHECK(nonce_function_bip340(nonce2, msg, msglen, key, pk, algo, algolen_tmp, NULL) == 1); CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); @@ -116,10 +116,10 @@ static void test_schnorrsig_api(void) { secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; - secp256k1_testrand256(sk1); - secp256k1_testrand256(sk2); - secp256k1_testrand256(sk3); - secp256k1_testrand256(msg); + testrand256(sk1); + testrand256(sk2); + testrand256(sk3); + testrand256(msg); CHECK(secp256k1_keypair_create(CTX, &keypairs[0], sk1) == 1); CHECK(secp256k1_keypair_create(CTX, &keypairs[1], sk2) == 1); CHECK(secp256k1_keypair_create(CTX, &keypairs[2], sk3) == 1); @@ -158,7 +158,7 @@ static void test_schnorrsig_api(void) { /* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the * expected state. */ static void test_schnorrsig_sha256_tagged(void) { - unsigned char tag[17] = "BIP0340/challenge"; + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}; secp256k1_sha256 sha; secp256k1_sha256 sha_optimized; @@ -806,15 +806,15 @@ static void test_schnorrsig_sign(void) { unsigned char sk[32]; secp256k1_xonly_pubkey pk; secp256k1_keypair keypair; - const unsigned char msg[32] = "this is a msg for a schnorrsig.."; + const unsigned char msg[] = {'t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'm', 's', 'g', ' ', 'f', 'o', 'r', ' ', 'a', ' ', 's', 'c', 'h', 'n', 'o', 'r', 'r', 's', 'i', 'g', '.', '.'}; unsigned char sig[64]; unsigned char sig2[64]; unsigned char zeros64[64] = { 0 }; secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; unsigned char aux_rand[32]; - secp256k1_testrand256(sk); - secp256k1_testrand256(aux_rand); + testrand256(sk); + testrand256(aux_rand); CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); @@ -861,12 +861,12 @@ static void test_schnorrsig_sign_verify(void) { secp256k1_xonly_pubkey pk; secp256k1_scalar s; - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); for (i = 0; i < N_SIGS; i++) { - secp256k1_testrand256(msg[i]); + testrand256(msg[i]); CHECK(secp256k1_schnorrsig_sign32(CTX, sig[i], msg[i], &keypair, NULL)); CHECK(secp256k1_schnorrsig_verify(CTX, sig[i], msg[i], sizeof(msg[i]), &pk)); } @@ -874,19 +874,19 @@ static void test_schnorrsig_sign_verify(void) { { /* Flip a few bits in the signature and in the message and check that * verify and verify_batch (TODO) fail */ - size_t sig_idx = secp256k1_testrand_int(N_SIGS); - size_t byte_idx = secp256k1_testrand_bits(5); - unsigned char xorbyte = secp256k1_testrand_int(254)+1; + size_t sig_idx = testrand_int(N_SIGS); + size_t byte_idx = testrand_bits(5); + unsigned char xorbyte = testrand_int(254)+1; sig[sig_idx][byte_idx] ^= xorbyte; CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); sig[sig_idx][byte_idx] ^= xorbyte; - byte_idx = secp256k1_testrand_bits(5); + byte_idx = testrand_bits(5); sig[sig_idx][32+byte_idx] ^= xorbyte; CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); sig[sig_idx][32+byte_idx] ^= xorbyte; - byte_idx = secp256k1_testrand_bits(5); + byte_idx = testrand_bits(5); msg[sig_idx][byte_idx] ^= xorbyte; CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); msg[sig_idx][byte_idx] ^= xorbyte; @@ -916,9 +916,9 @@ static void test_schnorrsig_sign_verify(void) { { /* Test varying message lengths */ unsigned char msg_large[32 * 8]; - uint32_t msglen = secp256k1_testrand_int(sizeof(msg_large)); + uint32_t msglen = testrand_int(sizeof(msg_large)); for (i = 0; i < sizeof(msg_large); i += 32) { - secp256k1_testrand256(&msg_large[i]); + testrand256(&msg_large[i]); } CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], msg_large, msglen, &keypair, NULL) == 1); CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 1); @@ -942,7 +942,7 @@ static void test_schnorrsig_taproot(void) { unsigned char sig[64]; /* Create output key */ - secp256k1_testrand256(sk); + testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); /* In actual taproot the tweak would be hash of internal_pk */ @@ -952,7 +952,7 @@ static void test_schnorrsig_taproot(void) { CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk_bytes, &output_pk) == 1); /* Key spend */ - secp256k1_testrand256(msg); + testrand256(msg); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); /* Verify key spend */ CHECK(secp256k1_xonly_pubkey_parse(CTX, &output_pk, output_pk_bytes) == 1); diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index 7a32769408..72d725a74e 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -76,7 +76,7 @@ const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_stati /* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. * - * This is intended for "context" functions such as secp256k1_context_clone. Function which need specific + * This is intended for "context" functions such as secp256k1_context_clone. Functions that need specific * features of a context should still check for these features directly. For example, a function that needs * ecmult_gen should directly check for the existence of the ecmult_gen context. */ static int secp256k1_context_is_proper(const secp256k1_context* ctx) { @@ -544,7 +544,7 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc break; } is_nonce_valid = secp256k1_scalar_set_b32_seckey(&non, nonce32); - /* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */ + /* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */ secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); if (is_nonce_valid) { ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h index 721099d039..3c1ed3d45d 100644 --- a/src/secp256k1/src/testrand.h +++ b/src/secp256k1/src/testrand.h @@ -12,37 +12,37 @@ /* A non-cryptographic RNG used only for test infrastructure. */ /** Seed the pseudorandom number generator for testing. */ -SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16); +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16); /** Generate a pseudorandom number in the range [0..2**32-1]. */ -SECP256K1_INLINE static uint32_t secp256k1_testrand32(void); +SECP256K1_INLINE static uint32_t testrand32(void); /** Generate a pseudorandom number in the range [0..2**64-1]. */ -SECP256K1_INLINE static uint64_t secp256k1_testrand64(void); +SECP256K1_INLINE static uint64_t testrand64(void); /** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or * more. */ -SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits); +SECP256K1_INLINE static uint64_t testrand_bits(int bits); /** Generate a pseudorandom number in the range [0..range-1]. */ -static uint32_t secp256k1_testrand_int(uint32_t range); +static uint32_t testrand_int(uint32_t range); /** Generate a pseudorandom 32-byte array. */ -static void secp256k1_testrand256(unsigned char *b32); +static void testrand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ -static void secp256k1_testrand256_test(unsigned char *b32); +static void testrand256_test(unsigned char *b32); /** Generate pseudorandom bytes with long sequences of zero and one bits. */ -static void secp256k1_testrand_bytes_test(unsigned char *bytes, size_t len); +static void testrand_bytes_test(unsigned char *bytes, size_t len); /** Flip a single random bit in a byte array */ -static void secp256k1_testrand_flip(unsigned char *b, size_t len); +static void testrand_flip(unsigned char *b, size_t len); /** Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL. */ -static void secp256k1_testrand_init(const char* hexseed); +static void testrand_init(const char* hexseed); /** Print final test information. */ -static void secp256k1_testrand_finish(void); +static void testrand_finish(void); #endif /* SECP256K1_TESTRAND_H */ diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h index fe97620435..b84f5730a9 100644 --- a/src/secp256k1/src/testrand_impl.h +++ b/src/secp256k1/src/testrand_impl.h @@ -17,8 +17,8 @@ static uint64_t secp256k1_test_state[4]; -SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16) { - static const unsigned char PREFIX[19] = "secp256k1 test init"; +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) { + static const unsigned char PREFIX[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', ' ', 't', 'e', 's', 't', ' ', 'i', 'n', 'i', 't'}; unsigned char out32[32]; secp256k1_sha256 hash; int i; @@ -40,7 +40,7 @@ SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } -SECP256K1_INLINE static uint64_t secp256k1_testrand64(void) { +SECP256K1_INLINE static uint64_t testrand64(void) { /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */ const uint64_t result = rotl(secp256k1_test_state[0] + secp256k1_test_state[3], 23) + secp256k1_test_state[0]; const uint64_t t = secp256k1_test_state[1] << 17; @@ -53,16 +53,16 @@ SECP256K1_INLINE static uint64_t secp256k1_testrand64(void) { return result; } -SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits) { +SECP256K1_INLINE static uint64_t testrand_bits(int bits) { if (bits == 0) return 0; - return secp256k1_testrand64() >> (64 - bits); + return testrand64() >> (64 - bits); } -SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) { - return secp256k1_testrand64() >> 32; +SECP256K1_INLINE static uint32_t testrand32(void) { + return testrand64() >> 32; } -static uint32_t secp256k1_testrand_int(uint32_t range) { +static uint32_t testrand_int(uint32_t range) { uint32_t mask = 0; uint32_t range_copy; /* Reduce range by 1, changing its meaning to "maximum value". */ @@ -76,15 +76,15 @@ static uint32_t secp256k1_testrand_int(uint32_t range) { } /* Generation loop. */ while (1) { - uint32_t val = secp256k1_testrand64() & mask; + uint32_t val = testrand64() & mask; if (val <= range) return val; } } -static void secp256k1_testrand256(unsigned char *b32) { +static void testrand256(unsigned char *b32) { int i; for (i = 0; i < 4; ++i) { - uint64_t val = secp256k1_testrand64(); + uint64_t val = testrand64(); b32[0] = val; b32[1] = val >> 8; b32[2] = val >> 16; @@ -97,14 +97,14 @@ static void secp256k1_testrand256(unsigned char *b32) { } } -static void secp256k1_testrand_bytes_test(unsigned char *bytes, size_t len) { +static void testrand_bytes_test(unsigned char *bytes, size_t len) { size_t bits = 0; memset(bytes, 0, len); while (bits < len * 8) { int now; uint32_t val; - now = 1 + (secp256k1_testrand_bits(6) * secp256k1_testrand_bits(5) + 16) / 31; - val = secp256k1_testrand_bits(1); + now = 1 + (testrand_bits(6) * testrand_bits(5) + 16) / 31; + val = testrand_bits(1); while (now > 0 && bits < len * 8) { bytes[bits / 8] |= val << (bits % 8); now--; @@ -113,15 +113,15 @@ static void secp256k1_testrand_bytes_test(unsigned char *bytes, size_t len) { } } -static void secp256k1_testrand256_test(unsigned char *b32) { - secp256k1_testrand_bytes_test(b32, 32); +static void testrand256_test(unsigned char *b32) { + testrand_bytes_test(b32, 32); } -static void secp256k1_testrand_flip(unsigned char *b, size_t len) { - b[secp256k1_testrand_int(len)] ^= (1 << secp256k1_testrand_bits(3)); +static void testrand_flip(unsigned char *b, size_t len) { + b[testrand_int(len)] ^= (1 << testrand_bits(3)); } -static void secp256k1_testrand_init(const char* hexseed) { +static void testrand_init(const char* hexseed) { unsigned char seed16[16] = {0}; if (hexseed && strlen(hexseed) != 0) { int pos = 0; @@ -155,12 +155,12 @@ static void secp256k1_testrand_init(const char* hexseed) { } printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); - secp256k1_testrand_seed(seed16); + testrand_seed(seed16); } -static void secp256k1_testrand_finish(void) { +static void testrand_finish(void) { unsigned char run32[32]; - secp256k1_testrand256(run32); + testrand256(run32); printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); } diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index dab47608c2..70c15f870b 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -96,122 +96,6 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { (*p)--; } -static void random_field_element_magnitude(secp256k1_fe *fe, int m) { - secp256k1_fe zero; - int n = secp256k1_testrand_int(m + 1); - secp256k1_fe_normalize(fe); - if (n == 0) { - return; - } - secp256k1_fe_clear(&zero); - secp256k1_fe_negate(&zero, &zero, 0); - secp256k1_fe_mul_int_unchecked(&zero, n - 1); - secp256k1_fe_add(fe, &zero); -#ifdef VERIFY - CHECK(fe->magnitude == n); -#endif -} - -static void random_fe_test(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_testrand256_test(bin); - if (secp256k1_fe_set_b32_limit(x, bin)) { - return; - } - } while(1); -} - -static void random_fe_non_zero_test(secp256k1_fe *fe) { - do { - random_fe_test(fe); - } while(secp256k1_fe_is_zero(fe)); -} - -static void random_fe_magnitude(secp256k1_fe *fe) { - random_field_element_magnitude(fe, 8); -} - -static void random_ge_x_magnitude(secp256k1_ge *ge) { - random_field_element_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX); -} - -static void random_ge_y_magnitude(secp256k1_ge *ge) { - random_field_element_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX); -} - -static void random_gej_x_magnitude(secp256k1_gej *gej) { - random_field_element_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); -} - -static void random_gej_y_magnitude(secp256k1_gej *gej) { - random_field_element_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); -} - -static void random_gej_z_magnitude(secp256k1_gej *gej) { - random_field_element_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); -} - -static void random_group_element_test(secp256k1_ge *ge) { - secp256k1_fe fe; - do { - random_fe_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_testrand_bits(1))) { - secp256k1_fe_normalize(&ge->y); - break; - } - } while(1); - ge->infinity = 0; -} - -static void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { - secp256k1_fe z2, z3; - random_fe_non_zero_test(&gej->z); - secp256k1_fe_sqr(&z2, &gej->z); - secp256k1_fe_mul(&z3, &z2, &gej->z); - secp256k1_fe_mul(&gej->x, &ge->x, &z2); - secp256k1_fe_mul(&gej->y, &ge->y, &z3); - gej->infinity = ge->infinity; -} - -static void random_gej_test(secp256k1_gej *gej) { - secp256k1_ge ge; - random_group_element_test(&ge); - random_group_element_jacobian_test(gej, &ge); -} - -static void random_scalar_order_test(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - secp256k1_testrand256_test(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); -} - -static void random_scalar_order(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - secp256k1_testrand256(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); -} - -static void random_scalar_order_b32(unsigned char *b32) { - secp256k1_scalar num; - random_scalar_order(&num); - secp256k1_scalar_get_b32(b32, &num); -} - static void run_xoshiro256pp_tests(void) { { size_t i; @@ -233,9 +117,9 @@ static void run_xoshiro256pp_tests(void) { 0x4C, 0xCC, 0xC1, 0x18, 0xB2, 0xD8, 0x8F, 0xEF, 0x43, 0x26, 0x15, 0x57, 0x37, 0x00, 0xEF, 0x30, }; - secp256k1_testrand_seed(seed16); + testrand_seed(seed16); for (i = 0; i < 17; i++) { - secp256k1_testrand256(buf32); + testrand256(buf32); } CHECK(secp256k1_memcmp_var(buf32, buf32_expected, sizeof(buf32)) == 0); } @@ -444,14 +328,14 @@ static void run_proper_context_tests(int use_prealloc) { CHECK(context_eq(my_ctx, my_ctx_fresh)); /*** attempt to use them ***/ - random_scalar_order_test(&msg); - random_scalar_order_test(&key); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); /* obtain a working nonce */ do { - random_scalar_order_test(&nonce); + testutil_random_scalar_order_test(&nonce); } while(!secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try signing */ @@ -608,7 +492,7 @@ static void run_sha256_known_output_tests(void) { CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); /* 2. Run: split the input bytestrings randomly before writing */ if (strlen(inputs[i]) > 0) { - int split = secp256k1_testrand_int(strlen(inputs[i])); + int split = testrand_int(strlen(inputs[i])); secp256k1_sha256_initialize(&hasher); j = repeat[i]; while (j > 0) { @@ -769,7 +653,7 @@ static void run_hmac_sha256_tests(void) { secp256k1_hmac_sha256_finalize(&hasher, out); CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_testrand_int(strlen(inputs[i])); + int split = testrand_int(strlen(inputs[i])); secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); @@ -969,7 +853,7 @@ static void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* static void mutate_sign_signed30(secp256k1_modinv32_signed30* x) { int i; for (i = 0; i < 16; ++i) { - int pos = secp256k1_testrand_bits(3); + int pos = testrand_bits(3); if (x->v[pos] > 0 && x->v[pos + 1] <= 0x3fffffff) { x->v[pos] -= 0x40000000; x->v[pos + 1] += 1; @@ -1061,7 +945,7 @@ static void mutate_sign_signed62(secp256k1_modinv64_signed62* x) { static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); int i; for (i = 0; i < 8; ++i) { - int pos = secp256k1_testrand_bits(2); + int pos = testrand_bits(2); if (x->v[pos] > 0 && x->v[pos + 1] <= M62) { x->v[pos] -= (M62 + 1); x->v[pos + 1] += 1; @@ -1774,8 +1658,8 @@ static void run_modinv_tests(void) { /* generate random xd and md, so that md is odd, md>1, xd<md, and gcd(xd,md)=1 */ do { /* generate random xd and md (with many subsequent 0s and 1s) */ - secp256k1_testrand256_test((unsigned char*)xd); - secp256k1_testrand256_test((unsigned char*)md); + testrand256_test((unsigned char*)xd); + testrand256_test((unsigned char*)md); md[0] |= 1; /* modulus must be odd */ /* If modulus is 1, find another one. */ ok = md[0] != 1; @@ -1907,7 +1791,7 @@ static void run_int128_test_case(void) { int i; /* Generate 32-byte random value. */ - secp256k1_testrand256_test(buf); + testrand256_test(buf); /* Convert into 4 64-bit integers. */ for (i = 0; i < 4; ++i) { uint64_t vi = 0; @@ -2133,13 +2017,13 @@ static void scalar_test(void) { unsigned char c[32]; /* Set 's' to a random scalar, with value 'snum'. */ - random_scalar_order_test(&s); + testutil_random_scalar_order_test(&s); /* Set 's1' to a random scalar, with value 's1num'. */ - random_scalar_order_test(&s1); + testutil_random_scalar_order_test(&s1); /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ - random_scalar_order_test(&s2); + testutil_random_scalar_order_test(&s2); secp256k1_scalar_get_b32(c, &s2); { @@ -2167,7 +2051,7 @@ static void scalar_test(void) { while (i < 256) { secp256k1_scalar t; int j; - int now = secp256k1_testrand_int(15) + 1; + int now = testrand_int(15) + 1; if (now + i > 256) { now = 256 - i; } @@ -2194,7 +2078,7 @@ static void scalar_test(void) { secp256k1_scalar b; int i; /* Test add_bit. */ - int bit = secp256k1_testrand_bits(8); + int bit = testrand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); for (i = 0; i < bit; i++) { @@ -2287,7 +2171,7 @@ static void run_scalar_set_b32_seckey_tests(void) { secp256k1_scalar s2; /* Usually set_b32 and set_b32_seckey give the same result */ - random_scalar_order_b32(b32); + testutil_random_scalar_order_b32(b32); secp256k1_scalar_set_b32(&s1, b32, NULL); CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 1); CHECK(secp256k1_scalar_eq(&s1, &s2) == 1); @@ -2948,7 +2832,7 @@ static void run_scalar_tests(void) { static void random_fe_non_square(secp256k1_fe *ns) { secp256k1_fe r; - random_fe_non_zero(ns); + testutil_random_fe_non_zero(ns); if (secp256k1_fe_sqrt(&r, ns)) { secp256k1_fe_negate(ns, ns, 1); } @@ -3125,12 +3009,12 @@ static void run_field_misc(void) { for (i = 0; i < 1000 * COUNT; i++) { secp256k1_fe_storage xs, ys, zs; if (i & 1) { - random_fe(&x); + testutil_random_fe(&x); } else { - random_fe_test(&x); + testutil_random_fe_test(&x); } - random_fe_non_zero(&y); - v = secp256k1_testrand_bits(15); + testutil_random_fe_non_zero(&y); + v = testrand_bits(15); /* Test that fe_add_int is equivalent to fe_set_int + fe_add. */ secp256k1_fe_set_int(&q, v); /* q = v */ z = x; /* z = x */ @@ -3268,14 +3152,14 @@ static void run_fe_mul(void) { int i; for (i = 0; i < 100 * COUNT; ++i) { secp256k1_fe a, b, c, d; - random_fe(&a); - random_fe_magnitude(&a); - random_fe(&b); - random_fe_magnitude(&b); - random_fe_test(&c); - random_fe_magnitude(&c); - random_fe_test(&d); - random_fe_magnitude(&d); + testutil_random_fe(&a); + testutil_random_fe_magnitude(&a, 8); + testutil_random_fe(&b); + testutil_random_fe_magnitude(&b, 8); + testutil_random_fe_test(&c); + testutil_random_fe_magnitude(&c, 8); + testutil_random_fe_test(&d); + testutil_random_fe_magnitude(&d, 8); test_fe_mul(&a, &a, 1); test_fe_mul(&c, &c, 1); test_fe_mul(&a, &b, 0); @@ -3297,7 +3181,7 @@ static void run_sqr(void) { secp256k1_fe_normalize(&x); /* Check that (x+y)*(x-y) = x^2 - y*2 for some random values y */ - random_fe_test(&y); + testutil_random_fe_test(&y); lhs = x; secp256k1_fe_add(&lhs, &y); /* lhs = x+y */ @@ -3351,7 +3235,7 @@ static void run_sqrt(void) { int j; random_fe_non_square(&ns); for (j = 0; j < COUNT; j++) { - random_fe(&x); + testutil_random_fe(&x); secp256k1_fe_sqr(&s, &x); CHECK(secp256k1_fe_is_square_var(&s)); test_sqrt(&s, &x); @@ -3665,7 +3549,7 @@ static void run_inverse_tests(void) /* test 128*count random inputs; half with testrand256_test, half with testrand256 */ for (testrand = 0; testrand <= 1; ++testrand) { for (i = 0; i < 64 * COUNT; ++i) { - (testrand ? secp256k1_testrand256_test : secp256k1_testrand256)(b32); + (testrand ? testrand256_test : testrand256)(b32); secp256k1_scalar_set_b32(&x_scalar, b32, NULL); secp256k1_fe_set_b32_mod(&x_fe, b32); for (var = 0; var <= 1; ++var) { @@ -3731,8 +3615,8 @@ static void test_hsort(size_t element_len) { /* Test hsort with array of random length n */ for (i = 0; i < COUNT; i++) { - int n = secp256k1_testrand_int(NUM); - secp256k1_testrand_bytes_test(elements, n*element_len); + int n = testrand_int(NUM); + testrand_bytes_test(elements, n*element_len); secp256k1_hsort(elements, n, element_len, test_hsort_cmp, &data); test_hsort_is_sorted(elements, n, element_len); } @@ -3792,7 +3676,7 @@ static void test_ge(void) { for (i = 0; i < runs; i++) { int j, k; secp256k1_ge g; - random_group_element_test(&g); + testutil_random_ge_test(&g); if (i >= runs - 2) { secp256k1_ge_mul_lambda(&g, &ge[1]); CHECK(!secp256k1_ge_eq_var(&g, &ge[1])); @@ -3805,15 +3689,15 @@ static void test_ge(void) { secp256k1_ge_neg(&ge[3 + 4 * i], &g); secp256k1_ge_neg(&ge[4 + 4 * i], &g); secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); - random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); - random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); for (j = 0; j < 4; j++) { - random_ge_x_magnitude(&ge[1 + j + 4 * i]); - random_ge_y_magnitude(&ge[1 + j + 4 * i]); - random_gej_x_magnitude(&gej[1 + j + 4 * i]); - random_gej_y_magnitude(&gej[1 + j + 4 * i]); - random_gej_z_magnitude(&gej[1 + j + 4 * i]); + testutil_random_ge_x_magnitude(&ge[1 + j + 4 * i]); + testutil_random_ge_y_magnitude(&ge[1 + j + 4 * i]); + testutil_random_gej_x_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_y_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_z_magnitude(&gej[1 + j + 4 * i]); } for (j = 0; j < 4; ++j) { @@ -3828,14 +3712,14 @@ static void test_ge(void) { } /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ - random_fe_non_zero_test(&zf); - random_fe_magnitude(&zf); + testutil_random_fe_non_zero_test(&zf); + testutil_random_fe_magnitude(&zf, 8); secp256k1_fe_inv_var(&zfi3, &zf); secp256k1_fe_sqr(&zfi2, &zfi3); secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); /* Generate random r */ - random_fe_non_zero_test(&r); + testutil_random_fe_non_zero_test(&r); for (i1 = 0; i1 < 1 + 4 * runs; i1++) { int i2; @@ -3865,8 +3749,8 @@ static void test_ge(void) { secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); - random_ge_x_magnitude(&ge2_zfi); - random_ge_y_magnitude(&ge2_zfi); + testutil_random_ge_x_magnitude(&ge2_zfi); + testutil_random_ge_y_magnitude(&ge2_zfi); secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); } @@ -3922,7 +3806,7 @@ static void test_ge(void) { gej_shuffled[i] = gej[i]; } for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + secp256k1_testrand_int(4 * runs + 1 - i); + int swap = i + testrand_int(4 * runs + 1 - i); if (swap != i) { secp256k1_gej t = gej_shuffled[i]; gej_shuffled[i] = gej_shuffled[swap]; @@ -3942,7 +3826,7 @@ static void test_ge(void) { secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); for (i = 0; i < 4 * runs + 1; i++) { secp256k1_fe s; - random_fe_non_zero(&s); + testutil_random_fe_non_zero(&s); secp256k1_gej_rescale(&gej[i], &s); CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i])); } @@ -3975,7 +3859,7 @@ static void test_ge(void) { /* Test batch gej -> ge conversion with many infinities. */ for (i = 0; i < 4 * runs + 1; i++) { int odd; - random_group_element_test(&ge[i]); + testutil_random_ge_test(&ge[i]); odd = secp256k1_fe_is_odd(&ge[i].x); CHECK(odd == 0 || odd == 1); /* randomly set half the points to infinity */ @@ -4012,7 +3896,7 @@ static void test_intialized_inf(void) { secp256k1_fe zinv; /* Test that adding P+(-P) results in a fully initialized infinity*/ - random_group_element_test(&p); + testutil_random_ge_test(&p); secp256k1_gej_set_ge(&pj, &p); secp256k1_gej_neg(&npj, &pj); @@ -4125,14 +4009,14 @@ static void run_gej(void) { secp256k1_gej_set_infinity(&b); test_gej_cmov(&a, &b); - random_gej_test(&a); + testutil_random_gej_test(&a); test_gej_cmov(&a, &b); test_gej_cmov(&b, &a); b = a; test_gej_cmov(&a, &b); - random_gej_test(&b); + testutil_random_gej_test(&b); test_gej_cmov(&a, &b); test_gej_cmov(&b, &a); } @@ -4140,12 +4024,12 @@ static void run_gej(void) { /* Tests for secp256k1_gej_eq_var */ for (i = 0; i < COUNT; i++) { secp256k1_fe fe; - random_gej_test(&a); - random_gej_test(&b); + testutil_random_gej_test(&a); + testutil_random_gej_test(&b); CHECK(!secp256k1_gej_eq_var(&a, &b)); b = a; - random_fe_non_zero_test(&fe); + testutil_random_fe_non_zero_test(&fe); secp256k1_gej_rescale(&a, &fe); CHECK(secp256k1_gej_eq_var(&a, &b)); } @@ -4162,7 +4046,7 @@ static void test_ec_combine(void) { int i; for (i = 1; i <= 6; i++) { secp256k1_scalar s; - random_scalar_order_test(&s); + testutil_random_scalar_order_test(&s); secp256k1_scalar_add(&sum, &sum, &s); secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s); secp256k1_ge_set_gej(&Q, &Qj); @@ -4222,7 +4106,7 @@ static void run_group_decompress(void) { int i; for (i = 0; i < COUNT * 4; i++) { secp256k1_fe fe; - random_fe_test(&fe); + testutil_random_fe_test(&fe); test_group_decompress(&fe); } } @@ -4370,7 +4254,7 @@ static void test_point_times_order(const secp256k1_gej *point) { secp256k1_ge res3; unsigned char pub[65]; size_t psize = 65; - random_scalar_order_test(&x); + testutil_random_scalar_order_test(&x); secp256k1_scalar_negate(&nx, &x); secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ @@ -4431,13 +4315,13 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) { secp256k1_gej pj, p1j, p2j, ptj; /* Generate random n1,n2 such that n1+n2 = -target. */ - random_scalar_order_test(&n1); + testutil_random_scalar_order_test(&n1); secp256k1_scalar_add(&n2, &n1, target); secp256k1_scalar_negate(&n2, &n2); /* Generate a random input point. */ if (mode != 0) { - random_group_element_test(&p); + testutil_random_ge_test(&p); secp256k1_gej_set_ge(&pj, &p); } @@ -4529,8 +4413,8 @@ static void ecmult_const_commutativity(void) { secp256k1_gej res2; secp256k1_ge mid1; secp256k1_ge mid2; - random_scalar_order_test(&a); - random_scalar_order_test(&b); + testutil_random_scalar_order_test(&a); + testutil_random_scalar_order_test(&b); secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); @@ -4551,9 +4435,9 @@ static void ecmult_const_mult_zero_one(void) { secp256k1_ge point; secp256k1_ge inf; - random_scalar_order_test(&s); + testutil_random_scalar_order_test(&s); secp256k1_scalar_negate(&negone, &secp256k1_scalar_one); - random_group_element_test(&point); + testutil_random_ge_test(&point); secp256k1_ge_set_infinity(&inf); /* 0*point */ @@ -4606,7 +4490,7 @@ static void ecmult_const_edges(void) { secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); } - random_group_element_test(&point); + testutil_random_ge_test(&point); secp256k1_ecmult_const(&res, &point, &q); ecmult_const_check_result(&point, &q, &res); } @@ -4623,12 +4507,12 @@ static void ecmult_const_mult_xonly(void) { secp256k1_scalar q; int res; /* Random base point. */ - random_group_element_test(&base); + testutil_random_ge_test(&base); /* Random scalar to multiply it with. */ - random_scalar_order_test(&q); + testutil_random_scalar_order_test(&q); /* If i is odd, n=d*base.x for random non-zero d */ if (i & 1) { - random_fe_non_zero_test(&d); + testutil_random_fe_non_zero_test(&d); secp256k1_fe_mul(&n, &base.x, &d); } else { n = base.x; @@ -4650,14 +4534,14 @@ static void ecmult_const_mult_xonly(void) { secp256k1_fe x, n, d, r; int res; secp256k1_scalar q; - random_scalar_order_test(&q); + testutil_random_scalar_order_test(&q); /* Generate random X coordinate not on the curve. */ do { - random_fe_test(&x); + testutil_random_fe_test(&x); } while (secp256k1_ge_x_on_curve_var(&x)); /* If i is odd, n=d*x for random non-zero d. */ if (i & 1) { - random_fe_non_zero_test(&d); + testutil_random_fe_non_zero_test(&d); secp256k1_fe_mul(&n, &x, &d); } else { n = x; @@ -4740,10 +4624,10 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi for (ncount = 0; ncount < COUNT; ncount++) { secp256k1_ge ptg; secp256k1_gej ptgj; - random_scalar_order(&sc[0]); - random_scalar_order(&sc[1]); + testutil_random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[1]); - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); secp256k1_gej_set_ge(&ptgj, &ptg); pt[0] = ptg; pt[1] = secp256k1_ge_const_g; @@ -4780,7 +4664,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi for (j = 0; j < 3; j++) { for (i = 0; i < 32; i++) { - random_scalar_order(&sc[i]); + testutil_random_scalar_order(&sc[i]); secp256k1_ge_set_infinity(&pt[i]); } CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); @@ -4789,7 +4673,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi for (j = 0; j < 3; j++) { for (i = 0; i < 32; i++) { - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); pt[i] = ptg; secp256k1_scalar_set_int(&sc[i], 0); } @@ -4798,9 +4682,9 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi } for (j = 0; j < 3; j++) { - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); for (i = 0; i < 16; i++) { - random_scalar_order(&sc[2*i]); + testutil_random_scalar_order(&sc[2*i]); secp256k1_scalar_negate(&sc[2*i + 1], &sc[2*i]); pt[2 * i] = ptg; pt[2 * i + 1] = ptg; @@ -4809,9 +4693,9 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); CHECK(secp256k1_gej_is_infinity(&r)); - random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[0]); for (i = 0; i < 16; i++) { - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); sc[2*i] = sc[0]; sc[2*i+1] = sc[0]; @@ -4823,13 +4707,13 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi CHECK(secp256k1_gej_is_infinity(&r)); } - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); secp256k1_scalar_set_int(&sc[0], 0); pt[0] = ptg; for (i = 1; i < 32; i++) { pt[i] = ptg; - random_scalar_order(&sc[i]); + testutil_random_scalar_order(&sc[i]); secp256k1_scalar_add(&sc[0], &sc[0], &sc[i]); secp256k1_scalar_negate(&sc[i], &sc[i]); } @@ -4843,11 +4727,11 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi size_t i; secp256k1_gej_set_infinity(&r); - random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[0]); for (i = 0; i < 20; i++) { secp256k1_ge ptg; sc[i] = sc[0]; - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); pt[i] = ptg; secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL); } @@ -4865,9 +4749,9 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi secp256k1_scalar rs; secp256k1_scalar_set_int(&rs, 0); - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); for (i = 0; i < 20; i++) { - random_scalar_order(&sc[i]); + testutil_random_scalar_order(&sc[i]); pt[i] = ptg; secp256k1_scalar_add(&rs, &rs, &sc[i]); } @@ -4880,8 +4764,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi /* Sanity check that zero scalars don't cause problems */ for (ncount = 0; ncount < 20; ncount++) { - random_scalar_order(&sc[ncount]); - random_group_element_test(&pt[ncount]); + testutil_random_scalar_order(&sc[ncount]); + testutil_random_ge_test(&pt[ncount]); } secp256k1_scalar_clear(&sc[0]); @@ -4902,7 +4786,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi secp256k1_ge ptg; secp256k1_gej ptgj; - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); secp256k1_gej_set_ge(&ptgj, &ptg); for(t0i = 0; t0i < TOP; t0i++) { @@ -4973,29 +4857,29 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { int i; /* Which multiplication function to use */ - int fn = secp256k1_testrand_int(3); + int fn = testrand_int(3); secp256k1_ecmult_multi_func ecmult_multi = fn == 0 ? secp256k1_ecmult_multi_var : fn == 1 ? secp256k1_ecmult_strauss_batch_single : secp256k1_ecmult_pippenger_batch_single; /* Simulate exponentially distributed num. */ - int num_bits = 2 + secp256k1_testrand_int(6); + int num_bits = 2 + testrand_int(6); /* Number of (scalar, point) inputs (excluding g). */ - int num = secp256k1_testrand_int((1 << num_bits) + 1); + int num = testrand_int((1 << num_bits) + 1); /* Number of those which are nonzero. */ - int num_nonzero = secp256k1_testrand_int(num + 1); + int num_nonzero = testrand_int(num + 1); /* Whether we're aiming to create an input with nonzero expected result. */ - int nonzero_result = secp256k1_testrand_bits(1); + int nonzero_result = testrand_bits(1); /* Whether we will provide nonzero g multiplicand. In some cases our hand * is forced here based on num_nonzero and nonzero_result. */ int g_nonzero = num_nonzero == 0 ? nonzero_result : num_nonzero == 1 && !nonzero_result ? 1 : - (int)secp256k1_testrand_bits(1); + (int)testrand_bits(1); /* Which g_scalar pointer to pass into ecmult_multi(). */ - const secp256k1_scalar* g_scalar_ptr = (g_nonzero || secp256k1_testrand_bits(1)) ? &g_scalar : NULL; + const secp256k1_scalar* g_scalar_ptr = (g_nonzero || testrand_bits(1)) ? &g_scalar : NULL; /* How many EC multiplications were performed in this function. */ int mults = 0; /* How many randomization steps to apply to the input list. */ - int rands = (int)secp256k1_testrand_bits(3); + int rands = (int)testrand_bits(3); if (rands > num_nonzero) rands = num_nonzero; secp256k1_gej_set_infinity(&expected); @@ -5004,11 +4888,11 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { if (g_nonzero) { /* If g_nonzero, set g_scalar to nonzero value r. */ - random_scalar_order_test(&g_scalar); + testutil_random_scalar_order_test(&g_scalar); if (!nonzero_result) { /* If expected=0 is desired, add a (a*r, -(1/a)*g) term to compensate. */ CHECK(num_nonzero > filled); - random_scalar_order_test(&sc_tmp); + testutil_random_scalar_order_test(&sc_tmp); secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp); secp256k1_scalar_negate(&sc_tmp, &sc_tmp); @@ -5020,8 +4904,8 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { if (nonzero_result && filled < num_nonzero) { /* If a nonzero result is desired, and there is space, add a random nonzero term. */ - random_scalar_order_test(&scalars[filled]); - random_group_element_test(&ge_tmp); + testutil_random_scalar_order_test(&scalars[filled]); + testutil_random_ge_test(&ge_tmp); secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); ++filled; } @@ -5040,12 +4924,12 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { /* Add entries to scalars,gejs so that there are num of them. All the added entries * either have scalar=0 or point=infinity, so these do not change the expected result. */ while (filled < num) { - if (secp256k1_testrand_bits(1)) { + if (testrand_bits(1)) { secp256k1_gej_set_infinity(&gejs[filled]); - random_scalar_order_test(&scalars[filled]); + testutil_random_scalar_order_test(&scalars[filled]); } else { secp256k1_scalar_set_int(&scalars[filled], 0); - random_group_element_test(&ge_tmp); + testutil_random_ge_test(&ge_tmp); secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); } ++filled; @@ -5059,7 +4943,7 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { secp256k1_scalar v, iv; /* Shuffle the entries. */ for (j = 0; j < num_nonzero; ++j) { - int k = secp256k1_testrand_int(num_nonzero - j); + int k = testrand_int(num_nonzero - j); if (k != 0) { secp256k1_gej gej = gejs[j]; secp256k1_scalar sc = scalars[j]; @@ -5079,7 +4963,7 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { } /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */ CHECK(num_nonzero >= 1); - random_scalar_order_test(&v); + testutil_random_scalar_order_test(&v); secp256k1_scalar_inverse(&iv, &v); secp256k1_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v); secp256k1_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL); @@ -5088,7 +4972,7 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { /* Shuffle all entries (0..num-1). */ for (i = 0; i < num; ++i) { - int j = secp256k1_testrand_int(num - i); + int j = testrand_int(num - i); if (j != 0) { secp256k1_gej gej = gejs[i]; secp256k1_scalar sc = scalars[i]; @@ -5118,8 +5002,8 @@ static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_mu ecmult_multi_data data; secp256k1_scratch *scratch_empty; - random_group_element_test(&pt); - random_scalar_order(&sc); + testutil_random_ge_test(&pt); + testutil_random_scalar_order(&sc); data.sc = ≻ data.pt = &pt; @@ -5150,7 +5034,7 @@ static void test_secp256k1_pippenger_bucket_window_inv(void) { * for a given scratch space. */ static void test_ecmult_multi_pippenger_max_points(void) { - size_t scratch_size = secp256k1_testrand_bits(8); + size_t scratch_size = testrand_bits(8); size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); secp256k1_scratch *scratch; size_t n_points_supported; @@ -5244,15 +5128,15 @@ static void test_ecmult_multi_batching(void) { secp256k1_gej_set_infinity(&r2); /* Get random scalars and group elements and compute result */ - random_scalar_order(&scG); + testutil_random_scalar_order(&scG); secp256k1_ecmult(&r2, &r2, &secp256k1_scalar_zero, &scG); for(i = 0; i < n_points; i++) { secp256k1_ge ptg; secp256k1_gej ptgj; - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); secp256k1_gej_set_ge(&ptgj, &ptg); pt[i] = ptg; - random_scalar_order(&sc[i]); + testutil_random_scalar_order(&sc[i]); secp256k1_ecmult(&ptgj, &ptgj, &sc[i], NULL); secp256k1_gej_add_var(&r2, &r2, &ptgj, NULL); } @@ -5464,7 +5348,7 @@ static void run_wnaf(void) { test_fixed_wnaf_small(); /* Random tests */ for (i = 0; i < COUNT; i++) { - random_scalar_order(&n); + testutil_random_scalar_order(&n); test_wnaf(&n, 4+(i%10)); test_fixed_wnaf(&n, 4 + (i % 10)); } @@ -5645,9 +5529,9 @@ static void test_ecmult_gen_blind(void) { secp256k1_gej pgej2; secp256k1_ge p; secp256k1_ge pge; - random_scalar_order_test(&key); + testutil_random_scalar_order_test(&key); secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key); - secp256k1_testrand256(seed32); + testrand256(seed32); b = CTX->ecmult_gen_ctx.scalar_offset; p = CTX->ecmult_gen_ctx.ge_offset; secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32); @@ -5741,7 +5625,7 @@ static void run_endomorphism_tests(void) { for (i = 0; i < 100U * COUNT; ++i) { secp256k1_scalar full; - random_scalar_order_test(&full); + testutil_random_scalar_order_test(&full); test_scalar_split(&full); } for (i = 0; i < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++i) { @@ -6327,7 +6211,7 @@ static void run_eckey_negate_test(void) { unsigned char seckey[32]; unsigned char seckey_tmp[32]; - random_scalar_order_b32(seckey); + testutil_random_scalar_order_b32(seckey); memcpy(seckey_tmp, seckey, 32); /* Verify negation changes the key and changes it back */ @@ -6351,7 +6235,7 @@ static void run_eckey_negate_test(void) { /* Negating an overflowing seckey fails and the seckey is zeroed. In this * test, the seckey has 16 random bytes to ensure that ec_seckey_negate * doesn't just set seckey to a constant value in case of failure. */ - random_scalar_order_b32(seckey); + testutil_random_scalar_order_b32(seckey); memset(seckey, 0xFF, 16); memset(seckey_tmp, 0, 32); CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0); @@ -6361,7 +6245,7 @@ static void run_eckey_negate_test(void) { static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { secp256k1_scalar nonce; do { - random_scalar_order_test(&nonce); + testutil_random_scalar_order_test(&nonce); } while(!secp256k1_ecdsa_sig_sign(&CTX->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } @@ -6373,11 +6257,11 @@ static void test_ecdsa_sign_verify(void) { secp256k1_scalar sigr, sigs; int getrec; int recid; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_testrand_bits(1); + getrec = testrand_bits(1); /* The specific way in which this conditional is written sidesteps a potential bug in clang. See the commit messages of the commit that introduced this comment for details. */ if (getrec) { @@ -6470,8 +6354,8 @@ static void test_ecdsa_end_to_end(void) { /* Generate a random key and message. */ { secp256k1_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); secp256k1_scalar_get_b32(message, &msg); } @@ -6481,7 +6365,7 @@ static void test_ecdsa_end_to_end(void) { CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); /* Verify exporting and importing public key. */ - CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyc, &pubkeyclen, &pubkey, secp256k1_testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyc, &pubkeyclen, &pubkey, testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); memset(&pubkey, 0, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); @@ -6493,19 +6377,19 @@ static void test_ecdsa_end_to_end(void) { CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); /* Verify private key import and export. */ - CHECK(ec_privkey_export_der(CTX, seckey, &seckeylen, privkey, secp256k1_testrand_bits(1) == 1)); + CHECK(ec_privkey_export_der(CTX, seckey, &seckeylen, privkey, testrand_bits(1) == 1)); CHECK(ec_privkey_import_der(CTX, privkey2, seckey, seckeylen) == 1); CHECK(secp256k1_memcmp_var(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (secp256k1_testrand_int(3) == 0) { + if (testrand_int(3) == 0) { int ret1; int ret2; int ret3; unsigned char rnd[32]; unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; - secp256k1_testrand256_test(rnd); + testrand256_test(rnd); memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_add(CTX, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, rnd); @@ -6522,14 +6406,14 @@ static void test_ecdsa_end_to_end(void) { } /* Optionally tweak the keys using multiplication. */ - if (secp256k1_testrand_int(3) == 0) { + if (testrand_int(3) == 0) { int ret1; int ret2; int ret3; unsigned char rnd[32]; unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; - secp256k1_testrand256_test(rnd); + testrand256_test(rnd); memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_mul(CTX, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, rnd); @@ -6591,7 +6475,7 @@ static void test_ecdsa_end_to_end(void) { /* Serialize/destroy/parse DER and verify again. */ siglen = 74; CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); - sig[secp256k1_testrand_int(siglen)] += 1 + secp256k1_testrand_int(255); + sig[testrand_int(siglen)] += 1 + testrand_int(255); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 0 || secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 0); } @@ -6601,23 +6485,23 @@ static void test_random_pubkeys(void) { secp256k1_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - size_t len = secp256k1_testrand_bits(2) == 0 ? 65 : 33; - if (secp256k1_testrand_bits(2) == 0) { - len = secp256k1_testrand_bits(6); + size_t len = testrand_bits(2) == 0 ? 65 : 33; + if (testrand_bits(2) == 0) { + len = testrand_bits(6); } if (len == 65) { - in[0] = secp256k1_testrand_bits(1) ? 4 : (secp256k1_testrand_bits(1) ? 6 : 7); + in[0] = testrand_bits(1) ? 4 : (testrand_bits(1) ? 6 : 7); } else { - in[0] = secp256k1_testrand_bits(1) ? 2 : 3; + in[0] = testrand_bits(1) ? 2 : 3; } - if (secp256k1_testrand_bits(3) == 0) { - in[0] = secp256k1_testrand_bits(8); + if (testrand_bits(3) == 0) { + in[0] = testrand_bits(8); } if (len > 1) { - secp256k1_testrand256(&in[1]); + testrand256(&in[1]); } if (len > 33) { - secp256k1_testrand256(&in[33]); + testrand256(&in[33]); } if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { unsigned char out[65]; @@ -6639,7 +6523,7 @@ static void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); CHECK(secp256k1_ge_eq_var(&elem2, &elem)); /* Check that the X9.62 hybrid type is checked. */ - in[0] = secp256k1_testrand_bits(1) ? 6 : 7; + in[0] = testrand_bits(1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { if (in[0] == firstb + 4) { @@ -6718,21 +6602,13 @@ static void permute(size_t *arr, size_t n) { size_t i; for (i = n - 1; i >= 1; i--) { size_t tmp, j; - j = secp256k1_testrand_int(i + 1); + j = testrand_int(i + 1); tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } } -static void rand_pk(secp256k1_pubkey *pk) { - unsigned char seckey[32]; - secp256k1_keypair keypair; - secp256k1_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]; @@ -6740,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)); @@ -6794,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); @@ -6944,27 +6820,27 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { static void damage_array(unsigned char *sig, size_t *len) { int pos; - int action = secp256k1_testrand_bits(3); + int action = testrand_bits(3); if (action < 1 && *len > 3) { /* Delete a byte. */ - pos = secp256k1_testrand_int(*len); + pos = testrand_int(*len); memmove(sig + pos, sig + pos + 1, *len - pos - 1); (*len)--; return; } else if (action < 2 && *len < 2048) { /* Insert a byte. */ - pos = secp256k1_testrand_int(1 + *len); + pos = testrand_int(1 + *len); memmove(sig + pos + 1, sig + pos, *len - pos); - sig[pos] = secp256k1_testrand_bits(8); + sig[pos] = testrand_bits(8); (*len)++; return; } else if (action < 4) { /* Modify a byte. */ - sig[secp256k1_testrand_int(*len)] += 1 + secp256k1_testrand_int(255); + sig[testrand_int(*len)] += 1 + testrand_int(255); return; } else { /* action < 8 */ /* Modify a bit. */ - sig[secp256k1_testrand_int(*len)] ^= 1 << secp256k1_testrand_bits(3); + sig[testrand_int(*len)] ^= 1 << testrand_bits(3); return; } } @@ -6977,23 +6853,23 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly int n; *len = 0; - der = secp256k1_testrand_bits(2) == 0; + der = testrand_bits(2) == 0; *certainly_der = der; *certainly_not_der = 0; - indet = der ? 0 : secp256k1_testrand_int(10) == 0; + indet = der ? 0 : testrand_int(10) == 0; for (n = 0; n < 2; n++) { /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ - nlow[n] = der ? 1 : (secp256k1_testrand_bits(3) != 0); + nlow[n] = der ? 1 : (testrand_bits(3) != 0); /* The length of the number in bytes (the first byte of which will always be nonzero) */ - nlen[n] = nlow[n] ? secp256k1_testrand_int(33) : 32 + secp256k1_testrand_int(200) * secp256k1_testrand_bits(3) / 8; + nlen[n] = nlow[n] ? testrand_int(33) : 32 + testrand_int(200) * testrand_bits(3) / 8; CHECK(nlen[n] <= 232); /* The top bit of the number. */ - nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_testrand_bits(1)); + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : testrand_bits(1)); /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ - nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_testrand_bits(7) : 1 + secp256k1_testrand_int(127)); + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + testrand_bits(7) : 1 + testrand_int(127)); /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ - nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_testrand_int(3) : secp256k1_testrand_int(300 - nlen[n]) * secp256k1_testrand_bits(3) / 8); + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? testrand_int(3) : testrand_int(300 - nlen[n]) * testrand_bits(3) / 8); if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { *certainly_not_der = 1; } @@ -7002,7 +6878,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); if (!der) { /* nlenlen[n] max 127 bytes */ - int add = secp256k1_testrand_int(127 - nlenlen[n]) * secp256k1_testrand_bits(4) * secp256k1_testrand_bits(4) / 256; + int add = testrand_int(127 - nlenlen[n]) * testrand_bits(4) * testrand_bits(4) / 256; nlenlen[n] += add; if (add != 0) { *certainly_not_der = 1; @@ -7016,7 +6892,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 856); /* The length of the garbage inside the tuple. */ - elen = (der || indet) ? 0 : secp256k1_testrand_int(980 - tlen) * secp256k1_testrand_bits(3) / 8; + elen = (der || indet) ? 0 : testrand_int(980 - tlen) * testrand_bits(3) / 8; if (elen != 0) { *certainly_not_der = 1; } @@ -7024,7 +6900,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 980); /* The length of the garbage after the end of the tuple. */ - glen = der ? 0 : secp256k1_testrand_int(990 - tlen) * secp256k1_testrand_bits(3) / 8; + glen = der ? 0 : testrand_int(990 - tlen) * testrand_bits(3) / 8; if (glen != 0) { *certainly_not_der = 1; } @@ -7039,7 +6915,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly } else { int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); if (!der) { - int add = secp256k1_testrand_int(127 - tlenlen) * secp256k1_testrand_bits(4) * secp256k1_testrand_bits(4) / 256; + int add = testrand_int(127 - tlenlen) * testrand_bits(4) * testrand_bits(4) / 256; tlenlen += add; if (add != 0) { *certainly_not_der = 1; @@ -7090,13 +6966,13 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlen[n]--; } /* Generate remaining random bytes of number */ - secp256k1_testrand_bytes_test(sig + *len, nlen[n]); + testrand_bytes_test(sig + *len, nlen[n]); *len += nlen[n]; nlen[n] = 0; } /* Generate random garbage inside tuple. */ - secp256k1_testrand_bytes_test(sig + *len, elen); + testrand_bytes_test(sig + *len, elen); *len += elen; /* Generate end-of-contents bytes. */ @@ -7108,7 +6984,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen + glen <= 1121); /* Generate random garbage outside tuple. */ - secp256k1_testrand_bytes_test(sig + *len, glen); + testrand_bytes_test(sig + *len, glen); *len += glen; tlen += glen; CHECK(tlen <= 1121); @@ -7771,7 +7647,7 @@ int main(int argc, char **argv) { run_xoshiro256pp_tests(); /* find random seed */ - secp256k1_testrand_init(argc > 2 ? argv[2] : NULL); + testrand_init(argc > 2 ? argv[2] : NULL); /*** Setup test environment ***/ @@ -7780,9 +7656,9 @@ int main(int argc, char **argv) { /* Randomize the context only with probability 15/16 to make sure we test without context randomization from time to time. TODO Reconsider this when recalibrating the tests. */ - if (secp256k1_testrand_bits(4)) { + if (testrand_bits(4)) { unsigned char rand32[32]; - secp256k1_testrand256(rand32); + testrand256(rand32); CHECK(secp256k1_context_randomize(CTX, rand32)); } /* Make a writable copy of secp256k1_context_static in order to test the effect of API functions @@ -7909,7 +7785,7 @@ int main(int argc, char **argv) { free(STATIC_CTX); secp256k1_context_destroy(CTX); - secp256k1_testrand_finish(); + testrand_finish(); printf("no problems found\n"); return 0; diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c index 5843b3e1f5..6efa88982e 100644 --- a/src/secp256k1/src/tests_exhaustive.c +++ b/src/secp256k1/src/tests_exhaustive.c @@ -171,7 +171,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */ - random_fe_non_zero(&xd); + testutil_random_fe_non_zero(&xd); secp256k1_fe_mul(&xn, &xd, &group[i].x); ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0); CHECK(ret); @@ -375,7 +375,7 @@ int main(int argc, char** argv) { printf("test count = %i\n", count); /* find random seed */ - secp256k1_testrand_init(argc > 2 ? argv[2] : NULL); + testrand_init(argc > 2 ? argv[2] : NULL); /* set up split processing */ if (argc > 4) { @@ -395,7 +395,7 @@ int main(int argc, char** argv) { while (count--) { /* Build context */ ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_testrand256(rand32); + testrand256(rand32); CHECK(secp256k1_context_randomize(ctx, rand32)); /* Generate the entire group */ @@ -408,7 +408,7 @@ int main(int argc, char** argv) { /* Set a different random z-value for each Jacobian point, except z=1 is used in the last iteration. */ secp256k1_fe z; - random_fe(&z); + testutil_random_fe(&z); secp256k1_gej_rescale(&groupj[i], &z); } @@ -459,7 +459,7 @@ int main(int argc, char** argv) { secp256k1_context_destroy(ctx); } - secp256k1_testrand_finish(); + testrand_finish(); printf("no problems found\n"); return 0; diff --git a/src/secp256k1/src/testutil.h b/src/secp256k1/src/testutil.h index 4e2cb7d5b3..fc56854dd3 100644 --- a/src/secp256k1/src/testutil.h +++ b/src/secp256k1/src/testutil.h @@ -7,23 +7,142 @@ #define SECP256K1_TESTUTIL_H #include "field.h" +#include "group.h" #include "testrand.h" #include "util.h" -static void random_fe(secp256k1_fe *x) { +static void testutil_random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { - secp256k1_testrand256(bin); + testrand256(bin); if (secp256k1_fe_set_b32_limit(x, bin)) { return; } } while(1); } -static void random_fe_non_zero(secp256k1_fe *nz) { +static void testutil_random_fe_non_zero(secp256k1_fe *nz) { do { - random_fe(nz); + testutil_random_fe(nz); } while (secp256k1_fe_is_zero(nz)); } +static void testutil_random_fe_magnitude(secp256k1_fe *fe, int m) { + secp256k1_fe zero; + int n = testrand_int(m + 1); + secp256k1_fe_normalize(fe); + if (n == 0) { + return; + } + secp256k1_fe_clear(&zero); + secp256k1_fe_negate(&zero, &zero, 0); + secp256k1_fe_mul_int_unchecked(&zero, n - 1); + secp256k1_fe_add(fe, &zero); +#ifdef VERIFY + CHECK(fe->magnitude == n); +#endif +} + +static void testutil_random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + testrand256_test(bin); + if (secp256k1_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void testutil_random_fe_non_zero_test(secp256k1_fe *fe) { + do { + testutil_random_fe_test(fe); + } while(secp256k1_fe_is_zero(fe)); +} + +static void testutil_random_ge_x_magnitude(secp256k1_ge *ge) { + testutil_random_fe_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX); +} + +static void testutil_random_ge_y_magnitude(secp256k1_ge *ge) { + testutil_random_fe_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_x_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); +} + +static void testutil_random_gej_y_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_z_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); +} + +static void testutil_random_ge_test(secp256k1_ge *ge) { + secp256k1_fe fe; + do { + testutil_random_fe_test(&fe); + if (secp256k1_ge_set_xo_var(ge, &fe, testrand_bits(1))) { + secp256k1_fe_normalize(&ge->y); + break; + } + } while(1); + ge->infinity = 0; +} + +static void testutil_random_ge_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { + secp256k1_fe z2, z3; + testutil_random_fe_non_zero_test(&gej->z); + secp256k1_fe_sqr(&z2, &gej->z); + secp256k1_fe_mul(&z3, &z2, &gej->z); + secp256k1_fe_mul(&gej->x, &ge->x, &z2); + secp256k1_fe_mul(&gej->y, &ge->y, &z3); + gej->infinity = ge->infinity; +} + +static void testutil_random_gej_test(secp256k1_gej *gej) { + secp256k1_ge ge; + testutil_random_ge_test(&ge); + 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]; + int overflow = 0; + testrand256_test(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order(secp256k1_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + testrand256(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order_b32(unsigned char *b32) { + secp256k1_scalar num; + testutil_random_scalar_order(&num); + secp256k1_scalar_get_b32(b32, &num); +} + #endif /* SECP256K1_TESTUTIL_H */ 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/signet.cpp b/src/signet.cpp index ebf0de09d3..9b7ffd07cd 100644 --- a/src/signet.cpp +++ b/src/signet.cpp @@ -4,10 +4,6 @@ #include <signet.h> -#include <array> -#include <cstdint> -#include <vector> - #include <common/system.h> #include <consensus/merkle.h> #include <consensus/params.h> @@ -23,6 +19,11 @@ #include <uint256.h> #include <util/strencodings.h> +#include <algorithm> +#include <array> +#include <cstdint> +#include <vector> + static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2}; static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY; @@ -38,7 +39,7 @@ static bool FetchAndClearCommitmentSection(const Span<const uint8_t> header, CSc std::vector<uint8_t> pushdata; while (witness_commitment.GetOp(pc, opcode, pushdata)) { if (pushdata.size() > 0) { - if (!found_header && pushdata.size() > (size_t)header.size() && Span{pushdata}.first(header.size()) == header) { + if (!found_header && pushdata.size() > header.size() && std::ranges::equal(Span{pushdata}.first(header.size()), header)) { // pushdata only counts if it has the header _and_ some data result.insert(result.end(), pushdata.begin() + header.size(), pushdata.end()); pushdata.erase(pushdata.begin() + header.size(), pushdata.end()); @@ -68,13 +69,13 @@ static uint256 ComputeModifiedMerkleRoot(const CMutableTransaction& cb, const CB std::optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& challenge) { CMutableTransaction tx_to_spend; - tx_to_spend.nVersion = 0; + tx_to_spend.version = 0; tx_to_spend.nLockTime = 0; tx_to_spend.vin.emplace_back(COutPoint(), CScript(OP_0), 0); tx_to_spend.vout.emplace_back(0, challenge); CMutableTransaction tx_spending; - tx_spending.nVersion = 0; + tx_spending.version = 0; tx_spending.nLockTime = 0; tx_spending.vin.emplace_back(COutPoint(), CScript(), 0); tx_spending.vout.emplace_back(0, CScript(OP_RETURN)); @@ -132,7 +133,7 @@ bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& cons const std::optional<SignetTxs> signet_txs = SignetTxs::Create(block, challenge); if (!signet_txs) { - LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution parse failure)\n"); + LogDebug(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution parse failure)\n"); return false; } @@ -144,7 +145,7 @@ bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& cons TransactionSignatureChecker sigcheck(&signet_txs->m_to_sign, /* nInIn= */ 0, /* amountIn= */ signet_txs->m_to_spend.vout[0].nValue, txdata, MissingDataBehavior::ASSERT_FAIL); if (!VerifyScript(scriptSig, signet_txs->m_to_spend.vout[0].scriptPubKey, &witness, BLOCK_SCRIPT_VERIFY_FLAGS, sigcheck)) { - LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution invalid)\n"); + LogDebug(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution invalid)\n"); return false; } return true; diff --git a/src/span.h b/src/span.h index c974c265ce..3c5028f0b7 100644 --- a/src/span.h +++ b/src/span.h @@ -5,11 +5,11 @@ #ifndef BITCOIN_SPAN_H #define BITCOIN_SPAN_H -#include <algorithm> #include <cassert> #include <cstddef> #include <span> #include <type_traits> +#include <utility> #ifdef DEBUG #define CONSTEXPR_IF_NOT_DEBUG @@ -213,13 +213,6 @@ public: return Span<C>(m_data + m_size - count, count); } - friend constexpr bool operator==(const Span& a, const Span& b) noexcept { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); } - friend constexpr bool operator!=(const Span& a, const Span& b) noexcept { return !(a == b); } - friend constexpr bool operator<(const Span& a, const Span& b) noexcept { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); } - friend constexpr bool operator<=(const Span& a, const Span& b) noexcept { return !(b < a); } - friend constexpr bool operator>(const Span& a, const Span& b) noexcept { return (b < a); } - friend constexpr bool operator>=(const Span& a, const Span& b) noexcept { return !(a < b); } - template <typename O> friend class Span; }; diff --git a/src/streams.cpp b/src/streams.cpp index cdd36a86fe..baa5ad7abe 100644 --- a/src/streams.cpp +++ b/src/streams.cpp @@ -4,21 +4,29 @@ #include <span.h> #include <streams.h> +#include <util/fs_helpers.h> #include <array> +AutoFile::AutoFile(std::FILE* file, std::vector<std::byte> data_xor) + : m_file{file}, m_xor{std::move(data_xor)} +{ + if (!IsNull()) { + auto pos{std::ftell(m_file)}; + if (pos >= 0) m_position = pos; + } +} + std::size_t AutoFile::detail_fread(Span<std::byte> dst) { if (!m_file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr"); - if (m_xor.empty()) { - return std::fread(dst.data(), 1, dst.size(), m_file); - } else { - const auto init_pos{std::ftell(m_file)}; - if (init_pos < 0) throw std::ios_base::failure("AutoFile::read: ftell failed"); - std::size_t ret{std::fread(dst.data(), 1, dst.size(), m_file)}; - util::Xor(dst.subspan(0, ret), m_xor, init_pos); - return ret; + size_t ret = std::fread(dst.data(), 1, dst.size(), m_file); + if (!m_xor.empty()) { + if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::read: position unknown"); + util::Xor(dst.subspan(0, ret), m_xor, *m_position); } + if (m_position.has_value()) *m_position += ret; + return ret; } void AutoFile::seek(int64_t offset, int origin) @@ -29,18 +37,23 @@ void AutoFile::seek(int64_t offset, int origin) if (std::fseek(m_file, offset, origin) != 0) { throw std::ios_base::failure(feof() ? "AutoFile::seek: end of file" : "AutoFile::seek: fseek failed"); } + if (origin == SEEK_SET) { + m_position = offset; + } else if (origin == SEEK_CUR && m_position.has_value()) { + *m_position += offset; + } else { + int64_t r{std::ftell(m_file)}; + if (r < 0) { + throw std::ios_base::failure("AutoFile::seek: ftell failed"); + } + m_position = r; + } } int64_t AutoFile::tell() { - if (IsNull()) { - throw std::ios_base::failure("AutoFile::tell: file handle is nullptr"); - } - int64_t r{std::ftell(m_file)}; - if (r < 0) { - throw std::ios_base::failure("AutoFile::tell: ftell failed"); - } - return r; + if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::tell: position unknown"); + return *m_position; } void AutoFile::read(Span<std::byte> dst) @@ -60,6 +73,7 @@ void AutoFile::ignore(size_t nSize) throw std::ios_base::failure(feof() ? "AutoFile::ignore: end of file" : "AutoFile::ignore: fread failed"); } nSize -= nNow; + if (m_position.has_value()) *m_position += nNow; } } @@ -70,19 +84,29 @@ void AutoFile::write(Span<const std::byte> src) if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) { throw std::ios_base::failure("AutoFile::write: write failed"); } + if (m_position.has_value()) *m_position += src.size(); } else { - auto current_pos{std::ftell(m_file)}; - if (current_pos < 0) throw std::ios_base::failure("AutoFile::write: ftell failed"); + if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::write: position unknown"); std::array<std::byte, 4096> buf; while (src.size() > 0) { auto buf_now{Span{buf}.first(std::min<size_t>(src.size(), buf.size()))}; std::copy(src.begin(), src.begin() + buf_now.size(), buf_now.begin()); - util::Xor(buf_now, m_xor, current_pos); + util::Xor(buf_now, m_xor, *m_position); if (std::fwrite(buf_now.data(), 1, buf_now.size(), m_file) != buf_now.size()) { throw std::ios_base::failure{"XorFile::write: failed"}; } src = src.subspan(buf_now.size()); - current_pos += buf_now.size(); + *m_position += buf_now.size(); } } } + +bool AutoFile::Commit() +{ + return ::FileCommit(m_file); +} + +bool AutoFile::Truncate(unsigned size) +{ + return ::TruncateFile(m_file, size); +} diff --git a/src/streams.h b/src/streams.h index 57fc600646..e9f3562c6c 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()) {} @@ -390,9 +390,10 @@ class AutoFile protected: std::FILE* m_file; std::vector<std::byte> m_xor; + std::optional<int64_t> m_position; public: - explicit AutoFile(std::FILE* file, std::vector<std::byte> data_xor={}) : m_file{file}, m_xor{std::move(data_xor)} {} + explicit AutoFile(std::FILE* file, std::vector<std::byte> data_xor={}); ~AutoFile() { fclose(); } @@ -419,12 +420,6 @@ public: return ret; } - /** Get wrapped FILE* without transfer of ownership. - * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the - * AutoFile outlives use of the passed pointer. - */ - std::FILE* Get() const { return m_file; } - /** Return true if the wrapped FILE* is nullptr, false otherwise. */ bool IsNull() const { return m_file == nullptr; } @@ -435,9 +430,18 @@ public: /** Implementation detail, only used internally. */ std::size_t detail_fread(Span<std::byte> dst); + /** Wrapper around fseek(). Will throw if seeking is not possible. */ void seek(int64_t offset, int origin); + + /** Find position within the file. Will throw if unknown. */ int64_t tell(); + /** Wrapper around FileCommit(). */ + bool Commit(); + + /** Wrapper around TruncateFile(). */ + bool Truncate(unsigned size); + // // Stream subset // 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/.gitignore b/src/test/.gitignore deleted file mode 100644 index 036df1430c..0000000000 --- a/src/test/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# capnp generated files -*.capnp.* diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt new file mode 100644 index 0000000000..c23fbae92f --- /dev/null +++ b/src/test/CMakeLists.txt @@ -0,0 +1,216 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include(GenerateHeaders) +generate_header_from_json(data/base58_encode_decode.json) +generate_header_from_json(data/bip341_wallet_vectors.json) +generate_header_from_json(data/blockfilters.json) +generate_header_from_json(data/key_io_invalid.json) +generate_header_from_json(data/key_io_valid.json) +generate_header_from_json(data/script_tests.json) +generate_header_from_json(data/sighash.json) +generate_header_from_json(data/tx_invalid.json) +generate_header_from_json(data/tx_valid.json) +generate_header_from_raw(data/asmap.raw test::data) + +# Do not use generator expressions in test sources because the +# SOURCES property is processed to gather test suite macros. +add_executable(test_bitcoin + main.cpp + $<TARGET_OBJECTS:bitcoin_consensus> + ${CMAKE_CURRENT_BINARY_DIR}/data/asmap.raw.h + ${CMAKE_CURRENT_BINARY_DIR}/data/base58_encode_decode.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/bip341_wallet_vectors.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/blockfilters.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/key_io_invalid.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/key_io_valid.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/script_tests.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/sighash.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/tx_invalid.json.h + ${CMAKE_CURRENT_BINARY_DIR}/data/tx_valid.json.h + addrman_tests.cpp + allocator_tests.cpp + amount_tests.cpp + argsman_tests.cpp + arith_uint256_tests.cpp + banman_tests.cpp + base32_tests.cpp + base58_tests.cpp + base64_tests.cpp + bech32_tests.cpp + bip32_tests.cpp + bip324_tests.cpp + blockchain_tests.cpp + blockencodings_tests.cpp + blockfilter_index_tests.cpp + blockfilter_tests.cpp + blockmanager_tests.cpp + bloom_tests.cpp + bswap_tests.cpp + checkqueue_tests.cpp + cluster_linearize_tests.cpp + coins_tests.cpp + coinscachepair_tests.cpp + coinstatsindex_tests.cpp + common_url_tests.cpp + compilerbug_tests.cpp + compress_tests.cpp + crypto_tests.cpp + cuckoocache_tests.cpp + dbwrapper_tests.cpp + denialofservice_tests.cpp + descriptor_tests.cpp + disconnected_transactions.cpp + feefrac_tests.cpp + flatfile_tests.cpp + fs_tests.cpp + getarg_tests.cpp + hash_tests.cpp + headers_sync_chainwork_tests.cpp + httpserver_tests.cpp + i2p_tests.cpp + interfaces_tests.cpp + key_io_tests.cpp + key_tests.cpp + logging_tests.cpp + mempool_tests.cpp + merkle_tests.cpp + merkleblock_tests.cpp + miner_tests.cpp + miniminer_tests.cpp + miniscript_tests.cpp + minisketch_tests.cpp + multisig_tests.cpp + net_peer_connection_tests.cpp + net_peer_eviction_tests.cpp + net_tests.cpp + netbase_tests.cpp + node_warnings_tests.cpp + orphanage_tests.cpp + peerman_tests.cpp + pmt_tests.cpp + policy_fee_tests.cpp + policyestimator_tests.cpp + pool_tests.cpp + pow_tests.cpp + prevector_tests.cpp + raii_event_tests.cpp + random_tests.cpp + rbf_tests.cpp + rest_tests.cpp + result_tests.cpp + reverselock_tests.cpp + rpc_tests.cpp + sanity_tests.cpp + scheduler_tests.cpp + script_p2sh_tests.cpp + script_parse_tests.cpp + script_segwit_tests.cpp + script_standard_tests.cpp + script_tests.cpp + scriptnum_tests.cpp + serfloat_tests.cpp + serialize_tests.cpp + settings_tests.cpp + sighash_tests.cpp + sigopcount_tests.cpp + skiplist_tests.cpp + sock_tests.cpp + span_tests.cpp + streams_tests.cpp + sync_tests.cpp + system_tests.cpp + timeoffsets_tests.cpp + torcontrol_tests.cpp + transaction_tests.cpp + translation_tests.cpp + txindex_tests.cpp + txpackage_tests.cpp + txreconciliation_tests.cpp + txrequest_tests.cpp + txvalidation_tests.cpp + txvalidationcache_tests.cpp + uint256_tests.cpp + util_string_tests.cpp + util_tests.cpp + util_threadnames_tests.cpp + validation_block_tests.cpp + validation_chainstate_tests.cpp + validation_chainstatemanager_tests.cpp + validation_flush_tests.cpp + validation_tests.cpp + validationinterface_tests.cpp + versionbits_tests.cpp +) + +target_link_libraries(test_bitcoin + core_interface + test_util + bitcoin_cli + bitcoin_node + minisketch + secp256k1 + Boost::headers + $<TARGET_NAME_IF_EXISTS:libevent::libevent> +) + +if(ENABLE_WALLET) + add_subdirectory(${PROJECT_SOURCE_DIR}/src/wallet/test wallet) +endif() + +if(WITH_MULTIPROCESS) + target_link_libraries(bitcoin_ipc_test + PRIVATE + core_interface + univalue + ) + + target_sources(test_bitcoin + PRIVATE + ipc_tests.cpp + ) + target_link_libraries(test_bitcoin bitcoin_ipc_test bitcoin_ipc) +endif() + +function(add_boost_test source_file) + if(NOT EXISTS ${source_file}) + return() + endif() + + file(READ "${source_file}" source_file_content) + string(REGEX + MATCH "(BOOST_FIXTURE_TEST_SUITE|BOOST_AUTO_TEST_SUITE)\\(([A-Za-z0-9_]+)" + test_suite_macro "${source_file_content}" + ) + string(REGEX + REPLACE "(BOOST_FIXTURE_TEST_SUITE|BOOST_AUTO_TEST_SUITE)\\(" "" + test_suite_name "${test_suite_macro}" + ) + if(test_suite_name) + add_test(NAME ${test_suite_name} + COMMAND test_bitcoin --run_test=${test_suite_name} --catch_system_error=no --log_level=test_suite -- DEBUG_LOG_OUT + ) + set_property(TEST ${test_suite_name} PROPERTY + SKIP_REGULAR_EXPRESSION "no test cases matching filter" + ) + endif() +endfunction() + +function(add_all_test_targets) + get_target_property(test_source_dir test_bitcoin SOURCE_DIR) + get_target_property(test_sources test_bitcoin SOURCES) + foreach(test_source ${test_sources}) + cmake_path(IS_RELATIVE test_source result) + if(result) + cmake_path(APPEND test_source_dir ${test_source} OUTPUT_VARIABLE test_source) + endif() + add_boost_test(${test_source}) + endforeach() +endfunction() + +add_all_test_targets() + +install(TARGETS test_bitcoin + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/test/Makefile b/src/test/Makefile deleted file mode 100644 index 87bf73fec9..0000000000 --- a/src/test/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: - $(MAKE) -C .. bitcoin_test -clean: - $(MAKE) -C .. bitcoin_test_clean -check: - $(MAKE) -C .. bitcoin_test_check diff --git a/src/test/README.md b/src/test/README.md index bab1a28f61..7e0f245ee8 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -10,59 +10,76 @@ The build system is set up to compile an executable called `test_bitcoin` that runs all of the unit tests. The main source file for the test library is found in `util/setup_common.cpp`. +The examples in this document assume the build directory is named +`build`. You'll need to adapt them if you named it differently. + ### Compiling/running unit tests -Unit tests will be automatically compiled if dependencies were met in `./configure` +Unit tests will be automatically compiled if dependencies were met +during the generation of the Bitcoin Core build system and tests weren't explicitly disabled. -After configuring, they can be run with `make check`, which includes unit tests from -subtrees, or `make && make -C src check-unit` for just the unit tests. +The unit tests can be run with `ctest --test-dir build`, which includes unit +tests from subtrees. + +Run `test_bitcoin --list_content` for the full list of tests. -To run the unit tests manually, launch `src/test/test_bitcoin`. To recompile -after a test file was modified, run `make` and then run the test again. If you -modify a non-test file, use `make -C src/test` to recompile only what's needed +To run the unit tests manually, launch `build/src/test/test_bitcoin`. To recompile +after a test file was modified, run `cmake --build build` and then run the test again. If you +modify a non-test file, use `cmake --build build --target test_bitcoin` to recompile only what's needed to run the unit tests. To add more unit tests, add `BOOST_AUTO_TEST_CASE` functions to the existing .cpp files in the `test/` directory or add new .cpp files that implement new `BOOST_AUTO_TEST_SUITE` sections. -To run the GUI unit tests manually, launch `src/qt/test/test_bitcoin-qt` +To run the GUI unit tests manually, launch `build/src/qt/test/test_bitcoin-qt` To add more GUI unit tests, add them to the `src/qt/test/` directory and the `src/qt/test/test_main.cpp` file. ### Running individual tests -`test_bitcoin` accepts the command line arguments from the boost framework. -For example, to run just the `getarg_tests` suite of tests: +The `test_bitcoin` runner accepts command line arguments from the Boost +framework. To see the list of arguments that may be passed, run: + +``` +test_bitcoin --help +``` + +For example, to run only the tests in the `getarg_tests` file, with full logging: ```bash -test_bitcoin --log_level=all --run_test=getarg_tests +build/src/test/test_bitcoin --log_level=all --run_test=getarg_tests ``` -`log_level` controls the verbosity of the test framework, which logs when a -test case is entered, for example. +or -`test_bitcoin` also accepts some of the command line arguments accepted by -`bitcoind`. Use `--` to separate these sets of arguments: +```bash +build/src/test/test_bitcoin -l all -t getarg_tests +``` + +or to run only the doubledash test in `getarg_tests` ```bash -test_bitcoin --log_level=all --run_test=getarg_tests -- -printtoconsole=1 +build/src/test/test_bitcoin --run_test=getarg_tests/doubledash ``` -The `-printtoconsole=1` after the two dashes sends debug logging, which -normally goes only to `debug.log` within the data directory, also to the -standard terminal output. +The `--log_level=` (or `-l`) argument controls the verbosity of the test output. -... or to run just the doubledash test: +The `test_bitcoin` runner also accepts some of the command line arguments accepted by +`bitcoind`. Use `--` to separate these sets of arguments: ```bash -test_bitcoin --run_test=getarg_tests/doubledash +build/src/test/test_bitcoin --log_level=all --run_test=getarg_tests -- -printtoconsole=1 ``` -`test_bitcoin` creates a temporary working (data) directory with a randomly -generated pathname within `test_common_Bitcoin Core/`, which in turn is within +The `-printtoconsole=1` after the two dashes sends debug logging, which +normally goes only to `debug.log` within the data directory, to the +standard terminal output as well. + +Running `test_bitcoin` creates a temporary working (data) directory with a randomly +generated pathname within `test_common bitcoin/`, which in turn is within the system's temporary directory (see [`temp_directory_path`](https://en.cppreference.com/w/cpp/filesystem/temp_directory_path)). This data directory looks like a simplified form of the standard `bitcoind` data @@ -72,7 +89,7 @@ have a `debug.log` file, for example. The location of the temporary data directory can be specified with the `-testdatadir` option. This can make debugging easier. The directory path used is the argument path appended with -`/test_common_Bitcoin Core/<test-name>/datadir`. +`/test_common bitcoin/<test-name>/datadir`. The directory path is created if necessary. Specifying this argument also causes the data directory not to be removed after the last test. This is useful for looking at @@ -81,12 +98,12 @@ what the test wrote to `debug.log` after it completes, for example. so no leftover state is used.) ```bash -$ test_bitcoin --run_test=getarg_tests/doubledash -- -testdatadir=/somewhere/mydatadir -Test directory (will not be deleted): "/somewhere/mydatadir/test_common_Bitcoin Core/getarg_tests/doubledash/datadir +$ build/src/test/test_bitcoin --run_test=getarg_tests/doubledash -- -testdatadir=/somewhere/mydatadir +Test directory (will not be deleted): "/somewhere/mydatadir/test_common bitcoin/getarg_tests/doubledash/datadir" Running 1 test case... *** No errors detected -$ ls -l '/somewhere/mydatadir/test_common_Bitcoin Core/getarg_tests/doubledash/datadir' +$ ls -l '/somewhere/mydatadir/test_common bitcoin/getarg_tests/doubledash/datadir' total 8 drwxrwxr-x 2 admin admin 4096 Nov 27 22:45 blocks -rw-rw-r-- 1 admin admin 1003 Nov 27 22:45 debug.log @@ -96,12 +113,11 @@ If you run an entire test suite, such as `--run_test=getarg_tests`, or all the t (by not specifying `--run_test`), a separate directory will be created for each individual test. -Run `test_bitcoin --help` for the full list of tests. - ### Adding test cases -To add a new unit test file to our test suite you need -to add the file to `src/Makefile.test.include`. The pattern is to create +To add a new unit test file to our test suite, you need +to add the file to either `src/test/CMakeLists.txt` or +`src/wallet/test/CMakeLists.txt` for wallet-related tests. The pattern is to create one test file for each class or source file for which you want to create unit tests. The file naming convention is `<source_filename>_tests.cpp` and such files should wrap their tests in a test suite @@ -110,7 +126,8 @@ see `uint256_tests.cpp`. ### Logging and debugging in unit tests -`make check` will write to a log file `foo_tests.cpp.log` and display this file +`ctest --test-dir build` will write to the log file `build/Testing/Temporary/LastTest.log`. You can +additionally use the `--output-on-failure` option to display logs of the failed tests automatically on failure. For running individual tests verbosely, refer to the section [above](#running-individual-tests). @@ -121,13 +138,13 @@ For debugging you can launch the `test_bitcoin` executable with `gdb` or `lldb` start debugging, just like you would with any other program: ```bash -gdb src/test/test_bitcoin +gdb build/src/test/test_bitcoin ``` #### Segmentation faults If you hit a segmentation fault during a test run, you can diagnose where the fault -is happening by running `gdb ./src/test/test_bitcoin` and then using the `bt` command +is happening by running `gdb ./build/src/test/test_bitcoin` and then using the `bt` command within gdb. Another tool that can be used to resolve segmentation faults is @@ -145,7 +162,7 @@ Running the tests and hitting a segmentation fault should now produce a file cal You can then explore the core dump using ```bash -gdb src/test/test_bitcoin core +gdb build/src/test/test_bitcoin core -(gbd) bt # produce a backtrace for where a segfault occurred +(gdb) bt # produce a backtrace for where a segfault occurred ``` diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 9668a85484..c4f58ebecf 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -22,6 +22,7 @@ using namespace std::literals; using node::NodeContext; +using util::ToString; static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()}; static const bool DETERMINISTIC{true}; @@ -46,11 +47,12 @@ static CService ResolveService(const std::string& ip, uint16_t port = 0) } -static std::vector<bool> FromBytes(const unsigned char* source, int vector_size) +static std::vector<bool> FromBytes(std::span<const std::byte> source) { + int vector_size(source.size() * 8); std::vector<bool> result(vector_size); for (int byte_i = 0; byte_i < vector_size / 8; ++byte_i) { - unsigned char cur_byte = source[byte_i]; + uint8_t cur_byte{std::to_integer<uint8_t>(source[byte_i])}; for (int bit_i = 0; bit_i < 8; ++bit_i) { result[byte_i * 8 + bit_i] = (cur_byte >> bit_i) & 1; } @@ -194,21 +196,21 @@ BOOST_AUTO_TEST_CASE(addrman_select) BOOST_AUTO_TEST_CASE(addrman_select_by_network) { auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)); - BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_IPV4).first.IsValid()); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV4).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/true, {NET_IPV4}).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_IPV4}).first.IsValid()); // add ipv4 address to the new table CNetAddr source = ResolveIP("252.2.2.2"); CService addr1 = ResolveService("250.1.1.1", 8333); BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source)); - BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_IPV4).first == addr1); - BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV6).first.IsValid()); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_ONION).first.IsValid()); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_I2P).first.IsValid()); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_CJDNS).first.IsValid()); - BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_CJDNS).first.IsValid()); + BOOST_CHECK(addrman->Select(/*new_only=*/true, {NET_IPV4}).first == addr1); + BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_IPV4}).first == addr1); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_IPV6}).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_ONION}).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_I2P}).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_CJDNS}).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/true, {NET_CJDNS}).first.IsValid()); BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1); // add I2P address to the new table @@ -216,25 +218,29 @@ BOOST_AUTO_TEST_CASE(addrman_select_by_network) i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p"); BOOST_CHECK(addrman->Add({i2p_addr}, source)); - BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_I2P).first == i2p_addr); - BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_I2P).first == i2p_addr); - BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV6).first.IsValid()); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_ONION).first.IsValid()); - BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_CJDNS).first.IsValid()); + BOOST_CHECK(addrman->Select(/*new_only=*/true, {NET_I2P}).first == i2p_addr); + BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_I2P}).first == i2p_addr); + BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_IPV4}).first == addr1); + std::unordered_set<Network> nets_with_entries = {NET_IPV4, NET_I2P}; + BOOST_CHECK(addrman->Select(/*new_only=*/false, nets_with_entries).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_IPV6}).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_ONION}).first.IsValid()); + BOOST_CHECK(!addrman->Select(/*new_only=*/false, {NET_CJDNS}).first.IsValid()); + std::unordered_set<Network> nets_without_entries = {NET_IPV6, NET_ONION, NET_CJDNS}; + BOOST_CHECK(!addrman->Select(/*new_only=*/false, nets_without_entries).first.IsValid()); // bump I2P address to tried table BOOST_CHECK(addrman->Good(i2p_addr)); - BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_I2P).first.IsValid()); - BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_I2P).first == i2p_addr); + BOOST_CHECK(!addrman->Select(/*new_only=*/true, {NET_I2P}).first.IsValid()); + BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_I2P}).first == i2p_addr); // add another I2P address to the new table CAddress i2p_addr2; i2p_addr2.SetSpecial("c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p"); BOOST_CHECK(addrman->Add({i2p_addr2}, source)); - BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_I2P).first == i2p_addr2); + BOOST_CHECK(addrman->Select(/*new_only=*/true, {NET_I2P}).first == i2p_addr2); // ensure that both new and tried table are selected from bool new_selected{false}; @@ -242,7 +248,7 @@ BOOST_AUTO_TEST_CASE(addrman_select_by_network) int counter = 256; while (--counter > 0 && (!new_selected || !tried_selected)) { - const CAddress selected{addrman->Select(/*new_only=*/false, NET_I2P).first}; + const CAddress selected{addrman->Select(/*new_only=*/false, {NET_I2P}).first}; BOOST_REQUIRE(selected == i2p_addr || selected == i2p_addr2); if (selected == i2p_addr) { tried_selected = true; @@ -275,7 +281,7 @@ BOOST_AUTO_TEST_CASE(addrman_select_special) // since the only ipv4 address is on the new table, ensure that the new // table gets selected even if new_only is false. if the table was being // selected at random, this test will sporadically fail - BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1); + BOOST_CHECK(addrman->Select(/*new_only=*/false, {NET_IPV4}).first == addr1); } BOOST_AUTO_TEST_CASE(addrman_new_collisions) @@ -575,7 +581,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy) // 101.8.0.0/16 AS8 BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) { - std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); + std::vector<bool> asmap = FromBytes(test::data::asmap); NetGroupManager ngm_asmap{asmap}; CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE); @@ -629,7 +635,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) { - std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); + std::vector<bool> asmap = FromBytes(test::data::asmap); NetGroupManager ngm_asmap{asmap}; CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); @@ -707,7 +713,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) BOOST_AUTO_TEST_CASE(addrman_serialization) { - std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); + std::vector<bool> asmap1 = FromBytes(test::data::asmap); NetGroupManager netgroupman{asmap1}; const auto ratio = GetCheckRatio(m_node); diff --git a/src/test/argsman_tests.cpp b/src/test/argsman_tests.cpp index 340208a1c9..297595a9cf 100644 --- a/src/test/argsman_tests.cpp +++ b/src/test/argsman_tests.cpp @@ -20,6 +20,8 @@ #include <boost/test/unit_test.hpp> +using util::ToString; + BOOST_FIXTURE_TEST_SUITE(argsman_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_datadir) @@ -642,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"}; @@ -661,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"); @@ -756,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); } @@ -911,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. @@ -1014,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..37a39adb9c 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,8 +23,6 @@ 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)); } - const unsigned char R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d"; @@ -37,8 +36,6 @@ const unsigned char R2Array[] = "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7"; const arith_uint256 R2L = arith_uint256V(std::vector<unsigned char>(R2Array,R2Array+32)); -const char R1LplusR2L[] = "549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C"; - const unsigned char ZeroArray[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; @@ -95,26 +92,25 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality } BOOST_CHECK(ZeroL == (OneL << 256)); - // String Constructor and Copy Constructor - BOOST_CHECK(arith_uint256S("0x" + R1L.ToString()) == R1L); - BOOST_CHECK(arith_uint256S("0x" + R2L.ToString()) == R2L); - BOOST_CHECK(arith_uint256S("0x" + ZeroL.ToString()) == ZeroL); - BOOST_CHECK(arith_uint256S("0x" + OneL.ToString()) == OneL); - BOOST_CHECK(arith_uint256S("0x" + MaxL.ToString()) == MaxL); - BOOST_CHECK(arith_uint256S(R1L.ToString()) == R1L); - BOOST_CHECK(arith_uint256S(" 0x" + R1L.ToString() + " ") == R1L); - BOOST_CHECK(arith_uint256S("") == ZeroL); - BOOST_CHECK(R1L == arith_uint256S(R1ArrayHex)); + // Construct from hex string + BOOST_CHECK_EQUAL(UintToArith256(uint256::FromHex(R1L.ToString()).value()), R1L); + BOOST_CHECK_EQUAL(UintToArith256(uint256::FromHex(R2L.ToString()).value()), R2L); + BOOST_CHECK_EQUAL(UintToArith256(uint256::FromHex(ZeroL.ToString()).value()), ZeroL); + BOOST_CHECK_EQUAL(UintToArith256(uint256::FromHex(OneL.ToString()).value()), OneL); + BOOST_CHECK_EQUAL(UintToArith256(uint256::FromHex(MaxL.ToString()).value()), MaxL); + BOOST_CHECK_EQUAL(UintToArith256(uint256::FromHex(R1ArrayHex).value()), R1L); + + // Copy constructor BOOST_CHECK(arith_uint256(R1L) == R1L); BOOST_CHECK((arith_uint256(R1L^R2L)^R2L) == R1L); BOOST_CHECK(arith_uint256(ZeroL) == ZeroL); BOOST_CHECK(arith_uint256(OneL) == OneL); // uint64_t constructor - BOOST_CHECK((R1L & arith_uint256S("0xffffffffffffffff")) == arith_uint256(R1LLow64)); - BOOST_CHECK(ZeroL == arith_uint256(0)); - BOOST_CHECK(OneL == arith_uint256(1)); - BOOST_CHECK(arith_uint256S("0xffffffffffffffff") == arith_uint256(0xffffffffffffffffULL)); + BOOST_CHECK_EQUAL(R1L & arith_uint256{0xffffffffffffffff}, arith_uint256{R1LLow64}); + BOOST_CHECK_EQUAL(ZeroL, arith_uint256{0}); + BOOST_CHECK_EQUAL(OneL, arith_uint256{1}); + BOOST_CHECK_EQUAL(arith_uint256{0xffffffffffffffff}, arith_uint256{0xffffffffffffffffULL}); // Assignment (from base_uint) arith_uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL); @@ -278,12 +274,15 @@ 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); } BOOST_AUTO_TEST_CASE( plusMinus ) { arith_uint256 TmpL = 0; - BOOST_CHECK(R1L + R2L == arith_uint256S(R1LplusR2L)); + BOOST_CHECK_EQUAL(R1L + R2L, UintToArith256(uint256{"549fb09fea236a1ea3e31d4d58f1b1369288d204211ca751527cfc175767850c"})); TmpL += R1L; BOOST_CHECK(TmpL == R1L); TmpL += R2L; @@ -347,8 +346,8 @@ BOOST_AUTO_TEST_CASE( multiply ) BOOST_AUTO_TEST_CASE( divide ) { - arith_uint256 D1L{arith_uint256S("AD7133AC1977FA2B7")}; - arith_uint256 D2L{arith_uint256S("ECD751716")}; + arith_uint256 D1L{UintToArith256(uint256{"00000000000000000000000000000000000000000000000ad7133ac1977fa2b7"})}; + arith_uint256 D2L{UintToArith256(uint256{"0000000000000000000000000000000000000000000000000000000ecd751716"})}; BOOST_CHECK((R1L / D1L).ToString() == "00000000000000000b8ac01106981635d9ed112290f8895545a7654dde28fb3a"); BOOST_CHECK((R1L / D2L).ToString() == "000000000873ce8efec5b67150bad3aa8c5fcb70e947586153bf2cec7c37c57a"); BOOST_CHECK(R1L / OneL == R1L); @@ -562,4 +561,51 @@ BOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% cover CHECKBITWISEOPERATOR(R1,~R2,&) } +BOOST_AUTO_TEST_CASE(conversion) +{ + for (const arith_uint256& arith : {ZeroL, OneL, R1L, R2L}) { + const auto u256{uint256::FromHex(arith.GetHex()).value()}; + BOOST_CHECK_EQUAL(UintToArith256(ArithToUint256(arith)), arith); + BOOST_CHECK_EQUAL(UintToArith256(u256), arith); + BOOST_CHECK_EQUAL(u256, ArithToUint256(arith)); + BOOST_CHECK_EQUAL(ArithToUint256(arith).GetHex(), UintToArith256(u256).GetHex()); + } + + for (uint8_t num : {0, 1, 0xff}) { + BOOST_CHECK_EQUAL(UintToArith256(uint256{num}), arith_uint256{num}); + BOOST_CHECK_EQUAL(uint256{num}, ArithToUint256(arith_uint256{num})); + BOOST_CHECK_EQUAL(UintToArith256(uint256{num}), num); + } +} + +BOOST_AUTO_TEST_CASE(operator_with_self) +{ + /* Clang 16 and earlier detects v -= v and v /= v as self-assignments + to 0 and 1 respectively. + See: https://github.com/llvm/llvm-project/issues/42469 + and the fix in commit c5302325b2a62d77cf13dd16cd5c19141862fed0 . + + This makes some sense for arithmetic classes, but could be considered a bug + elsewhere. Disable the warning here so that the code can be tested, but the + warning should remain on as there will likely always be a better way to + express this. + */ +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#endif + arith_uint256 v{2}; + v *= v; + BOOST_CHECK_EQUAL(v, arith_uint256{4}); + v /= v; + BOOST_CHECK_EQUAL(v, arith_uint256{1}); + v += v; + BOOST_CHECK_EQUAL(v, arith_uint256{2}); + v -= v; + BOOST_CHECK_EQUAL(v, arith_uint256{0}); +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 4617beecd9..be3b0c2d1f 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -5,6 +5,8 @@ #include <util/strencodings.h> #include <boost/test/unit_test.hpp> + +#include <algorithm> #include <string> using namespace std::literals; @@ -24,7 +26,7 @@ BOOST_AUTO_TEST_CASE(base32_testvectors) BOOST_CHECK_EQUAL(strEnc, vstrOutNoPadding[i]); auto dec = DecodeBase32(vstrOut[i]); BOOST_REQUIRE(dec); - BOOST_CHECK_MESSAGE(MakeByteSpan(*dec) == MakeByteSpan(vstrIn[i]), vstrOut[i]); + BOOST_CHECK_MESSAGE(std::ranges::equal(*dec, vstrIn[i]), vstrOut[i]); } // Decoding strings with embedded NUL characters should fail diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index bb3defb93e..5e97c9f4d6 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -17,6 +17,7 @@ #include <string> using namespace std::literals; +using namespace util::hex_literals; BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup) @@ -72,7 +73,7 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) // check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end. BOOST_CHECK(!DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t a", result, 3)); BOOST_CHECK( DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t ", result, 3)); - std::vector<unsigned char> expected = ParseHex("971a55"); + constexpr auto expected{"971a55"_hex_u8}; BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); BOOST_CHECK(DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oh"s, result, 100)); @@ -84,14 +85,14 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) BOOST_AUTO_TEST_CASE(base58_random_encode_decode) { for (int n = 0; n < 1000; ++n) { - unsigned int len = 1 + InsecureRandBits(8); - unsigned int zeroes = InsecureRandBool() ? InsecureRandRange(len + 1) : 0; - auto data = Cat(std::vector<unsigned char>(zeroes, '\000'), g_insecure_rand_ctx.randbytes(len - zeroes)); + unsigned int len = 1 + m_rng.randbits(8); + unsigned int zeroes = m_rng.randbool() ? m_rng.randrange(len + 1) : 0; + auto data = Cat(std::vector<unsigned char>(zeroes, '\000'), m_rng.randbytes(len - zeroes)); auto encoded = EncodeBase58Check(data); std::vector<unsigned char> decoded; - auto ok_too_small = DecodeBase58Check(encoded, decoded, InsecureRandRange(len)); + auto ok_too_small = DecodeBase58Check(encoded, decoded, m_rng.randrange(len)); BOOST_CHECK(!ok_too_small); - auto ok = DecodeBase58Check(encoded, decoded, len + InsecureRandRange(257 - len)); + auto ok = DecodeBase58Check(encoded, decoded, len + m_rng.randrange(257 - len)); BOOST_CHECK(ok); BOOST_CHECK(data == decoded); } diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index 6462aa82fb..b9d0d2b241 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -5,6 +5,8 @@ #include <util/strencodings.h> #include <boost/test/unit_test.hpp> + +#include <algorithm> #include <string> using namespace std::literals; @@ -21,7 +23,7 @@ BOOST_AUTO_TEST_CASE(base64_testvectors) BOOST_CHECK_EQUAL(strEnc, vstrOut[i]); auto dec = DecodeBase64(strEnc); BOOST_REQUIRE(dec); - BOOST_CHECK_MESSAGE(MakeByteSpan(*dec) == MakeByteSpan(vstrIn[i]), vstrOut[i]); + BOOST_CHECK_MESSAGE(std::ranges::equal(*dec, vstrIn[i]), vstrOut[i]); } { diff --git a/src/test/bip324_tests.cpp b/src/test/bip324_tests.cpp index 1ed7e23bcf..adabb7ef57 100644 --- a/src/test/bip324_tests.cpp +++ b/src/test/bip324_tests.cpp @@ -11,6 +11,7 @@ #include <test/util/setup_common.h> #include <util/strencodings.h> +#include <algorithm> #include <array> #include <cstddef> #include <cstdint> @@ -20,6 +21,7 @@ namespace { +struct BIP324Test : BasicTestingSetup { void TestBIP324PacketVector( uint32_t in_idx, const std::string& in_priv_ours_hex, @@ -62,9 +64,9 @@ void TestBIP324PacketVector( BOOST_CHECK(cipher); // Compare session variables. - BOOST_CHECK(Span{out_session_id} == cipher.GetSessionID()); - BOOST_CHECK(Span{mid_send_garbage} == cipher.GetSendGarbageTerminator()); - BOOST_CHECK(Span{mid_recv_garbage} == cipher.GetReceiveGarbageTerminator()); + BOOST_CHECK(std::ranges::equal(out_session_id, cipher.GetSessionID())); + BOOST_CHECK(std::ranges::equal(mid_send_garbage, cipher.GetSendGarbageTerminator())); + BOOST_CHECK(std::ranges::equal(mid_recv_garbage, cipher.GetReceiveGarbageTerminator())); // Vector of encrypted empty messages, encrypted in order to seek to the right position. std::vector<std::vector<std::byte>> dummies(in_idx); @@ -89,7 +91,7 @@ void TestBIP324PacketVector( BOOST_CHECK(out_ciphertext == ciphertext); } else { BOOST_CHECK(ciphertext.size() >= out_ciphertext_endswith.size()); - BOOST_CHECK(Span{out_ciphertext_endswith} == Span{ciphertext}.last(out_ciphertext_endswith.size())); + BOOST_CHECK(std::ranges::equal(out_ciphertext_endswith, Span{ciphertext}.last(out_ciphertext_endswith.size()))); } for (unsigned error = 0; error <= 12; ++error) { @@ -109,13 +111,13 @@ void TestBIP324PacketVector( BOOST_CHECK(dec_cipher); // Compare session variables. - BOOST_CHECK((Span{out_session_id} == dec_cipher.GetSessionID()) == (error != 1)); - BOOST_CHECK((Span{mid_send_garbage} == dec_cipher.GetSendGarbageTerminator()) == (error != 1)); - BOOST_CHECK((Span{mid_recv_garbage} == dec_cipher.GetReceiveGarbageTerminator()) == (error != 1)); + BOOST_CHECK(std::ranges::equal(out_session_id, dec_cipher.GetSessionID()) == (error != 1)); + BOOST_CHECK(std::ranges::equal(mid_send_garbage, dec_cipher.GetSendGarbageTerminator()) == (error != 1)); + BOOST_CHECK(std::ranges::equal(mid_recv_garbage, dec_cipher.GetReceiveGarbageTerminator()) == (error != 1)); // Seek to the numbered packet. if (in_idx == 0 && error == 12) continue; - uint32_t dec_idx = in_idx ^ (error == 12 ? (1U << InsecureRandRange(16)) : 0); + uint32_t dec_idx = in_idx ^ (error == 12 ? (1U << m_rng.randrange(16)) : 0); for (uint32_t i = 0; i < dec_idx; ++i) { unsigned use_idx = i < in_idx ? i : 0; bool dec_ignore{false}; @@ -127,7 +129,7 @@ void TestBIP324PacketVector( // Decrypt length auto to_decrypt = ciphertext; if (error >= 2 && error <= 9) { - to_decrypt[InsecureRandRange(to_decrypt.size())] ^= std::byte(1U << (error - 2)); + to_decrypt[m_rng.randrange(to_decrypt.size())] ^= std::byte(1U << (error - 2)); } // Decrypt length and resize ciphertext to accommodate. @@ -138,7 +140,7 @@ void TestBIP324PacketVector( auto dec_aad = in_aad; if (error == 10) { if (in_aad.size() == 0) continue; - dec_aad[InsecureRandRange(dec_aad.size())] ^= std::byte(1U << InsecureRandRange(8)); + dec_aad[m_rng.randrange(dec_aad.size())] ^= std::byte(1U << m_rng.randrange(8)); } if (error == 11) dec_aad.push_back({}); @@ -155,10 +157,11 @@ void TestBIP324PacketVector( } } } +}; // struct BIP324Test } // namespace -BOOST_FIXTURE_TEST_SUITE(bip324_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(bip324_tests, BIP324Test) BOOST_AUTO_TEST_CASE(packet_test_vectors) { // BIP324 key derivation uses network magic in the HKDF process. We use mainnet params here diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp index be515a9eac..4ecc15041c 100644 --- a/src/test/blockchain_tests.cpp +++ b/src/test/blockchain_tests.cpp @@ -5,12 +5,16 @@ #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> #include <cstdlib> +using util::ToString; + /* Equality between doubles is imprecise. Comparison should be done * with a small threshold of tolerance, rather than exact equality. */ @@ -74,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/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 05355fb21d..3a33bdb7ec 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -14,31 +14,36 @@ #include <boost/test/unit_test.hpp> -std::vector<CTransactionRef> extra_txn; +const std::vector<CTransactionRef> empty_extra_txn; BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegTestingSetup) -static CBlock BuildBlockTestCase() { - CBlock block; +static CMutableTransaction BuildTransactionTestCase() { CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].scriptSig.resize(10); tx.vout.resize(1); tx.vout[0].nValue = 42; + return tx; +} + +static CBlock BuildBlockTestCase(FastRandomContext& ctx) { + CBlock block; + CMutableTransaction tx = BuildTransactionTestCase(); block.vtx.resize(3); block.vtx[0] = MakeTransactionRef(tx); block.nVersion = 42; - block.hashPrevBlock = InsecureRand256(); + block.hashPrevBlock = ctx.rand256(); block.nBits = 0x207fffff; - tx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256()); + tx.vin[0].prevout.hash = Txid::FromUint256(ctx.rand256()); tx.vin[0].prevout.n = 0; block.vtx[1] = MakeTransactionRef(tx); tx.vin.resize(10); for (size_t i = 0; i < tx.vin.size(); i++) { - tx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256()); + tx.vin[i].prevout.hash = Txid::FromUint256(ctx.rand256()); tx.vin[i].prevout.n = 0; } block.vtx[2] = MakeTransactionRef(tx); @@ -58,7 +63,8 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) { CTxMemPool& pool = *Assert(m_node.mempool); TestMemPoolEntryHelper entry; - CBlock block(BuildBlockTestCase()); + auto rand_ctx(FastRandomContext(uint256{42})); + CBlock block(BuildBlockTestCase(rand_ctx)); LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[2])); @@ -66,7 +72,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) // Do a simple ShortTxIDs RT { - CBlockHeaderAndShortTxIDs shortIDs{block}; + CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx.rand64()}; DataStream stream{}; stream << shortIDs; @@ -75,7 +81,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(&pool); - BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); + BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK); BOOST_CHECK( partialBlock.IsTxAvailable(0)); BOOST_CHECK(!partialBlock.IsTxAvailable(1)); BOOST_CHECK( partialBlock.IsTxAvailable(2)); @@ -123,8 +129,8 @@ public: stream << orig; stream >> *this; } - explicit TestHeaderAndShortIDs(const CBlock& block) : - TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block}) {} + explicit TestHeaderAndShortIDs(const CBlock& block, FastRandomContext& ctx) : + TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block, ctx.rand64()}) {} uint64_t GetShortID(const Wtxid& txhash) const { DataStream stream{}; @@ -141,7 +147,8 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) { CTxMemPool& pool = *Assert(m_node.mempool); TestMemPoolEntryHelper entry; - CBlock block(BuildBlockTestCase()); + auto rand_ctx(FastRandomContext(uint256{42})); + CBlock block(BuildBlockTestCase(rand_ctx)); LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[2])); @@ -151,7 +158,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) // Test with pre-forwarding tx 1, but not coinbase { - TestHeaderAndShortIDs shortIDs(block); + TestHeaderAndShortIDs shortIDs(block, rand_ctx); shortIDs.prefilledtxn.resize(1); shortIDs.prefilledtxn[0] = {1, block.vtx[1]}; shortIDs.shorttxids.resize(2); @@ -165,7 +172,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(&pool); - BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); + BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK); BOOST_CHECK(!partialBlock.IsTxAvailable(0)); BOOST_CHECK( partialBlock.IsTxAvailable(1)); BOOST_CHECK( partialBlock.IsTxAvailable(2)); @@ -211,7 +218,8 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) { CTxMemPool& pool = *Assert(m_node.mempool); TestMemPoolEntryHelper entry; - CBlock block(BuildBlockTestCase()); + auto rand_ctx(FastRandomContext(uint256{42})); + CBlock block(BuildBlockTestCase(rand_ctx)); LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[1])); @@ -221,7 +229,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool { - TestHeaderAndShortIDs shortIDs(block); + TestHeaderAndShortIDs shortIDs(block, rand_ctx); shortIDs.prefilledtxn.resize(2); shortIDs.prefilledtxn[0] = {0, block.vtx[0]}; shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1 @@ -235,7 +243,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(&pool); - BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); + BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK); BOOST_CHECK( partialBlock.IsTxAvailable(0)); BOOST_CHECK( partialBlock.IsTxAvailable(1)); BOOST_CHECK( partialBlock.IsTxAvailable(2)); @@ -261,17 +269,14 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) { CTxMemPool& pool = *Assert(m_node.mempool); - CMutableTransaction coinbase; - coinbase.vin.resize(1); - coinbase.vin[0].scriptSig.resize(10); - coinbase.vout.resize(1); - coinbase.vout[0].nValue = 42; + CMutableTransaction coinbase = BuildTransactionTestCase(); CBlock block; + auto rand_ctx(FastRandomContext(uint256{42})); block.vtx.resize(1); block.vtx[0] = MakeTransactionRef(std::move(coinbase)); block.nVersion = 42; - block.hashPrevBlock = InsecureRand256(); + block.hashPrevBlock = rand_ctx.rand256(); block.nBits = 0x207fffff; bool mutated; @@ -281,7 +286,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) // Test simple header round-trip with only coinbase { - CBlockHeaderAndShortTxIDs shortIDs{block}; + CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx.rand64()}; DataStream stream{}; stream << shortIDs; @@ -290,7 +295,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(&pool); - BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); + BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK); BOOST_CHECK(partialBlock.IsTxAvailable(0)); CBlock block2; @@ -302,9 +307,56 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) } } +BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) { + CTxMemPool& pool = *Assert(m_node.mempool); + TestMemPoolEntryHelper entry; + auto rand_ctx(FastRandomContext(uint256{42})); + + CMutableTransaction mtx = BuildTransactionTestCase(); + mtx.vin[0].prevout.hash = Txid::FromUint256(rand_ctx.rand256()); + mtx.vin[0].prevout.n = 0; + const CTransactionRef non_block_tx = MakeTransactionRef(std::move(mtx)); + + CBlock block(BuildBlockTestCase(rand_ctx)); + std::vector<CTransactionRef> extra_txn; + extra_txn.resize(10); + + LOCK2(cs_main, pool.cs); + pool.addUnchecked(entry.FromTx(block.vtx[2])); + BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0); + // Ensure the non_block_tx is actually not in the block + for (const auto &block_tx : block.vtx) { + BOOST_CHECK_NE(block_tx->GetHash(), non_block_tx->GetHash()); + } + // Ensure block.vtx[1] is not in pool + BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()), nullptr); + + { + const CBlockHeaderAndShortTxIDs cmpctblock{block, rand_ctx.rand64()}; + PartiallyDownloadedBlock partial_block(&pool); + PartiallyDownloadedBlock partial_block_with_extra(&pool); + + BOOST_CHECK(partial_block.InitData(cmpctblock, extra_txn) == READ_STATUS_OK); + BOOST_CHECK( partial_block.IsTxAvailable(0)); + BOOST_CHECK(!partial_block.IsTxAvailable(1)); + BOOST_CHECK( partial_block.IsTxAvailable(2)); + + // Add an unrelated tx to extra_txn: + extra_txn[0] = non_block_tx; + // and a tx from the block that's not in the mempool: + extra_txn[1] = block.vtx[1]; + + BOOST_CHECK(partial_block_with_extra.InitData(cmpctblock, extra_txn) == READ_STATUS_OK); + BOOST_CHECK(partial_block_with_extra.IsTxAvailable(0)); + // This transaction is now available via extra_txn: + BOOST_CHECK(partial_block_with_extra.IsTxAvailable(1)); + BOOST_CHECK(partial_block_with_extra.IsTxAvailable(2)); + } +} + BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BlockTransactionsRequest req1; - req1.blockhash = InsecureRand256(); + req1.blockhash = m_rng.rand256(); req1.indexes.resize(4); req1.indexes[0] = 0; req1.indexes[1] = 1; @@ -328,7 +380,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) { // Check that the highest legal index is decoded correctly BlockTransactionsRequest req0; - req0.blockhash = InsecureRand256(); + req0.blockhash = m_rng.rand256(); req0.indexes.resize(1); req0.indexes[0] = 0xffff; DataStream stream{}; @@ -346,7 +398,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) { // a request cannot be created by serializing a real BlockTransactionsRequest // due to the overflow, so here we'll serialize from raw deltas. BlockTransactionsRequest req0; - req0.blockhash = InsecureRand256(); + req0.blockhash = m_rng.rand256(); req0.indexes.resize(3); req0.indexes[0] = 0x7000; req0.indexes[1] = 0x10000 - 0x7000 - 2; diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index d44d84af93..48ae874fcd 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -67,7 +67,8 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev, const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey) { - std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get()}.CreateNewBlock(scriptPubKey); + BlockAssembler::Options options; + std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(scriptPubKey); CBlock& block = pblocktemplate->block; block.hashPrevBlock = prev->GetBlockHash(); block.nTime = prev->nTime + 1; @@ -102,7 +103,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex, CBlockHeader header = block->GetBlockHeader(); BlockValidationState state; - if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, true, state, &pindex)) { + if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({{header}}, true, state, &pindex)) { return false; } } @@ -143,7 +144,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) BOOST_REQUIRE(filter_index.StartBackgroundSync()); // Allow filter index to catch up with the block index. - IndexWaitSynced(filter_index, *Assert(m_node.shutdown)); + IndexWaitSynced(filter_index, *Assert(m_node.shutdown_signal)); // Check that filter index has all blocks that were in the chain before it started. { 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 efe0983698..c2b95dd861 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> @@ -27,13 +28,13 @@ BOOST_FIXTURE_TEST_SUITE(blockmanager_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos) { const auto params {CreateChainParams(ArgsManager{}, ChainType::MAIN)}; - KernelNotifications notifications{*Assert(m_node.shutdown), m_node.exit_status}; + KernelNotifications notifications{Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)}; const BlockManager::Options blockman_opts{ .chainparams = *params, .blocks_dir = m_args.GetBlocksDirPath(), .notifications = notifications, }; - BlockManager blockman{*Assert(m_node.shutdown), blockman_opts}; + BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts}; // simulate adding a genesis block normally BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0).nPos, BLOCK_SERIALIZATION_HEADER_SIZE); // simulate what happens during reindex @@ -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,20 +128,20 @@ 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)); } BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file) { - KernelNotifications notifications{*Assert(m_node.shutdown), m_node.exit_status}; + KernelNotifications notifications{Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)}; node::BlockManager::Options blockman_opts{ .chainparams = Params(), .blocks_dir = m_args.GetBlocksDirPath(), .notifications = notifications, }; - BlockManager blockman{*Assert(m_node.shutdown), blockman_opts}; + BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts}; // Test blocks with no transactions, not even a coinbase CBlock block1; diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index cbf85277a8..1c732a8267 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -22,33 +22,39 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) +using namespace util::hex_literals; + +namespace bloom_tests { +struct BloomTest : public BasicTestingSetup { + std::vector<unsigned char> RandomData(); +}; +} // namespace bloom_tests + +BOOST_FIXTURE_TEST_SUITE(bloom_tests, BloomTest) BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) { CBloomFilter filter(3, 0.01, 0, BLOOM_UPDATE_ALL); - BOOST_CHECK_MESSAGE( !filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter should be empty!"); - filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); - BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!"); + BOOST_CHECK_MESSAGE( !filter.contains("99108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8), "Bloom filter should be empty!"); + filter.insert("99108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8); + BOOST_CHECK_MESSAGE( filter.contains("99108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8), "Bloom filter doesn't contain just-inserted object!"); // One bit different in first byte - BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter contains something it shouldn't!"); + BOOST_CHECK_MESSAGE(!filter.contains("19108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8), "Bloom filter contains something it shouldn't!"); - filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); - BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "Bloom filter doesn't contain just-inserted object (2)!"); + filter.insert("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"_hex_u8); + BOOST_CHECK_MESSAGE(filter.contains("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"_hex_u8), "Bloom filter doesn't contain just-inserted object (2)!"); - filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")); - BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!"); + filter.insert("b9300670b4c5366e95b2699e8b18bc75e5f729c5"_hex_u8); + BOOST_CHECK_MESSAGE(filter.contains("b9300670b4c5366e95b2699e8b18bc75e5f729c5"_hex_u8), "Bloom filter doesn't contain just-inserted object (3)!"); DataStream stream{}; stream << filter; - std::vector<uint8_t> expected = ParseHex("03614e9b050000000000000001"); - auto result{MakeUCharSpan(stream)}; - - BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); + constexpr auto expected{"03614e9b050000000000000001"_hex}; + BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); - BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!"); + BOOST_CHECK_MESSAGE( filter.contains("99108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8), "Bloom filter doesn't contain just-inserted object!"); } BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) @@ -56,24 +62,22 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) // Same test as bloom_create_insert_serialize, but we add a nTweak of 100 CBloomFilter filter(3, 0.01, 2147483649UL, BLOOM_UPDATE_ALL); - filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); - BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!"); + filter.insert("99108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8); + BOOST_CHECK_MESSAGE( filter.contains("99108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8), "Bloom filter doesn't contain just-inserted object!"); // One bit different in first byte - BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter contains something it shouldn't!"); + BOOST_CHECK_MESSAGE(!filter.contains("19108ad8ed9bb6274d3980bab5a85c048f0950c8"_hex_u8), "Bloom filter contains something it shouldn't!"); - filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); - BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "Bloom filter doesn't contain just-inserted object (2)!"); + filter.insert("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"_hex_u8); + BOOST_CHECK_MESSAGE(filter.contains("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"_hex_u8), "Bloom filter doesn't contain just-inserted object (2)!"); - filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")); - BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!"); + filter.insert("b9300670b4c5366e95b2699e8b18bc75e5f729c5"_hex_u8); + BOOST_CHECK_MESSAGE(filter.contains("b9300670b4c5366e95b2699e8b18bc75e5f729c5"_hex_u8), "Bloom filter doesn't contain just-inserted object (3)!"); DataStream stream{}; stream << filter; - std::vector<uint8_t> expected = ParseHex("03ce4299050000000100008001"); - auto result{MakeUCharSpan(stream)}; - - BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); + constexpr auto expected{"03ce4299050000000100008001"_hex}; + BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); } BOOST_AUTO_TEST_CASE(bloom_create_insert_key) @@ -91,17 +95,15 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key) DataStream stream{}; stream << filter; - std::vector<unsigned char> expected = ParseHex("038fc16b080000000000000001"); - auto result{MakeUCharSpan(stream)}; - - BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); + constexpr auto expected{"038fc16b080000000000000001"_hex}; + BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); } BOOST_AUTO_TEST_CASE(bloom_match) { // Random real transaction (b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b) DataStream stream{ - ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"), + "01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"_hex, }; CTransaction tx(deserialize, TX_WITH_WITNESS, stream); @@ -112,37 +114,37 @@ 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); // byte-reversed tx hash - filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4")); + filter.insert("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4"_hex_u8); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized tx hash"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01")); + filter.insert("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01"_hex_u8); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input signature"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339")); + filter.insert("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339"_hex_u8); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input pub key"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19")); + filter.insert("04943fdd508053c75000106d3bc6e2754dbcff19"_hex_u8); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx), "Simple Bloom filter didn't add output"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431")); + filter.insert("a266436d2965547608b9e15d9032a7b9d64fa431"_hex_u8); 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,19 +154,19 @@ 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); - filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431")); + filter.insert("0000006d2965547608b9e15d9032a7b9d64fa431"_hex_u8); 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 +175,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 +183,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 +194,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 +202,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); @@ -215,13 +217,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) // With 4 txes CBlock block; DataStream stream{ - ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), + "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"_hex, }; stream >> TX_WITH_WITNESS(block); 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 +231,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; @@ -242,7 +244,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) // This should match the third transaction because it spends the output matched // It also matches the fourth transaction, which spends to the pubkey again - filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af")); + filter.insert("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af"_hex_u8); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); @@ -251,13 +253,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); @@ -272,13 +274,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) // With 4 txes CBlock block; DataStream stream{ - ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), + "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"_hex, }; stream >> TX_WITH_WITNESS(block); 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 +288,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; @@ -299,7 +301,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) // This should not match the third transaction though it spends the output matched // It will match the fourth transaction, which has another pay-to-pubkey output to the same address - filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af")); + filter.insert("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af"_hex_u8); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); @@ -308,10 +310,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); @@ -326,20 +328,20 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) // With one tx CBlock block; DataStream stream{ - ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000"), + "0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000"_hex, }; stream >> TX_WITH_WITNESS(block); 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; @@ -352,10 +354,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) DataStream merkleStream{}; merkleStream << merkleBlock; - std::vector<uint8_t> expected = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); - auto result{MakeUCharSpan(merkleStream)}; - - BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), result.begin(), result.end()); + constexpr auto expected{"0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"_hex}; + BOOST_CHECK_EQUAL_COLLECTIONS(merkleStream.begin(), merkleStream.end(), expected.begin(), expected.end()); } BOOST_AUTO_TEST_CASE(merkle_block_4) @@ -364,13 +364,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) // With 7 txes CBlock block; DataStream stream{ - ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"_hex, }; stream >> TX_WITH_WITNESS(block); 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); @@ -412,23 +412,23 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_p2pubkey_only) // With 7 txes CBlock block; DataStream stream{ - ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"_hex, }; stream >> TX_WITH_WITNESS(block); CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_P2PUBKEY_ONLY); // Match the generation pubkey - filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91")); + filter.insert("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91"_hex_u8); // ...and the output address of the 4th transaction - filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); + filter.insert("b6efd80d99179f4f4ff6f4dd0a007d018c385d21"_hex_u8); CMerkleBlock merkleBlock(block, filter); 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) @@ -437,34 +437,33 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) // With 7 txes CBlock block; DataStream stream{ - ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"_hex, }; stream >> TX_WITH_WITNESS(block); CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); // Match the generation pubkey - filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91")); + filter.insert("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91"_hex_u8); // ...and the output address of the 4th transaction - filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); + filter.insert("b6efd80d99179f4f4ff6f4dd0a007d018c385d21"_hex_u8); CMerkleBlock merkleBlock(block, filter); 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() +std::vector<unsigned char> BloomTest::RandomData() { - uint256 r = InsecureRand256(); + uint256 r = m_rng.rand256(); return std::vector<unsigned char>(r.begin(), r.end()); } 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..a9a1e47070 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -28,13 +28,15 @@ 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 }; -BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, NoLockLoggingTestingSetup) +struct CheckQueueTest : NoLockLoggingTestingSetup { + void Correct_Queue_range(std::vector<size_t> range); +}; static const unsigned int QUEUE_BATCH_SIZE = 128; static const int SCRIPT_CHECK_THREADS = 3; @@ -156,7 +158,7 @@ typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue; /** This test case checks that the CCheckQueue works properly * with each specified size_t Checks pushed. */ -static void Correct_Queue_range(std::vector<size_t> range) +void CheckQueueTest::Correct_Queue_range(std::vector<size_t> range) { auto small_queue = std::make_unique<Correct_Queue>(QUEUE_BATCH_SIZE, SCRIPT_CHECK_THREADS); // Make vChecks here to save on malloc (this test can be slow...) @@ -168,7 +170,7 @@ static void Correct_Queue_range(std::vector<size_t> range) CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get()); while (total) { vChecks.clear(); - vChecks.resize(std::min<size_t>(total, InsecureRandRange(10))); + vChecks.resize(std::min<size_t>(total, m_rng.randrange(10))); total -= vChecks.size(); control.Add(std::move(vChecks)); } @@ -177,6 +179,8 @@ static void Correct_Queue_range(std::vector<size_t> range) } } +BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, CheckQueueTest) + /** Test that 0 checks is correct */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) @@ -207,7 +211,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random) { std::vector<size_t> range; range.reserve(100000/1000); - for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)InsecureRandRange(std::min((size_t)1000, ((size_t)100000) - i)))) + for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)m_rng.randrange(std::min((size_t)1000, ((size_t)100000) - i)))) range.push_back(i); Correct_Queue_range(range); } @@ -221,7 +225,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) CCheckQueueControl<FailingCheck> control(fail_queue.get()); size_t remaining = i; while (remaining) { - size_t r = InsecureRandRange(10); + size_t r = m_rng.randrange(10); std::vector<FailingCheck> vChecks; vChecks.reserve(r); @@ -268,7 +272,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) { CCheckQueueControl<UniqueCheck> control(queue.get()); while (total) { - size_t r = InsecureRandRange(10); + size_t r = m_rng.randrange(10); std::vector<UniqueCheck> vChecks; for (size_t k = 0; k < r && total; k++) vChecks.emplace_back(--total); @@ -300,7 +304,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) { CCheckQueueControl<MemoryCheck> control(queue.get()); while (total) { - size_t r = InsecureRandRange(10); + size_t r = m_rng.randrange(10); std::vector<MemoryCheck> vChecks; for (size_t k = 0; k < r && total; k++) { total--; diff --git a/src/test/cluster_linearize_tests.cpp b/src/test/cluster_linearize_tests.cpp new file mode 100644 index 0000000000..265ccdc805 --- /dev/null +++ b/src/test/cluster_linearize_tests.cpp @@ -0,0 +1,177 @@ +// 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 { + +/** Special magic value that indicates to TestDepGraphSerialization that a cluster entry represents + * a hole. */ +constexpr std::pair<FeeFrac, TestBitSet> HOLE{FeeFrac{0, 0x3FFFFF}, {}}; + +template<typename SetType> +void TestDepGraphSerialization(const std::vector<std::pair<FeeFrac, SetType>>& cluster, const std::string& hexenc) +{ + // Construct DepGraph from cluster argument. + DepGraph<SetType> depgraph; + SetType holes; + for (ClusterIndex i = 0; i < cluster.size(); ++i) { + depgraph.AddTransaction(cluster[i].first); + if (cluster[i] == HOLE) holes.Set(i); + } + for (ClusterIndex i = 0; i < cluster.size(); ++i) { + depgraph.AddDependencies(cluster[i].second, i); + } + depgraph.RemoveTransactions(holes); + + // 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 */ + ); + + // 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] (_ being holes). Internally serialized + // in order A,B,C,D,E. + TestDepGraphSerialization<TestBitSet>( + {HOLE, {{1, 3}, {4, 6}}, HOLE, HOLE, {{1, 2}, {}}, HOLE, {{3, 1}, {}}, HOLE, HOLE, HOLE, {{1, 1}, {1}}, HOLE, HOLE, {{2, 1}, {4}}}, + "02" /* A size */ + "02" /* A fee */ + "03" /* A insertion position (3 holes): _, _, _, A */ + "01" /* B size */ + "06" /* B fee */ + "06" /* B insertion position (skip B->A dependency, skip 4 inserts, add 1 hole): _, _, _, A, _, B */ + "01" /* C size */ + "04" /* C fee */ + "01" /* C->A dependency (skip C->B dependency) */ + "0b" /* C insertion position (skip 6 inserts, add 5 holes): _, _, _, A, _, B, _, _, _, _, _, C */ + "03" /* D size */ + "02" /* D fee */ + "01" /* D->B dependency (skip D->C dependency) */ + "00" /* D->A dependency (no skips) */ + "0b" /* D insertion position (skip 11 inserts): _, D, _, _, A, _, B, _, _, _, _, _, C */ + "01" /* E size */ + "02" /* E fee */ + "00" /* E->D dependency (no skips) */ + "04" /* E insertion position (skip E->C dependency, E->B and E->A are implied, skip 3 + inserts): _, 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..0d18cd0c2b 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -19,6 +19,8 @@ #include <boost/test/unit_test.hpp> +using namespace util::hex_literals; + int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out); void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight); @@ -35,10 +37,13 @@ bool operator==(const Coin &a, const Coin &b) { class CCoinsViewTest : public CCoinsView { + FastRandomContext& m_rng; uint256 hashBestBlock_; std::map<COutPoint, Coin> map_; public: + CCoinsViewTest(FastRandomContext& rng) : m_rng{rng} {} + [[nodiscard]] bool GetCoin(const COutPoint& outpoint, Coin& coin) const override { std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); @@ -46,7 +51,7 @@ public: return false; } coin = it->second; - if (coin.IsSpent() && InsecureRandBool() == 0) { + if (coin.IsSpent() && m_rng.randbool() == 0) { // Randomly return false in case of an empty entry. return false; } @@ -55,13 +60,13 @@ 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) { + if (it->second.coin.IsSpent() && m_rng.randrange(3) == 0) { // Randomly delete empty entries on write. map_.erase(it->first); } @@ -78,7 +83,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 +94,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; } }; @@ -101,6 +110,7 @@ BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; +struct CacheTest : BasicTestingSetup { // This is a large randomized insert/remove simulation test on a variable-size // stack of caches on top of CCoinsViewTest. // @@ -140,26 +150,26 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) std::vector<Txid> txids; txids.resize(NUM_SIMULATION_ITERATIONS / 8); for (unsigned int i = 0; i < txids.size(); i++) { - txids[i] = Txid::FromUint256(InsecureRand256()); + txids[i] = Txid::FromUint256(m_rng.rand256()); } for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { // Do a random modification. { - auto txid = txids[InsecureRandRange(txids.size())]; // txid we're going to modify in this iteration. + auto txid = txids[m_rng.randrange(txids.size())]; // txid we're going to modify in this iteration. Coin& coin = result[COutPoint(txid, 0)]; // Determine whether to test HaveCoin before or after Access* (or both). As these functions // can influence each other's behaviour by pulling things into the cache, all combinations // are tested. - bool test_havecoin_before = InsecureRandBits(2) == 0; - bool test_havecoin_after = InsecureRandBits(2) == 0; + bool test_havecoin_before = m_rng.randbits(2) == 0; + bool test_havecoin_after = m_rng.randbits(2) == 0; bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false; // Infrequently, test usage of AccessByTxid instead of AccessCoin - the // former just delegates to the latter and returns the first unspent in a txn. - const Coin& entry = (InsecureRandRange(500) == 0) ? + const Coin& entry = (m_rng.randrange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0)); BOOST_CHECK(coin == entry); @@ -172,23 +182,23 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) BOOST_CHECK(ret == !entry.IsSpent()); } - if (InsecureRandRange(5) == 0 || coin.IsSpent()) { + if (m_rng.randrange(5) == 0 || coin.IsSpent()) { Coin newcoin; - newcoin.out.nValue = InsecureRandMoneyAmount(); + newcoin.out.nValue = RandMoney(m_rng); newcoin.nHeight = 1; // Infrequently test adding unspendable coins. - if (InsecureRandRange(16) == 0 && coin.IsSpent()) { - newcoin.out.scriptPubKey.assign(1 + InsecureRandBits(6), OP_RETURN); + if (m_rng.randrange(16) == 0 && coin.IsSpent()) { + newcoin.out.scriptPubKey.assign(1 + m_rng.randbits(6), OP_RETURN); BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable()); added_an_unspendable_entry = true; } else { // Random sizes so we can test memory usage accounting - newcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); + newcoin.out.scriptPubKey.assign(m_rng.randbits(6), 0); (coin.IsSpent() ? added_an_entry : updated_an_entry) = true; coin = newcoin; } - bool is_overwrite = !coin.IsSpent() || InsecureRand32() & 1; + bool is_overwrite = !coin.IsSpent() || m_rng.rand32() & 1; stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), is_overwrite); } else { // Spend the coin. @@ -199,15 +209,15 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) } // Once every 10 iterations, remove a random entry from the cache - if (InsecureRandRange(10) == 0) { - COutPoint out(txids[InsecureRand32() % txids.size()], 0); - int cacheid = InsecureRand32() % stack.size(); + if (m_rng.randrange(10) == 0) { + COutPoint out(txids[m_rng.rand32() % txids.size()], 0); + int cacheid = m_rng.rand32() % stack.size(); stack[cacheid]->Uncache(out); uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); } // Once every 1000 iterations and at the end, verify the full cache. - if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + if (m_rng.randrange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { for (const auto& entry : result) { bool have = stack.back()->HaveCoin(entry.first); const Coin& coin = stack.back()->AccessCoin(entry.first); @@ -225,27 +235,27 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) } } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, flush an intermediate cache - if (stack.size() > 1 && InsecureRandBool() == 0) { - unsigned int flushIndex = InsecureRandRange(stack.size() - 1); - if (fake_best_block) stack[flushIndex]->SetBestBlock(InsecureRand256()); - bool should_erase = InsecureRandRange(4) < 3; + if (stack.size() > 1 && m_rng.randbool() == 0) { + unsigned int flushIndex = m_rng.randrange(stack.size() - 1); + if (fake_best_block) stack[flushIndex]->SetBestBlock(m_rng.rand256()); + bool should_erase = m_rng.randrange(4) < 3; BOOST_CHECK(should_erase ? stack[flushIndex]->Flush() : stack[flushIndex]->Sync()); flushed_without_erase |= !should_erase; } } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && InsecureRandBool() == 0) { + if (stack.size() > 0 && m_rng.randbool() == 0) { //Remove the top cache - if (fake_best_block) stack.back()->SetBestBlock(InsecureRand256()); - bool should_erase = InsecureRandRange(4) < 3; + if (fake_best_block) stack.back()->SetBestBlock(m_rng.rand256()); + bool should_erase = m_rng.randrange(4) < 3; BOOST_CHECK(should_erase ? stack.back()->Flush() : stack.back()->Sync()); flushed_without_erase |= !should_erase; stack.pop_back(); } - if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) { + if (stack.size() == 0 || (stack.size() < 4 && m_rng.randbool())) { //Add a new cache CCoinsView* tip = base; if (stack.size() > 0) { @@ -273,24 +283,26 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) BOOST_CHECK(uncached_an_entry); BOOST_CHECK(flushed_without_erase); } +}; // struct CacheTest // Run the above simulation for multiple base types. -BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) +BOOST_FIXTURE_TEST_CASE(coins_cache_simulation_test, CacheTest) { - CCoinsViewTest base; + CCoinsViewTest base{m_rng}; SimulationTest(&base, false); CCoinsViewDB db_base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}}; SimulationTest(&db_base, true); } +struct UpdateTest : BasicTestingSetup { // Store of all necessary tx and undo data for next test typedef std::map<COutPoint, std::tuple<CTransaction,CTxUndo,Coin>> UtxoData; UtxoData utxoData; UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { assert(utxoSet.size()); - auto utxoSetIt = utxoSet.lower_bound(COutPoint(Txid::FromUint256(InsecureRand256()), 0)); + auto utxoSetIt = utxoSet.lower_bound(COutPoint(Txid::FromUint256(m_rng.rand256()), 0)); if (utxoSetIt == utxoSet.end()) { utxoSetIt = utxoSet.begin(); } @@ -298,6 +310,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { assert(utxoDataIt != utxoData.end()); return utxoDataIt; } +}; // struct UpdateTest // This test is similar to the previous test @@ -305,17 +318,16 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { // random txs are created and UpdateCoins is used to update the cache stack // In particular it is tested that spending a duplicate coinbase tx // has the expected effect (the other duplicate is overwritten at all cache levels) -BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) +BOOST_FIXTURE_TEST_CASE(updatecoins_simulation_test, UpdateTest) { - 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. std::map<COutPoint, Coin> result; // The cache stack. - CCoinsViewTest base; // A CCoinsViewTest at the bottom. + CCoinsViewTest base{m_rng}; // A CCoinsViewTest at the bottom. std::vector<std::unique_ptr<CCoinsViewCacheTest>> stack; // A stack of CCoinsViewCaches on top. stack.push_back(std::make_unique<CCoinsViewCacheTest>(&base)); // Start with one cache. @@ -326,7 +338,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) std::set<COutPoint> utxoset; for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { - uint32_t randiter = InsecureRand32(); + uint32_t randiter = m_rng.rand32(); // 19/20 txs add a new transaction if (randiter % 20 < 19) { @@ -334,14 +346,14 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) tx.vin.resize(1); tx.vout.resize(1); tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate - tx.vout[0].scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting - const int height{int(InsecureRand32() >> 1)}; + tx.vout[0].scriptPubKey.assign(m_rng.rand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting + const int height{int(m_rng.rand32() >> 1)}; Coin old_coin; // 2/20 times create a new coinbase if (randiter % 20 < 2 || coinbase_coins.size() < 10) { // 1/10 of those times create a duplicate coinbase - if (InsecureRandRange(10) == 0 && coinbase_coins.size()) { + if (m_rng.randrange(10) == 0 && coinbase_coins.size()) { auto utxod = FindRandomFrom(coinbase_coins); // Reuse the exact same coinbase tx = CMutableTransaction{std::get<0>(utxod->second)}; @@ -451,7 +463,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) } // Once every 1000 iterations and at the end, verify the full cache. - if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + if (m_rng.randrange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { for (const auto& entry : result) { bool have = stack.back()->HaveCoin(entry.first); const Coin& coin = stack.back()->AccessCoin(entry.first); @@ -461,30 +473,30 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) } // One every 10 iterations, remove a random entry from the cache - if (utxoset.size() > 1 && InsecureRandRange(30) == 0) { - stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); + if (utxoset.size() > 1 && m_rng.randrange(30) == 0) { + stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); } - if (disconnected_coins.size() > 1 && InsecureRandRange(30) == 0) { - stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first); + if (disconnected_coins.size() > 1 && m_rng.randrange(30) == 0) { + stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first); } - if (duplicate_coins.size() > 1 && InsecureRandRange(30) == 0) { - stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first); + if (duplicate_coins.size() > 1 && m_rng.randrange(30) == 0) { + stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first); } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, flush an intermediate cache - if (stack.size() > 1 && InsecureRandBool() == 0) { - unsigned int flushIndex = InsecureRandRange(stack.size() - 1); + if (stack.size() > 1 && m_rng.randbool() == 0) { + unsigned int flushIndex = m_rng.randrange(stack.size() - 1); BOOST_CHECK(stack[flushIndex]->Flush()); } } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && InsecureRandBool() == 0) { + if (stack.size() > 0 && m_rng.randbool() == 0) { BOOST_CHECK(stack.back()->Flush()); stack.pop_back(); } - if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) { + if (stack.size() == 0 || (stack.size() < 4 && m_rng.randbool())) { CCoinsView* tip = &base; if (stack.size() > 0) { tip = stack.back().get(); @@ -496,32 +508,30 @@ 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) { // Good example - DataStream ss1{ParseHex("97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35")}; + DataStream ss1{"97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"_hex}; Coin cc1; ss1 >> cc1; BOOST_CHECK_EQUAL(cc1.fCoinBase, false); BOOST_CHECK_EQUAL(cc1.nHeight, 203998U); BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000}); - BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); + BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("816115944e077fe7c803cfa57f29b36bf87c1d35"_hex_u8))))); // Good example - DataStream ss2{ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4")}; + DataStream ss2{"8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex}; Coin cc2; ss2 >> cc2; BOOST_CHECK_EQUAL(cc2.fCoinBase, true); BOOST_CHECK_EQUAL(cc2.nHeight, 120891U); BOOST_CHECK_EQUAL(cc2.out.nValue, 110397); - BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); + BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex_u8))))); // Smallest possible example - DataStream ss3{ParseHex("000006")}; + DataStream ss3{"000006"_hex}; Coin cc3; ss3 >> cc3; BOOST_CHECK_EQUAL(cc3.fCoinBase, false); @@ -530,7 +540,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0U); // scriptPubKey that ends beyond the end of the stream - DataStream ss4{ParseHex("000007")}; + DataStream ss4{"000007"_hex}; try { Coin cc4; ss4 >> cc4; @@ -543,7 +553,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) uint64_t x = 3000000000ULL; tmp << VARINT(x); BOOST_CHECK_EQUAL(HexStr(tmp), "8a95c0bb00"); - DataStream ss5{ParseHex("00008a95c0bb00")}; + DataStream ss5{"00008a95c0bb00"_hex}; try { Coin cc5; ss5 >> cc5; @@ -579,7 +589,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 +597,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 +616,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 +638,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 +650,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 +819,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; @@ -884,11 +897,12 @@ BOOST_AUTO_TEST_CASE(ccoins_write) } +struct FlushTest : BasicTestingSetup { Coin MakeCoin() { Coin coin; - coin.out.nValue = InsecureRand32(); - coin.nHeight = InsecureRandRange(4096); + coin.out.nValue = m_rng.rand32(); + coin.nHeight = m_rng.randrange(4096); coin.fCoinBase = 0; return coin; } @@ -915,18 +929,19 @@ void TestFlushBehavior( size_t cache_usage; size_t cache_size; - auto flush_all = [&all_caches](bool erase) { + auto flush_all = [this, &all_caches](bool erase) { // Flush in reverse order to ensure that flushes happen from children up. for (auto i = all_caches.rbegin(); i != all_caches.rend(); ++i) { auto& cache = *i; + 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()); + cache->SetBestBlock(m_rng.rand256()); erase ? cache->Flush() : cache->Sync(); } }; - Txid txid = Txid::FromUint256(InsecureRand256()); + Txid txid = Txid::FromUint256(m_rng.rand256()); COutPoint outp = COutPoint(txid, 0); Coin coin = MakeCoin(); // Ensure the coins views haven't seen this coin before. @@ -1017,7 +1032,7 @@ void TestFlushBehavior( // --- Bonus check: ensure that a coin added to the base view via one cache // can be spent by another cache which has never seen it. // - txid = Txid::FromUint256(InsecureRand256()); + txid = Txid::FromUint256(m_rng.rand256()); outp = COutPoint(txid, 0); coin = MakeCoin(); BOOST_CHECK(!base.HaveCoin(outp)); @@ -1040,7 +1055,7 @@ void TestFlushBehavior( // --- Bonus check 2: ensure that a FRESH, spent coin is deleted by Sync() // - txid = Txid::FromUint256(InsecureRand256()); + txid = Txid::FromUint256(m_rng.rand256()); outp = COutPoint(txid, 0); coin = MakeCoin(); CAmount coin_val = coin.out.nValue; @@ -1069,8 +1084,9 @@ void TestFlushBehavior( BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp)); BOOST_CHECK(!base.HaveCoin(outp)); } +}; // struct FlushTest -BOOST_AUTO_TEST_CASE(ccoins_flush_behavior) +BOOST_FIXTURE_TEST_CASE(ccoins_flush_behavior, FlushTest) { // Create two in-memory caches atop a leveldb view. CCoinsViewDB base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}}; 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/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp index 08814c1499..e09aad05e9 100644 --- a/src/test/coinstatsindex_tests.cpp +++ b/src/test/coinstatsindex_tests.cpp @@ -35,7 +35,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) BOOST_REQUIRE(coin_stats_index.StartBackgroundSync()); - IndexWaitSynced(coin_stats_index, *Assert(m_node.shutdown)); + IndexWaitSynced(coin_stats_index, *Assert(m_node.shutdown_signal)); // Check that CoinStatsIndex works for genesis block. const CBlockIndex* genesis_block_index; @@ -86,7 +86,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup) CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20}; BOOST_REQUIRE(index.Init()); BOOST_REQUIRE(index.StartBackgroundSync()); - IndexWaitSynced(index, *Assert(m_node.shutdown)); + IndexWaitSynced(index, *Assert(m_node.shutdown_signal)); std::shared_ptr<const CBlock> new_block; CBlockIndex* new_block_index = nullptr; { diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp index 13c2740553..7e17e6ef93 100644 --- a/src/test/compress_tests.cpp +++ b/src/test/compress_tests.cpp @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(compress_p2pk_scripts_not_on_curve) { XOnlyPubKey x_not_on_curve; do { - x_not_on_curve = XOnlyPubKey(g_insecure_rand_ctx.randbytes(32)); + x_not_on_curve = XOnlyPubKey(m_rng.randbytes(32)); } while (x_not_on_curve.IsFullyValid()); // Check that P2PK script with uncompressed pubkey [=> OP_PUSH65 <0x04 .....> OP_CHECKSIG] diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 46acc6fc9f..e2ea7ed5fd 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -21,14 +21,18 @@ #include <test/util/setup_common.h> #include <util/strencodings.h> +#include <algorithm> #include <vector> #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup) +using namespace util::hex_literals; + +namespace crypto_tests { +struct CryptoTest : BasicTestingSetup { template<typename Hasher, typename In, typename Out> -static void TestVector(const Hasher &h, const In &in, const Out &out) { +void TestVector(const Hasher &h, const In &in, const Out &out) { Out hash; BOOST_CHECK(out.size() == h.OUTPUT_SIZE); hash.resize(out.size()); @@ -42,7 +46,7 @@ static void TestVector(const Hasher &h, const In &in, const Out &out) { Hasher hasher(h); size_t pos = 0; while (pos < in.size()) { - size_t len = InsecureRandRange((in.size() - pos + 1) / 2 + 1); + size_t len = m_rng.randrange((in.size() - pos + 1) / 2 + 1); hasher.Write((const uint8_t*)in.data() + pos, len); pos += len; if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) { @@ -56,22 +60,22 @@ static void TestVector(const Hasher &h, const In &in, const Out &out) { } } -static void TestSHA1(const std::string &in, const std::string &hexout) { TestVector(CSHA1(), in, ParseHex(hexout));} -static void TestSHA256(const std::string &in, const std::string &hexout) { TestVector(CSHA256(), in, ParseHex(hexout));} -static void TestSHA512(const std::string &in, const std::string &hexout) { TestVector(CSHA512(), in, ParseHex(hexout));} -static void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVector(CRIPEMD160(), in, ParseHex(hexout));} +void TestSHA1(const std::string &in, const std::string &hexout) { TestVector(CSHA1(), in, ParseHex(hexout));} +void TestSHA256(const std::string &in, const std::string &hexout) { TestVector(CSHA256(), in, ParseHex(hexout));} +void TestSHA512(const std::string &in, const std::string &hexout) { TestVector(CSHA512(), in, ParseHex(hexout));} +void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVector(CRIPEMD160(), in, ParseHex(hexout));} -static void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { +void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); TestVector(CHMAC_SHA256(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); } -static void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { +void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); } -static void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) +void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); std::vector<unsigned char> in = ParseHex(hexin); @@ -90,7 +94,7 @@ static void TestAES256(const std::string &hexkey, const std::string &hexin, cons BOOST_CHECK(buf == in); } -static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout) +void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); std::vector<unsigned char> iv = ParseHex(hexiv); @@ -131,7 +135,7 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b } } -static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, ChaCha20::Nonce96 nonce, uint32_t seek, const std::string& hexout) +void TestChaCha20(const std::string &hex_message, const std::string &hexkey, ChaCha20::Nonce96 nonce, uint32_t seek, const std::string& hexout) { auto key = ParseHex<std::byte>(hexkey); assert(key.size() == 32); @@ -163,8 +167,8 @@ static void TestChaCha20(const std::string &hex_message, const std::string &hexk // Repeat 10x, but fragmented into 3 chunks, to exercise the ChaCha20 class's caching. for (int i = 0; i < 10; ++i) { size_t lens[3]; - lens[0] = InsecureRandRange(hexout.size() / 2U + 1U); - lens[1] = InsecureRandRange(hexout.size() / 2U + 1U - lens[0]); + lens[0] = m_rng.randrange(hexout.size() / 2U + 1U); + lens[1] = m_rng.randrange(hexout.size() / 2U + 1U - lens[0]); lens[2] = hexout.size() / 2U - lens[0] - lens[1]; rng.Seek(nonce, seek); @@ -182,7 +186,7 @@ static void TestChaCha20(const std::string &hex_message, const std::string &hexk } } -static void TestFSChaCha20(const std::string& hex_plaintext, const std::string& hexkey, uint32_t rekey_interval, const std::string& ciphertext_after_rotation) +void TestFSChaCha20(const std::string& hex_plaintext, const std::string& hexkey, uint32_t rekey_interval, const std::string& ciphertext_after_rotation) { auto key = ParseHex<std::byte>(hexkey); BOOST_CHECK_EQUAL(FSChaCha20::KEYLEN, key.size()); @@ -222,7 +226,7 @@ static void TestFSChaCha20(const std::string& hex_plaintext, const std::string& BOOST_CHECK_EQUAL(HexStr(fsc20_output), ciphertext_after_rotation); } -static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag) +void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag) { auto key = ParseHex<std::byte>(hexkey); auto m = ParseHex<std::byte>(hexmessage); @@ -236,7 +240,7 @@ static void TestPoly1305(const std::string &hexmessage, const std::string &hexke auto data = Span{m}; Poly1305 poly1305{key}; for (int chunk = 0; chunk < splits; ++chunk) { - size_t now = InsecureRandRange(data.size() + 1); + size_t now = m_rng.randrange(data.size() + 1); poly1305.Update(data.first(now)); data = data.subspan(now); } @@ -247,7 +251,7 @@ static void TestPoly1305(const std::string &hexmessage, const std::string &hexke } } -static void TestChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, ChaCha20::Nonce96 nonce, const std::string& cipher_hex) +void TestChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, ChaCha20::Nonce96 nonce, const std::string& cipher_hex) { auto plain = ParseHex<std::byte>(plain_hex); auto aad = ParseHex<std::byte>(aad_hex); @@ -256,7 +260,7 @@ static void TestChaCha20Poly1305(const std::string& plain_hex, const std::string for (int i = 0; i < 10; ++i) { // During i=0, use single-plain Encrypt/Decrypt; others use a split at prefix. - size_t prefix = i ? InsecureRandRange(plain.size() + 1) : plain.size(); + size_t prefix = i ? m_rng.randrange(plain.size() + 1) : plain.size(); // Encrypt. std::vector<std::byte> cipher(plain.size() + AEADChaCha20Poly1305::EXPANSION); AEADChaCha20Poly1305 aead{key}; @@ -288,7 +292,7 @@ static void TestChaCha20Poly1305(const std::string& plain_hex, const std::string } } -static void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, uint64_t msg_idx, const std::string& cipher_hex) +void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, uint64_t msg_idx, const std::string& cipher_hex) { auto plain = ParseHex<std::byte>(plain_hex); auto aad = ParseHex<std::byte>(aad_hex); @@ -298,7 +302,7 @@ static void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::stri for (int it = 0; it < 10; ++it) { // During it==0 we use the single-plain Encrypt/Decrypt; others use a split at prefix. - size_t prefix = it ? InsecureRandRange(plain.size() + 1) : plain.size(); + size_t prefix = it ? m_rng.randrange(plain.size() + 1) : plain.size(); std::byte dummy_tag[FSChaCha20Poly1305::EXPANSION] = {{}}; // Do msg_idx dummy encryptions to seek to the correct packet. @@ -334,7 +338,7 @@ static void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::stri } } -static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, const std::string &okm_check_hex) { +void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, const std::string &okm_check_hex) { std::vector<unsigned char> initial_key_material = ParseHex(ikm_hex); std::vector<unsigned char> salt = ParseHex(salt_hex); std::vector<unsigned char> info = ParseHex(info_hex); @@ -350,6 +354,10 @@ static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &sa BOOST_CHECK(HexStr(out) == okm_check_hex); } +void TestSHA3_256(const std::string& input, const std::string& output); +}; // struct CryptoTests +} // namespace crypto_tests + static std::string LongTestString() { std::string ret; @@ -365,6 +373,8 @@ static std::string LongTestString() const std::string test1 = LongTestString(); +BOOST_FIXTURE_TEST_SUITE(crypto_tests, CryptoTest) + BOOST_AUTO_TEST_CASE(ripemd160_testvectors) { TestRIPEMD160("", "9c1185a5c5e9fc54612808977ee8f548b2258d31"); TestRIPEMD160("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); @@ -822,7 +832,7 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector) BOOST_AUTO_TEST_CASE(chacha20_midblock) { - auto key = ParseHex<std::byte>("0000000000000000000000000000000000000000000000000000000000000000"); + auto key = "0000000000000000000000000000000000000000000000000000000000000000"_hex; ChaCha20 c20{key}; // get one block of keystream std::byte block[64]; @@ -833,9 +843,9 @@ BOOST_AUTO_TEST_CASE(chacha20_midblock) c20.Keystream(b2); c20.Keystream(b3); - BOOST_CHECK(Span{block}.first(5) == Span{b1}); - BOOST_CHECK(Span{block}.subspan(5, 7) == Span{b2}); - BOOST_CHECK(Span{block}.last(52) == Span{b3}); + BOOST_CHECK(std::ranges::equal(Span{block}.first(5), b1)); + BOOST_CHECK(std::ranges::equal(Span{block}.subspan(5, 7), b2)); + BOOST_CHECK(std::ranges::equal(Span{block}.last(52), b3)); } BOOST_AUTO_TEST_CASE(poly1305_testvector) @@ -918,7 +928,7 @@ BOOST_AUTO_TEST_CASE(poly1305_testvector) { // mac of the macs of messages of length 0 to 256, where the key and messages have all // their values set to the length. - auto total_key = ParseHex<std::byte>("01020304050607fffefdfcfbfaf9ffffffffffffffffffffffffffff00000000"); + auto total_key = "01020304050607fffefdfcfbfaf9ffffffffffffffffffffffffffff00000000"_hex; Poly1305 total_ctx(total_key); for (unsigned i = 0; i < 256; ++i) { std::vector<std::byte> key(32, std::byte{uint8_t(i)}); @@ -1066,7 +1076,7 @@ BOOST_AUTO_TEST_CASE(sha256d64) unsigned char in[64 * 32]; unsigned char out1[32 * 32], out2[32 * 32]; for (int j = 0; j < 64 * i; ++j) { - in[j] = InsecureRandBits(8); + in[j] = m_rng.randbits(8); } for (int j = 0; j < i; ++j) { CHash256().Write({in + 64 * j, 64}).Finalize({out1 + 32 * j, 32}); @@ -1076,7 +1086,7 @@ BOOST_AUTO_TEST_CASE(sha256d64) } } -static void TestSHA3_256(const std::string& input, const std::string& output) +void CryptoTest::TestSHA3_256(const std::string& input, const std::string& output) { const auto in_bytes = ParseHex(input); const auto out_bytes = ParseHex(output); @@ -1090,8 +1100,8 @@ static void TestSHA3_256(const std::string& input, const std::string& output) // Reset and split randomly in 3 sha.Reset(); - int s1 = InsecureRandRange(in_bytes.size() + 1); - int s2 = InsecureRandRange(in_bytes.size() + 1 - s1); + int s1 = m_rng.randrange(in_bytes.size() + 1); + int s2 = m_rng.randrange(in_bytes.size() + 1 - s1); int s3 = in_bytes.size() - s1 - s2; sha.Write(Span{in_bytes}.first(s1)).Write(Span{in_bytes}.subspan(s1, s2)); sha.Write(Span{in_bytes}.last(s3)).Finalize(out); @@ -1195,7 +1205,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] = m_rng.randbits<3>(); } for (int order = 0; order < 4; ++order) { MuHash3072 acc; @@ -1215,8 +1225,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(m_rng.randbits<4>()); // x=X + MuHash3072 y = FromInt(m_rng.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 +1245,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 +1253,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); @@ -1261,7 +1271,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests) BOOST_CHECK_EQUAL(HexStr(out), HexStr(out3)); // Test MuHash3072 overflow, meaning the internal data is larger than the modulus. - DataStream ss_max{ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")}; + DataStream ss_max{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"_hex}; MuHash3072 overflowchk; ss_max >> overflowchk; diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index eafbcf5681..bb4c8c7093 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -29,33 +29,34 @@ * using BOOST_CHECK_CLOSE to fail. * */ -BOOST_AUTO_TEST_SUITE(cuckoocache_tests); +BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup); /* 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 m_rng.rand256() 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); for (int x = 0; x < 100000; ++x) { - cc.insert(InsecureRand256()); + cc.insert(m_rng.rand256()); } for (int x = 0; x < 100000; ++x) { - BOOST_CHECK(!cc.contains(InsecureRand256(), false)); + BOOST_CHECK(!cc.contains(m_rng.rand256(), false)); } }; +struct HitRateTest : BasicTestingSetup { /** This helper returns the hit rate when megabytes*load worth of entries are * inserted into a megabytes sized cache */ template <typename Cache> -static double test_cache(size_t megabytes, double load) +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); @@ -65,7 +66,7 @@ static double test_cache(size_t megabytes, double load) for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = m_rng.rand32(); } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is @@ -104,9 +105,10 @@ static double normalize_hit_rate(double hits, double load) { return hits * std::max(load, 1.0); } +}; // struct HitRateTest /** Check the hit rate on loads ranging from 0.1 to 1.6 */ -BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok) +BOOST_FIXTURE_TEST_CASE(cuckoocache_hit_rate_ok, HitRateTest) { /** Arbitrarily selected Hit Rate threshold that happens to work for this test * as a lower bound on performance. @@ -120,13 +122,14 @@ BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok) } +struct EraseTest : BasicTestingSetup { /** This helper checks that erased elements are preferentially inserted onto and * that the hit rate of "fresher" keys is reasonable*/ template <typename Cache> -static void test_cache_erase(size_t megabytes) +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); @@ -136,7 +139,7 @@ static void test_cache_erase(size_t megabytes) for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = m_rng.rand32(); } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is @@ -178,18 +181,20 @@ static void test_cache_erase(size_t megabytes) // erased elements. BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); } +}; // struct EraseTest -BOOST_AUTO_TEST_CASE(cuckoocache_erase_ok) +BOOST_FIXTURE_TEST_CASE(cuckoocache_erase_ok, EraseTest) { size_t megabytes = 4; test_cache_erase<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes); } +struct EraseParallelTest : BasicTestingSetup { template <typename Cache> -static void test_cache_erase_parallel(size_t megabytes) +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); @@ -199,7 +204,7 @@ static void test_cache_erase_parallel(size_t megabytes) for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = m_rng.rand32(); } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is @@ -268,15 +273,17 @@ static void test_cache_erase_parallel(size_t megabytes) // erased elements. BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); } -BOOST_AUTO_TEST_CASE(cuckoocache_erase_parallel_ok) +}; // struct EraseParallelTest +BOOST_FIXTURE_TEST_CASE(cuckoocache_erase_parallel_ok, EraseParallelTest) { size_t megabytes = 4; test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes); } +struct GenerationsTest : BasicTestingSetup { template <typename Cache> -static void test_cache_generations() +void test_cache_generations() { // This test checks that for a simulation of network activity, the fresh hit // rate is never below 99%, and the number of times that it is worse than @@ -293,7 +300,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 @@ -302,7 +309,7 @@ static void test_cache_generations() // immediately and never uses the other half. struct block_activity { std::vector<uint256> reads; - block_activity(uint32_t n_insert, Cache& c) : reads() + block_activity(uint32_t n_insert, FastRandomContext& rng, Cache& c) { std::vector<uint256> inserts; inserts.resize(n_insert); @@ -310,7 +317,7 @@ static void test_cache_generations() for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)inserts[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = rng.rand32(); } for (uint32_t i = 0; i < n_insert / 4; ++i) reads.push_back(inserts[i]); @@ -344,7 +351,7 @@ static void test_cache_generations() for (uint32_t i = 0; i < total; ++i) { if (last_few.size() == WINDOW_SIZE) last_few.pop_front(); - last_few.emplace_back(BLOCK_SIZE, set); + last_few.emplace_back(BLOCK_SIZE, m_rng, set); uint32_t count = 0; for (auto& act : last_few) for (uint32_t k = 0; k < POP_AMOUNT; ++k) { @@ -365,7 +372,8 @@ static void test_cache_generations() // max_rate_less_than_tight_hit_rate of the time BOOST_CHECK(double(out_of_tight_tolerance) / double(total) < max_rate_less_than_tight_hit_rate); } -BOOST_AUTO_TEST_CASE(cuckoocache_generations) +}; // struct GenerationsTest +BOOST_FIXTURE_TEST_CASE(cuckoocache_generations, GenerationsTest) { test_cache_generations<CuckooCache::cache<uint256, SignatureCacheHasher>>(); } diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index a47bc8f366..486469ddef 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -246,7 +246,7 @@ [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], "0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -["Failure due to insufficient tx.nVersion (<2)"], +["Failure due to insufficient tx.version (<2)"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY"]], diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 723a1ceee3..3a86036327 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -12,6 +12,8 @@ #include <boost/test/unit_test.hpp> +using util::ToString; + // Test if a string consists entirely of null characters static bool is_null_key(const std::vector<unsigned char>& key) { bool isnull = true; @@ -31,7 +33,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate}); uint8_t key{'k'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint256 res; // Ensure that we're doing real obfuscation when obfuscate=true @@ -58,65 +60,65 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data) BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw))); //Simulate block raw data - "b + block hash" - std::string key_block = "b" + InsecureRand256().ToString(); + std::string key_block = "b" + m_rng.rand256().ToString(); - uint256 in_block = InsecureRand256(); + uint256 in_block = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_block, in_block)); BOOST_CHECK(dbw.Read(key_block, res)); BOOST_CHECK_EQUAL(res.ToString(), in_block.ToString()); //Simulate file raw data - "f + file_number" - std::string key_file = strprintf("f%04x", InsecureRand32()); + std::string key_file = strprintf("f%04x", m_rng.rand32()); - uint256 in_file_info = InsecureRand256(); + uint256 in_file_info = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_file, in_file_info)); BOOST_CHECK(dbw.Read(key_file, res)); BOOST_CHECK_EQUAL(res.ToString(), in_file_info.ToString()); //Simulate transaction raw data - "t + transaction hash" - std::string key_transaction = "t" + InsecureRand256().ToString(); + std::string key_transaction = "t" + m_rng.rand256().ToString(); - uint256 in_transaction = InsecureRand256(); + uint256 in_transaction = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_transaction, in_transaction)); BOOST_CHECK(dbw.Read(key_transaction, res)); BOOST_CHECK_EQUAL(res.ToString(), in_transaction.ToString()); //Simulate UTXO raw data - "c + transaction hash" - std::string key_utxo = "c" + InsecureRand256().ToString(); + std::string key_utxo = "c" + m_rng.rand256().ToString(); - uint256 in_utxo = InsecureRand256(); + uint256 in_utxo = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_utxo, in_utxo)); BOOST_CHECK(dbw.Read(key_utxo, res)); BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString()); //Simulate last block file number - "l" uint8_t key_last_blockfile_number{'l'}; - uint32_t lastblockfilenumber = InsecureRand32(); + uint32_t lastblockfilenumber = m_rng.rand32(); BOOST_CHECK(dbw.Write(key_last_blockfile_number, lastblockfilenumber)); BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32)); BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32); //Simulate Is Reindexing - "R" uint8_t key_IsReindexing{'R'}; - bool isInReindexing = InsecureRandBool(); + bool isInReindexing = m_rng.randbool(); BOOST_CHECK(dbw.Write(key_IsReindexing, isInReindexing)); BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool)); BOOST_CHECK_EQUAL(isInReindexing, res_bool); //Simulate last block hash up to which UXTO covers - 'B' uint8_t key_lastblockhash_uxto{'B'}; - uint256 lastblock_hash = InsecureRand256(); + uint256 lastblock_hash = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_lastblockhash_uxto, lastblock_hash)); BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res)); BOOST_CHECK_EQUAL(lastblock_hash, res); //Simulate file raw data - "F + filename_number + filename" std::string file_option_tag = "F"; - uint8_t filename_length = InsecureRandBits(8); + uint8_t filename_length = m_rng.randbits(8); std::string filename = "randomfilename"; std::string key_file_option = strprintf("%s%01x%s", file_option_tag,filename_length,filename); - bool in_file_bool = InsecureRandBool(); + bool in_file_bool = m_rng.randbool(); BOOST_CHECK(dbw.Write(key_file_option, in_file_bool)); BOOST_CHECK(dbw.Read(key_file_option, res_bool)); BOOST_CHECK_EQUAL(res_bool, in_file_bool); @@ -132,11 +134,11 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate}); uint8_t key{'i'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint8_t key2{'j'}; - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); uint8_t key3{'k'}; - uint256 in3 = InsecureRand256(); + uint256 in3 = m_rng.rand256(); uint256 res; CDBBatch batch(dbw); @@ -169,10 +171,10 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) // The two keys are intentionally chosen for ordering uint8_t key{'j'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); BOOST_CHECK(dbw.Write(key, in)); uint8_t key2{'k'}; - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); BOOST_CHECK(dbw.Write(key2, in2)); std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator()); @@ -210,7 +212,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false}); uint8_t key{'k'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); @@ -232,7 +234,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); uint256 res3; // Check that we can write successfully @@ -251,7 +253,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false}); uint8_t key{'k'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); @@ -269,7 +271,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) BOOST_CHECK(!odbw.Read(key, res2)); BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); uint256 res3; // Check that we can write successfully diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 5e9ae78681..9ee7e9c9fe 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -106,17 +106,18 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) peerman.FinalizeNode(dummyNode1); } -static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false) +struct OutboundTest : TestingSetup { +void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false) { CAddress addr; if (onion_peer) { - auto tor_addr{g_insecure_rand_ctx.randbytes(ADDR_TORV3_SIZE)}; + auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)}; BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr))); } while (!addr.IsRoutable()) { - addr = CAddress(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE); + addr = CAddress(ip(m_rng.randbits(32)), NODE_NONE); } vNodes.emplace_back(new CNode{id++, @@ -136,12 +137,13 @@ static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerM connman.AddTestNode(node); } +}; // struct OutboundTest -BOOST_AUTO_TEST_CASE(stale_tip_peer_management) +BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest) { NodeId id{0}; auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); - auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {}); + auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {}); constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS; CConnman::Options options; @@ -235,11 +237,11 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) connman->ClearTestNodes(); } -BOOST_AUTO_TEST_CASE(block_relay_only_eviction) +BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest) { NodeId id{0}; auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); - auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {}); + auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {}); constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS}; constexpr int64_t MINIMUM_CONNECT_TIME{30}; @@ -300,7 +302,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); - auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, {}); + auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {}); CNetAddr tor_netaddr; BOOST_REQUIRE( @@ -330,7 +332,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) peerLogic->InitializeNode(*nodes[0], NODE_NETWORK); nodes[0]->fSuccessfullyConnected = true; connman->AddTestNode(*nodes[0]); - peerLogic->UnitTestMisbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged + peerLogic->UnitTestMisbehaving(nodes[0]->GetId()); // Should be discouraged BOOST_CHECK(peerLogic->SendMessages(nodes[0])); BOOST_CHECK(banman->IsDiscouraged(addr[0])); @@ -350,7 +352,6 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) peerLogic->InitializeNode(*nodes[1], NODE_NETWORK); nodes[1]->fSuccessfullyConnected = true; connman->AddTestNode(*nodes[1]); - peerLogic->UnitTestMisbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1); BOOST_CHECK(peerLogic->SendMessages(nodes[1])); // [0] is still discouraged/disconnected. BOOST_CHECK(banman->IsDiscouraged(addr[0])); @@ -358,7 +359,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) // [1] is not discouraged/disconnected yet. BOOST_CHECK(!banman->IsDiscouraged(addr[1])); BOOST_CHECK(!nodes[1]->fDisconnect); - peerLogic->UnitTestMisbehaving(nodes[1]->GetId(), 1); // [1] reaches discouragement threshold + peerLogic->UnitTestMisbehaving(nodes[1]->GetId()); BOOST_CHECK(peerLogic->SendMessages(nodes[1])); // Expect both [0] and [1] to be discouraged/disconnected now. BOOST_CHECK(banman->IsDiscouraged(addr[0])); @@ -381,7 +382,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) peerLogic->InitializeNode(*nodes[2], NODE_NETWORK); nodes[2]->fSuccessfullyConnected = true; connman->AddTestNode(*nodes[2]); - peerLogic->UnitTestMisbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD); + peerLogic->UnitTestMisbehaving(nodes[2]->GetId()); BOOST_CHECK(peerLogic->SendMessages(nodes[2])); BOOST_CHECK(banman->IsDiscouraged(addr[0])); BOOST_CHECK(banman->IsDiscouraged(addr[1])); @@ -402,7 +403,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); - auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, {}); + auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {}); banman->ClearBanned(); int64_t nStartTime = GetTime(); @@ -423,7 +424,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) peerLogic->InitializeNode(dummyNode, NODE_NETWORK); dummyNode.fSuccessfullyConnected = true; - peerLogic->UnitTestMisbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD); + peerLogic->UnitTestMisbehaving(dummyNode.GetId()); BOOST_CHECK(peerLogic->SendMessages(&dummyNode)); BOOST_CHECK(banman->IsDiscouraged(addr)); diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index c779bf6f73..24b8f2f793 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -7,6 +7,7 @@ #include <script/sign.h> #include <test/util/setup_common.h> #include <util/strencodings.h> +#include <util/string.h> #include <boost/test/unit_test.hpp> @@ -14,6 +15,9 @@ #include <string> #include <vector> +using namespace util::hex_literals; +using util::Split; + namespace { void CheckUnparsable(const std::string& prv, const std::string& pub, const std::string& expected_error) @@ -22,8 +26,8 @@ void CheckUnparsable(const std::string& prv, const std::string& pub, const std:: std::string error; auto parse_priv = Parse(prv, keys_priv, error); auto parse_pub = Parse(pub, keys_pub, error); - BOOST_CHECK_MESSAGE(!parse_priv, prv); - BOOST_CHECK_MESSAGE(!parse_pub, pub); + BOOST_CHECK_MESSAGE(parse_priv.empty(), prv); + BOOST_CHECK_MESSAGE(parse_pub.empty(), pub); BOOST_CHECK_EQUAL(error, expected_error); } @@ -130,25 +134,29 @@ void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, std::optional<uint256> op_desc_id = std::nullopt, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, bool replace_apostrophe_with_h_in_prv=false, bool replace_apostrophe_with_h_in_pub=false, uint32_t spender_nlocktime=0, uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL, - std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={}) + std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={}, + std::optional<std::string> expected_prv = std::nullopt, std::optional<std::string> expected_pub = std::nullopt, int desc_index = 0) { FlatSigningProvider keys_priv, keys_pub; std::set<std::vector<uint32_t>> left_paths = paths; std::string error; - std::unique_ptr<Descriptor> parse_priv; - std::unique_ptr<Descriptor> parse_pub; + std::vector<std::unique_ptr<Descriptor>> parse_privs; + std::vector<std::unique_ptr<Descriptor>> parse_pubs; // Check that parsing succeeds. if (replace_apostrophe_with_h_in_prv) { prv = UseHInsteadOfApostrophe(prv); } - parse_priv = Parse(prv, keys_priv, error); - BOOST_CHECK_MESSAGE(parse_priv, error); + parse_privs = Parse(prv, keys_priv, error); + BOOST_CHECK_MESSAGE(!parse_privs.empty(), error); if (replace_apostrophe_with_h_in_pub) { pub = UseHInsteadOfApostrophe(pub); } - parse_pub = Parse(pub, keys_pub, error); - BOOST_CHECK_MESSAGE(parse_pub, error); + parse_pubs = Parse(pub, keys_pub, error); + BOOST_CHECK_MESSAGE(!parse_pubs.empty(), error); + + auto& parse_priv = parse_privs.at(desc_index); + auto& parse_pub = parse_pubs.at(desc_index); // We must be able to estimate the max satisfaction size for any solvable descriptor top descriptor (but combo). const bool is_nontop_or_nonsolvable{!parse_priv->IsSolvable() || !parse_priv->GetOutputType()}; @@ -170,11 +178,17 @@ void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int BOOST_CHECK(keys_priv.keys.size()); BOOST_CHECK(!keys_pub.keys.size()); - // Check that both versions serialize back to the public version. + // If expected_pub is provided, check that the serialize matches that. + // Otherwise check that they serialize back to the public version. std::string pub1 = parse_priv->ToString(); std::string pub2 = parse_pub->ToString(); - BOOST_CHECK_MESSAGE(EqualDescriptor(pub, pub1), "Private ser: " + pub1 + " Public desc: " + pub); - BOOST_CHECK_MESSAGE(EqualDescriptor(pub, pub2), "Public ser: " + pub2 + " Public desc: " + pub); + if (expected_pub) { + BOOST_CHECK_MESSAGE(EqualDescriptor(*expected_pub, pub1), "Private ser: " + pub1 + " Public desc: " + *expected_pub); + BOOST_CHECK_MESSAGE(EqualDescriptor(*expected_pub, pub2), "Public ser: " + pub2 + " Public desc: " + *expected_pub); + } else { + BOOST_CHECK_MESSAGE(EqualDescriptor(pub, pub1), "Private ser: " + pub1 + " Public desc: " + pub); + BOOST_CHECK_MESSAGE(EqualDescriptor(pub, pub2), "Public ser: " + pub2 + " Public desc: " + pub); + } // Check that the COMPAT identifier did not change if (op_desc_id) { @@ -185,10 +199,19 @@ void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int if (!(flags & MISSING_PRIVKEYS)) { std::string prv1; BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1)); - BOOST_CHECK_MESSAGE(EqualDescriptor(prv, prv1), "Private ser: " + prv1 + " Private desc: " + prv); + if (expected_prv) { + BOOST_CHECK_MESSAGE(EqualDescriptor(*expected_prv, prv1), "Private ser: " + prv1 + "Private desc: " + *expected_prv); + } else { + BOOST_CHECK_MESSAGE(EqualDescriptor(prv, prv1), "Private ser: " + prv1 + " Private desc: " + prv); + } BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1)); BOOST_CHECK(parse_pub->ToPrivateString(keys_priv, prv1)); - BOOST_CHECK_MESSAGE(EqualDescriptor(prv, prv1), "Private ser: " + prv1 + " Private desc: " + prv); + if (expected_prv) { + BOOST_CHECK(EqualDescriptor(*expected_prv, prv1)); + BOOST_CHECK_MESSAGE(EqualDescriptor(*expected_prv, prv1), "Private ser: " + prv1 + " Private desc: " + *expected_prv); + } else { + BOOST_CHECK_MESSAGE(EqualDescriptor(prv, prv1), "Private ser: " + prv1 + " Private desc: " + prv); + } BOOST_CHECK(!parse_pub->ToPrivateString(keys_pub, prv1)); } @@ -369,18 +392,42 @@ void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int void Check(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, std::optional<uint256> op_desc_id = std::nullopt, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, uint32_t spender_nlocktime=0, - uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL, std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={}) + uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL, std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={}, + std::optional<std::string> expected_prv = std::nullopt, std::optional<std::string> expected_pub = std::nullopt, int desc_index = 0) { // Do not replace apostrophes with 'h' in prv and pub DoCheck(prv, pub, norm_pub, flags, scripts, type, op_desc_id, paths, /*replace_apostrophe_with_h_in_prv=*/false, /*replace_apostrophe_with_h_in_pub=*/false, /*spender_nlocktime=*/spender_nlocktime, - /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages); + /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages, + expected_prv, expected_pub, desc_index); // Replace apostrophes with 'h' both in prv and in pub, if apostrophes are found in both if (prv.find('\'') != std::string::npos && pub.find('\'') != std::string::npos) { DoCheck(prv, pub, norm_pub, flags, scripts, type, op_desc_id, paths, /*replace_apostrophe_with_h_in_prv=*/true, /*replace_apostrophe_with_h_in_pub=*/true, /*spender_nlocktime=*/spender_nlocktime, - /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages); + /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages, + expected_prv, expected_pub, desc_index); + } +} + +void CheckMultipath(const std::string& prv, + const std::string& pub, + const std::vector<std::string>& expanded_prvs, + const std::vector<std::string>& expanded_pubs, + const std::vector<std::string>& expanded_norm_pubs, + int flags, + const std::vector<std::vector<std::vector<std::string>>>& scripts, + const std::optional<OutputType>& type, + const std::vector<std::set<std::vector<uint32_t>>>& paths) +{ + assert(expanded_prvs.size() == expanded_pubs.size()); + assert(expanded_prvs.size() == expanded_norm_pubs.size()); + assert(expanded_prvs.size() == scripts.size()); + assert(expanded_prvs.size() == paths.size()); + for (size_t i = 0; i < expanded_prvs.size(); ++i) { + Check(prv, pub, expanded_norm_pubs.at(i), flags, scripts.at(i), type, std::nullopt, paths.at(i), + /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, /*preimages=*/{}, + expanded_prvs.at(i), expanded_pubs.at(i), i); } } @@ -400,7 +447,6 @@ void CheckInferDescriptor(const std::string& script_hex, const std::string& expe provider.pubkeys.emplace(origin_pubkey.GetID(), origin_pubkey); if (!origin_str.empty()) { - using namespace spanparsing; KeyOriginInfo info; Span<const char> origin_sp{origin_str}; std::vector<Span<const char>> origin_split = Split(origin_sp, "/"); @@ -439,20 +485,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 @@ -472,16 +518,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},{}}); @@ -490,15 +536,302 @@ BOOST_AUTO_TEST_CASE(descriptor_test) CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/1aa)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1aa)", "pkh(): Key path value '1aa' is not a valid uint32"); // Path is not valid uint 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}}); + // Multipath versions with BIP32 derivations + CheckMultipath("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/<0;1>)", + "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/<0;1>)", + { + "pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", + "pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/1)", + }, + { + "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", + "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/1)", + }, + { + "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", + "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/1)", + }, + DEFAULT, + { + {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, + {{"21034f8d02282ac6786737d0f37f0df7655f49daa24843bc7de3f4ea88603d26d10aac"}}, + }, + std::nullopt, + { + {{0}}, + {{1}}, + } + ); + CheckMultipath("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<2147483647h;0>/0)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<2147483647h;0>/0)", + { + "pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647h/0)", + "pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/0/0)", + }, + { + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647h/0)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0/0)", + }, + { + "pkh([bd16bee5/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0/0)", + }, + HARDENED, + { + {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, + {{"76a914f103317b9f0b758a62cb3879281d23e3b1deb90d88ac"}}, + }, + OutputType::LEGACY, + { + {{0xFFFFFFFFUL,0}}, + {{0,0}}, + } + ); + CheckMultipath("wpkh([ffffffff/13h]xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/<1;3>/2/*)", + "wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/<1;3>/2/*)", + { + "wpkh([ffffffff/13h]xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", + "wpkh([ffffffff/13h]xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/3/2/*)", + }, + { + "wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", + "wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/3/2/*)", + }, + { + "wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", + "wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/3/2/*)", + }, + RANGE, + { + {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, + {{"001426183882ef9c76b9a44386e9b387f33cee7c3a2d"},{"001447c1b9dc215c3f8b47e572981eb97528768cde4e"},{"00146e92cbaa397f9caeccf9a049460258af6ccd67e2"}}, + }, + OutputType::BECH32, + { + {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}}, + {{0x8000000DUL, 3, 2, 0}, {0x8000000DUL, 3, 2, 1}, {0x8000000DUL, 3, 2, 2}}, + } + ); + CheckMultipath("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/<10;100h>/20/30/40/*h))", + "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/<10;100h>/20/30/40/*h))", + { + "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*h))", + "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/100h/20/30/40/*h))", + }, + { + "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", + "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/100h/20/30/40/*h))", + }, + { + "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", + "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/100h/20/30/40/*h))", + }, + RANGE | HARDENED | DERIVE_HARDENED, + { + {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, + {{"a91470192039cb9529aadf4e53e46d9ac6a13790865787"},{"a914855859faffabf1e4ed2bb7411ab66f4599b1abd287"},{"a9148f2cfd4b486de247c44684160da164617ccf2c2687"}}, + }, + OutputType::P2SH_SEGWIT, + { + {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}}, + {{0x80000064UL, 20, 30, 40, 0x80000000UL}, {0x80000064UL, 20, 30, 40, 0x80000001UL}, {0x80000064UL, 20, 30, 40, 0x80000002UL}}, + } + ); + CheckMultipath("multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2>/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/<3;4>/0/*)", + "multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2>/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/<3;4>/0/*)", + { + "multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/3/0/*)", + "multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/2/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/4/0/*)", + }, + { + "multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/3/0/*)", + "multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/4/0/*)", + }, + { + "multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/3/0/*)", + "multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/4/0/*)", + }, + RANGE, + { + {{"522103095e95d8c50ae3f3fea93fa8e983f710489f60ff681a658c06eba64622c824b121020443e9e729b42628913f1a69b46b7d43ff87c46e86140e12ee420d7e2e8caf8c52ae"},{"5221027512d6bd74e24eeb1ad752d5be800adc5886ded11c5293a9a701db83658b526a2102371e912dea5fefa56158908fe4c9f66bc925a8939b10f3821e8f8be797b9ca8252ae"},{"522102cc9fd211dc0a1c8bb7a106ff831be0e253bc992f21d08fb8a6fd43fae51b9b892103e43eddc68afc9746c9d09ce0bf8067b4f2416287abbc422ed1ac300673b1104952ae"}}, + {{"5221031c0517fff3d483f06ca769bd2326bf30aca1c4de278e676e6ef760c3301244c6210316e171ff4f82dc62ad3f0d84c97865034fc5041eaa508b48c1d7af77f301c8bd52ae"},{"52210240f010ccff4202ade2ef87756f6b9af57bbf5ebcb0393b949e6e5d45d30bff36210229057a7e03510b8cb66727fab3f47a52a02ea94eae03e7c2e81b72a26781bfde52ae"},{"5221034052522058a07b647bd08fa1a9eaedae0222eac76ddd122ff8096ec969398de721038cb8180dd4c956848bcf191e45aaf297146207559fb8737881156aadaf13704152ae"}}, + }, + std::nullopt, + { + {{1, 0}, {1, 1}, {1, 2}, {3, 0, 0}, {3, 0, 1}, {3, 0, 2}}, + {{2, 0}, {2, 1}, {2, 2}, {4, 0, 0}, {4, 0, 1}, {4, 0, 2}}, + } + ); + CheckMultipath("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<0;1;2>)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0;1;2>)", + { + "pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/0)", + "pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/1)", + "pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2)", + }, + { + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2)", + }, + { + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1)", + "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2)", + }, + DEFAULT, + { + {{"76a9145a61ff8eb7aaca3010db97ebda76121610b7809688ac"}}, + {{"76a9142f792a782cf4adbb321fe646c8e220563649b8fa88ac"}}, + {{"76a914dcc5b93b52177d78f97b3f2d259b9a86ee1403b188ac"}}, + }, + OutputType::LEGACY, + { + {{0}}, + {{1}}, + {{2}}, + } + ); + CheckMultipath("sh(multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/*,xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4;5>/*))", + "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4;5>/*))", + { + "sh(multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/0/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/*,xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/3/*))", + "sh(multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/2/0/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/*,xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/4/*))", + "sh(multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3/0/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/*,xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/5/*))", + }, + { + "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/3/*))", + "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/4/*))", + "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/5/*))", + }, + { + "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/3/*))", + "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/4/*))", + "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/5/*))", + }, + RANGE, + { + {{"a914689cdf7de5836ec04fb971d128cc84858f73e11487"},{"a9142ea7dbaf0a77ee19f080cdacb3e13560e3cd9cf587"},{"a9143da854021f58f5e2d3ff6bb4fcd0ced877deb34987"}}, + {{"a9143dd613d162e89b83369bbf08e5f1977cfdc9b02787"},{"a91449eef5d3df5c465b20a630c66058fe689082d8e187"},{"a91492be56babf54ea2109c577f799ba6d73948e8c3287"}}, + {{"a9140093ca92097bdf557fbb0570bb77e1efd2e7529c87"},{"a914e4d0419d3d2ce8f921a800796811ff5462bb151887"},{"a914997bf69841ac444190dc02f5e6031dd6f8feab4587"}}, + }, + OutputType::LEGACY, + { + {{1, 0, 0}, {1, 0, 1}, {1, 0, 2}, {0, 0}, {0, 1}, {0, 2}, {0, 0, 3, 0}, {0, 0, 3, 1}, {0, 0, 3, 2}}, + {{2, 0, 0}, {2, 0, 1}, {2, 0, 2}, {0, 0}, {0, 1}, {0, 2}, {0, 0, 4, 0}, {0, 0, 4, 1}, {0, 0, 4, 2}}, + {{3, 0, 0}, {3, 0, 1}, {3, 0, 2}, {0, 0}, {0, 1}, {0, 2}, {0, 0, 5, 0}, {0, 0, 5, 1}, {0, 0, 5, 2}}, + } + ); + CheckMultipath("tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/<6;7;8>/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4;5>/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/<6;7;8>/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4;5>/*)})", + { + "tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/6/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/3/*)})", + "tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/7/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/2/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/4/*)})", + "tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/8/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/5/*)})", + }, + { + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/3/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/7/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/4/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/8/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/5/*)})", + }, + { + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/3/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/7/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/4/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/8/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/5/*)})", + }, + XONLY_KEYS | RANGE, + { + {{"5120993e5b1d71d14cbb0a90c57ea0fed1d5bf77d5804cee206c3dbd7e4d2c67d869"},{"51207b8f629f6d406b92ffa6284f5545085eafb837c469018b715755f619b587163b"},{"512061f52925826e51e4615007557ddbea55b22c817909d7ebcfd3c454c634643ece"}}, + {{"5120633808b2156d0a6597e8b07f59c387bb4c2d5c02c4cb98f1802748e64c6abf5f"},{"5120fc5f06ded29328c170bf7e49e71c9cc8699befa2bf0a2a80802a1f32ab72d291"},{"5120fd05e2227e0dac972dff9941e332db8461bedc320c2a74def44e469ddbad9d21"}}, + {{"51205d19538c7c0901520eb712d079ae6eebed4f691021da466dc24e9575d9815ad0"},{"5120b9fc348ede2b7b9fb1f84c21741bb36bb3fa0905d0bc9417e07145d3142673f7"},{"51203a655bc5181b12efac82a5a5d1d0969b2ceb92c6fc37f505fdf00ee8afa09b33"}}, + }, + OutputType::BECH32M, + { + {{6, 0}, {6, 1}, {6, 2}, {1, 0, 0}, {1, 0, 1}, {1, 0, 2}, {0, 0, 3, 0}, {0, 0, 3, 1}, {0, 0, 3, 2}}, + {{7, 0}, {7, 1}, {7, 2}, {2, 0, 0}, {2, 0, 1}, {2, 0, 2}, {0, 0, 4, 0}, {0, 0, 4, 1}, {0, 0, 4, 2}}, + {{8, 0}, {8, 1}, {8, 2}, {3, 0, 0}, {3, 0, 1}, {3, 0, 2}, {0, 0, 5, 0}, {0, 0, 5, 1}, {0, 0, 5, 2}}, + } + ); + CheckMultipath("tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/6/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4;5>/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4;5>/*)})", + { + "tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/6/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/3/*)})", + "tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/6/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/2/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/4/*)})", + "tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/6/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/5/*)})", + }, + { + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/3/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/4/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/5/*)})", + }, + { + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/3/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/4/*)})", + "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/5/*)})", + }, + XONLY_KEYS | RANGE, + { + {{"5120993e5b1d71d14cbb0a90c57ea0fed1d5bf77d5804cee206c3dbd7e4d2c67d869"},{"51207b8f629f6d406b92ffa6284f5545085eafb837c469018b715755f619b587163b"},{"512061f52925826e51e4615007557ddbea55b22c817909d7ebcfd3c454c634643ece"}}, + {{"5120c481a8ada38d1070094f62af526d4f8aae2eb1e44d1fd961be6a25198b4da77b"},{"512034a2d31c091905e62def62b575b88beff41723d83acb02dfada2e73d9c529b40"},{"5120e0ecc278655b092962ded92a5781bd8e86e8408055de05f121e107fa211e5dfb"}}, + {{"51206052cff5efc848e4b38a947803943eb1eb0076523eec1041969851ebcd265555"},{"512009ed83d758c0bdd36e225c961810761c7a360533434a41a17bba709e331e6cd1"},{"5120fcd77851ebaac37564b87e9b351c54492a8fbb1d6afdf7f3a9317703a002b22b"}}, + }, + OutputType::BECH32M, + { + {{6, 0}, {6, 1}, {6, 2}, {1, 0, 0}, {1, 0, 1}, {1, 0, 2}, {0, 0, 3, 0}, {0, 0, 3, 1}, {0, 0, 3, 2}}, + {{6, 0}, {6, 1}, {6, 2}, {2, 0, 0}, {2, 0, 1}, {2, 0, 2}, {0, 0, 4, 0}, {0, 0, 4, 1}, {0, 0, 4, 2}}, + {{6, 0}, {6, 1}, {6, 2}, {3, 0, 0}, {3, 0, 1}, {3, 0, 2}, {0, 0, 5, 0}, {0, 0, 5, 1}, {0, 0, 5, 2}}, + } + ); + CheckMultipath("wsh(or_d(pk([2557c640/48h/1h/0h/2h]xprv9ws7hGFQPbDga6QrETbFM7Gqc7m15UNoJ7KF5kkDhyZCBcANAqRMUCytQ4JM1nLSYvGyFjg6TvBEfNrN3znaFdb67jQoQ7z9kFnd4BUUJiE/<0;1>/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xprv9ws7hGFQPbDgbCvNcYVfGeGK8UTSFmAho4iAXZf13yQVJmHuKHN9oMXCv7zsJn8Dcqvqy2iugFWAhDdUUX6r5VLNWkRTpxVoQJ6DbzY9eYa/<0;1>/*),older(2))))", + "wsh(or_d(pk([2557c640/48h/1h/0h/2h]xpub6ArU6mnJDxmynaVKLV8FiFDaA9bVUw6efLEqt99qGK6B4QVWiNjc21JNFKkXNjgT8NCUmpFpSSBrYFtWEAqGirbqT4J1bRFpWyAnYdzmZUm/<0;1>/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xpub6ArU6mnJDxmyogzqia2fdnD3gWHvfDtZAHdmKx4ccJwUBZd3rpgQM9qgmPAn1mqT2yh81uvGGohMkg3fNLoXZzn7sRo4a1X3KnCAVot2yuS/<0;1>/*),older(2))))", + { + "wsh(or_d(pk([2557c640/48h/1h/0h/2h]xprv9ws7hGFQPbDga6QrETbFM7Gqc7m15UNoJ7KF5kkDhyZCBcANAqRMUCytQ4JM1nLSYvGyFjg6TvBEfNrN3znaFdb67jQoQ7z9kFnd4BUUJiE/0/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xprv9ws7hGFQPbDgbCvNcYVfGeGK8UTSFmAho4iAXZf13yQVJmHuKHN9oMXCv7zsJn8Dcqvqy2iugFWAhDdUUX6r5VLNWkRTpxVoQJ6DbzY9eYa/0/*),older(2))))", + "wsh(or_d(pk([2557c640/48h/1h/0h/2h]xprv9ws7hGFQPbDga6QrETbFM7Gqc7m15UNoJ7KF5kkDhyZCBcANAqRMUCytQ4JM1nLSYvGyFjg6TvBEfNrN3znaFdb67jQoQ7z9kFnd4BUUJiE/1/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xprv9ws7hGFQPbDgbCvNcYVfGeGK8UTSFmAho4iAXZf13yQVJmHuKHN9oMXCv7zsJn8Dcqvqy2iugFWAhDdUUX6r5VLNWkRTpxVoQJ6DbzY9eYa/1/*),older(2))))", + }, + { + "wsh(or_d(pk([2557c640/48h/1h/0h/2h]xpub6ArU6mnJDxmynaVKLV8FiFDaA9bVUw6efLEqt99qGK6B4QVWiNjc21JNFKkXNjgT8NCUmpFpSSBrYFtWEAqGirbqT4J1bRFpWyAnYdzmZUm/0/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xpub6ArU6mnJDxmyogzqia2fdnD3gWHvfDtZAHdmKx4ccJwUBZd3rpgQM9qgmPAn1mqT2yh81uvGGohMkg3fNLoXZzn7sRo4a1X3KnCAVot2yuS/0/*),older(2))))", + "wsh(or_d(pk([2557c640/48h/1h/0h/2h]xpub6ArU6mnJDxmynaVKLV8FiFDaA9bVUw6efLEqt99qGK6B4QVWiNjc21JNFKkXNjgT8NCUmpFpSSBrYFtWEAqGirbqT4J1bRFpWyAnYdzmZUm/1/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xpub6ArU6mnJDxmyogzqia2fdnD3gWHvfDtZAHdmKx4ccJwUBZd3rpgQM9qgmPAn1mqT2yh81uvGGohMkg3fNLoXZzn7sRo4a1X3KnCAVot2yuS/1/*),older(2))))" + }, + { + "wsh(or_d(pk([2557c640/48h/1h/0h/2h]xpub6ArU6mnJDxmynaVKLV8FiFDaA9bVUw6efLEqt99qGK6B4QVWiNjc21JNFKkXNjgT8NCUmpFpSSBrYFtWEAqGirbqT4J1bRFpWyAnYdzmZUm/0/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xpub6ArU6mnJDxmyogzqia2fdnD3gWHvfDtZAHdmKx4ccJwUBZd3rpgQM9qgmPAn1mqT2yh81uvGGohMkg3fNLoXZzn7sRo4a1X3KnCAVot2yuS/0/*),older(2))))", + "wsh(or_d(pk([2557c640/48h/1h/0h/2h]xpub6ArU6mnJDxmynaVKLV8FiFDaA9bVUw6efLEqt99qGK6B4QVWiNjc21JNFKkXNjgT8NCUmpFpSSBrYFtWEAqGirbqT4J1bRFpWyAnYdzmZUm/1/*),and_v(v:pkh([00aabb22/48h/1h/0h/2h]xpub6ArU6mnJDxmyogzqia2fdnD3gWHvfDtZAHdmKx4ccJwUBZd3rpgQM9qgmPAn1mqT2yh81uvGGohMkg3fNLoXZzn7sRo4a1X3KnCAVot2yuS/1/*),older(2))))" + }, + RANGE, + { + {{"0020538436a60f2a638ea9e1e1342e9b93374aa7ec559ff0a805b3a185d4ba855d7f"},{"00203a588d107d604b6913201c7c1e1722f07a0f8fb3a382744f17b9ae5f6ccfcdd7"},{"0020d30fb375f7c491a208e77c7b5d0996ca14cf4a770c2ab5981f915c0e4565c74a"}}, + {{"002072b5fc3a691c48fdbaf485f27e787b4094055d4b434c90c81ed1090f3d48733b"},{"0020a9ccdf4496e5d60db4704b27494d9d74f54a16c180ff954a43ce5e3aa465113a"},{"0020d17e21820a0069ca87049513eca763f08a74b586724441e7d76fc5142bcc327c"}}, + }, + OutputType::BECH32, + { + {{0x80000000UL + 48, 0x80000000UL + 1, 0x80000000UL, 0x80000000UL + 2, 0, 0}, {0x80000000UL + 48, 0x80000000UL + 1, 0x80000000UL, 0x80000000UL + 2, 0, 1}, {0x80000000UL + 48, 0x80000000UL + 1, 0x80000000UL, 0x80000000UL + 2, 0, 2}}, + {{0x80000000UL + 48, 0x80000000UL + 1, 0x80000000UL, 0x80000000UL + 2, 1, 0}, {0x80000000UL + 48, 0x80000000UL + 1, 0x80000000UL, 0x80000000UL + 2, 1, 1}, {0x80000000UL + 48, 0x80000000UL + 1, 0x80000000UL, 0x80000000UL + 2, 1, 2}}, + } + ); + CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<0;1>/<2;3>)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0;1>/<2;3>)", "pkh(): Multiple multipath key path specifiers found"); + CheckUnparsable("pkh([deadbeef/<0;1>]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/0)", "pkh([deadbeef/<0;1>]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0)", "pkh(): Key path value \'<0;1>\' specifies multipath in a section where multipath is not allowed"); + CheckUnparsable("tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/6/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4>/*)})", "tr(xpub6B4sSbNr8XFYXqqKB7PeUemqgEaVtCLjgd5Lf2VYtezSHozC7ffCvVNCyu9TCgHntRQdimjV3tHbxmNfocxtuh6saNtZEw91gjXLRhQ3Yar/6/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*),pk(xpub6AhFhZJJGt9YB8i85RfrJ8jT3T2FF5EejDCXqXfm1DAczFEXkk8HD3CXTg2TmKM8wTbSnSw3wPg5JuyLitUrpRmkjn2BQXyZnqJx16AGy94/0/0/<3;4>/*)})", "tr(): Multipath subscripts have mismatched lengths"); + CheckUnparsable("tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/<6;7;8;9>/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4;5>/*)})", "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/<6;7;8;9>/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4;5>/*)})", "tr(): Multipath subscripts have mismatched lengths"); + CheckUnparsable("tr(xprv9s21ZrQH143K2Zu2kTVKcQi9nKhfgJUkYqG73wXsHuhATm1wkt6kcSZeTYEw2PL7krZtJopEYDvBdYWdAai3n3TWUTCVfHvPHqTYJv7smYe/<6;7>/*,{pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*),pk(xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4;5>/*)})", "tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/<6;7>/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4;5>/*)})", "tr(): Multipath internal key mismatches multipath subscripts lengths"); + CheckUnparsable("sh(multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/*,xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4>/*))", "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4>/*))", "multi(): Multipath derivation paths have mismatched lengths"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<0>/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0>/*)", "wpkh(): Multipath key path specifiers must have at least two items"); + CheckUnparsable("wsh(andor(pk(xprv9xGFvhWa1Koc8dmeEG5JXVfMaNBkioYscFGmn7yx8YnhFQYeydFfudxdKRzR5p7v1kip85ohB6eUQbPpAee9cFZu9M85G9X4ovPP4xw4xbM/0'/<0;1;2;3>/*),older(10000),pk(xprv9x9bas78RYwopceXTStT8vDuTiu6g1u91L6sG3DhHfDDXKPrYdcHcDuDw4Hv1kjZBWKoZnobUHrdoFxBPUMBTMruUs8HwzL8GxGA95MmZ7v/8/<0;1;2>/*)))", "wsh(andor(pk(xpub6BFcLD3TqhMuM7r7LHcJtdc68Q2F8GGiyUCNaWPZgtKg8CsoXAZvTSH7AhaCPnuuewjwzA2gbAm1y6uaDNNxa7JqTiL76cdioT5rxjgxWXF/0'/<0;1;2;3>/*),older(10000),pk(xpub6B8wzNe2FvW736izZURTW4Ae1kjb5UczNZ2U4RdJqzkCQ7j16AvYA2DhnL8Kb5FeWAZJ43NnGPdjpeSKvAeM8YGaqhCzpD743Uv6S87hfAt/8/<0;1;2>/*)))", "Miniscript: Multipath derivation paths have mismatched lengths"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<>/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<>/*)", "wpkh(): Multipath key path specifiers must have at least two items"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<0/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0/*)", "wpkh(): Key path value '<0' is not a valid uint32"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/0>/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0>/*)", "wpkh(): Key path value '0>' is not a valid uint32"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<0;>/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0;>/*)", "wpkh(): Key path value '' is not a valid uint32"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<;1>/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<;1>/*)", "wpkh(): Key path value '' is not a valid uint32"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<0;1;>/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0;1;>/*)", "wpkh(): Key path value '' is not a valid uint32"); + CheckUnparsable("wpkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<1;1>/*)", "wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<1;1>/*)", "wpkh(): Duplicated key path value 1 in multipath specifier"); + // 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 @@ -511,8 +844,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 @@ -523,8 +856,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 @@ -544,7 +877,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( @@ -554,7 +887,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test) SIGNABLE | XONLY_KEYS, {{"5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd"}}, OutputType::BECH32M, - /*op_desc_id=*/uint256S("5ba3f7d83cee4795df00e0eaa5070a3e164283c5fc6e8586fd710eaa7a4168ec")); + /*op_desc_id=*/uint256{"5ba3f7d83cee4795df00e0eaa5070a3e164283c5fc6e8586fd710eaa7a4168ec"}); CheckUnparsable( "", @@ -605,31 +938,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, {{"ff9aa1829c90d26e73301383f549e1497b7d6325"_hex_v_u8, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"_hex_v_u8}}); // 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, {{"7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863"_hex_v_u8, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"_hex_v_u8}}); // 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, {{"292e2df59e3a22109200beed0cdc84b12e66793e"_hex_v_u8, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"_hex_v_u8}}); // 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, {{"ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"_hex_v_u8, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"_hex_v_u8}}); // 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). @@ -641,7 +974,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test) // Can sign for a Miniscript expression containing a hash challenge inside a Taproot tree. (Fails without the // preimages and the sequence, passes with.) Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(KykUPmR5967F4URzMUeCv9kNMU9CNRWycrPmx3ZvfkWoQLabbimL)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,KztMyyi1pXUtuZfJSB7JzVdmJMAz7wfGVFoSRUR5CVZxXxULXuGR)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE | SIGNABLE_FAILS, {{"51209a3d79db56fbe3ba4d905d827b62e1ed31cd6df1198b8c759d589c0f4efc27bd"}}, OutputType::BECH32M); - Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(KykUPmR5967F4URzMUeCv9kNMU9CNRWycrPmx3ZvfkWoQLabbimL)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,KztMyyi1pXUtuZfJSB7JzVdmJMAz7wfGVFoSRUR5CVZxXxULXuGR)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE, {{"51209a3d79db56fbe3ba4d905d827b62e1ed31cd6df1198b8c759d589c0f4efc27bd"}}, OutputType::BECH32M, /*op_desc_id=*/{}, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/42, /*preimages=*/{{ParseHex("ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}}); + Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(KykUPmR5967F4URzMUeCv9kNMU9CNRWycrPmx3ZvfkWoQLabbimL)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,KztMyyi1pXUtuZfJSB7JzVdmJMAz7wfGVFoSRUR5CVZxXxULXuGR)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE, {{"51209a3d79db56fbe3ba4d905d827b62e1ed31cd6df1198b8c759d589c0f4efc27bd"}}, OutputType::BECH32M, /*op_desc_id=*/{}, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/42, /*preimages=*/{{"ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"_hex_v_u8, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"_hex_v_u8}}); // Basic sh(pkh()) with key origin CheckInferDescriptor("a9141a31ad23bf49c247dd531a623c2ef57da3c400c587", "sh(pkh([deadbeef/0h/0h/0]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", {"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}, {{"03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", "deadbeef/0h/0h/0"}}); diff --git a/src/test/feefrac_tests.cpp b/src/test/feefrac_tests.cpp index 5af3c3d7ed..41c9c0a633 100644 --- a/src/test/feefrac_tests.cpp +++ b/src/test/feefrac_tests.cpp @@ -15,7 +15,7 @@ BOOST_AUTO_TEST_CASE(feefrac_operators) FeeFrac sum{1500, 400}; FeeFrac diff{500, -200}; FeeFrac empty{0, 0}; - FeeFrac zero_fee{0, 1}; // zero-fee allowed + [[maybe_unused]] FeeFrac zero_fee{0, 1}; // zero-fee allowed BOOST_CHECK(empty == FeeFrac{}); // same as no-args diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt new file mode 100644 index 0000000000..1c7b0d5c25 --- /dev/null +++ b/src/test/fuzz/CMakeLists.txt @@ -0,0 +1,147 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_subdirectory(util) + +add_executable(fuzz + addition_overflow.cpp + addrman.cpp + asmap.cpp + asmap_direct.cpp + autofile.cpp + banman.cpp + base_encode_decode.cpp + bech32.cpp + bip324.cpp + bitdeque.cpp + bitset.cpp + block.cpp + block_header.cpp + block_index.cpp + blockfilter.cpp + bloom_filter.cpp + buffered_file.cpp + chain.cpp + checkqueue.cpp + cluster_linearize.cpp + coins_view.cpp + coinscache_sim.cpp + connman.cpp + crypto.cpp + crypto_aes256.cpp + crypto_aes256cbc.cpp + crypto_chacha20.cpp + crypto_chacha20poly1305.cpp + crypto_common.cpp + crypto_diff_fuzz_chacha20.cpp + crypto_hkdf_hmac_sha256_l32.cpp + crypto_poly1305.cpp + cuckoocache.cpp + decode_tx.cpp + descriptor_parse.cpp + deserialize.cpp + eval_script.cpp + feefrac.cpp + fee_rate.cpp + feeratediagram.cpp + fees.cpp + flatfile.cpp + float.cpp + golomb_rice.cpp + headerssync.cpp + hex.cpp + http_request.cpp + i2p.cpp + integer.cpp + key.cpp + key_io.cpp + kitchen_sink.cpp + load_external_block_file.cpp + locale.cpp + merkleblock.cpp + message.cpp + miniscript.cpp + minisketch.cpp + mini_miner.cpp + muhash.cpp + multiplication_overflow.cpp + net.cpp + net_permissions.cpp + netaddress.cpp + netbase_dns_lookup.cpp + node_eviction.cpp + p2p_handshake.cpp + p2p_headers_presync.cpp + p2p_transport_serialization.cpp + package_eval.cpp + parse_hd_keypath.cpp + parse_numbers.cpp + parse_script.cpp + parse_univalue.cpp + partially_downloaded_block.cpp + policy_estimator.cpp + policy_estimator_io.cpp + poolresource.cpp + pow.cpp + prevector.cpp + primitives_transaction.cpp + process_message.cpp + process_messages.cpp + protocol.cpp + psbt.cpp + random.cpp + rbf.cpp + rolling_bloom_filter.cpp + rpc.cpp + script.cpp + script_assets_test_minimizer.cpp + script_descriptor_cache.cpp + script_flags.cpp + script_format.cpp + script_interpreter.cpp + script_ops.cpp + script_parsing.cpp + script_sigcache.cpp + script_sign.cpp + scriptnum_ops.cpp + secp256k1_ec_seckey_import_export_der.cpp + secp256k1_ecdsa_signature_parse_der_lax.cpp + signature_checker.cpp + signet.cpp + socks5.cpp + span.cpp + string.cpp + strprintf.cpp + system.cpp + timeoffsets.cpp + torcontrol.cpp + transaction.cpp + tx_in.cpp + tx_out.cpp + tx_pool.cpp + txorphan.cpp + txrequest.cpp + utxo_snapshot.cpp + utxo_total_supply.cpp + validation_load_mempool.cpp + vecdeque.cpp + versionbits.cpp +) +target_link_libraries(fuzz + core_interface + test_fuzz + bitcoin_cli + bitcoin_common + bitcoin_util + minisketch + leveldb + univalue + secp256k1 + Boost::headers + $<TARGET_NAME_IF_EXISTS:libevent::libevent> +) + +if(ENABLE_WALLET) + add_subdirectory(${PROJECT_SOURCE_DIR}/src/wallet/test/fuzz wallet) +endif() diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 8a54cc656d..bcc3dd3e14 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))); } /** @@ -186,7 +186,7 @@ public: return false; } - auto IdsReferToSameAddress = [&](int id, int other_id) EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs, other.m_impl->cs) { + auto IdsReferToSameAddress = [&](nid_type id, nid_type other_id) EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs, other.m_impl->cs) { if (id == -1 && other_id == -1) { return true; } @@ -250,19 +250,30 @@ FUZZ_TARGET(addrman, .init = initialize_addrman) LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { addresses.push_back(ConsumeAddress(fuzzed_data_provider)); } - addr_man.Add(addresses, ConsumeNetAddr(fuzzed_data_provider), std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)}); + auto net_addr = ConsumeNetAddr(fuzzed_data_provider); + auto time_penalty = std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)}; + addr_man.Add(addresses, net_addr, time_penalty); }, [&] { - addr_man.Good(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}}); + auto addr = ConsumeService(fuzzed_data_provider); + auto time = NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}}; + addr_man.Good(addr, time); }, [&] { - addr_man.Attempt(ConsumeService(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}}); + auto addr = ConsumeService(fuzzed_data_provider); + auto count_failure = fuzzed_data_provider.ConsumeBool(); + auto time = NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}}; + addr_man.Attempt(addr, count_failure, time); }, [&] { - addr_man.Connected(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}}); + auto addr = ConsumeService(fuzzed_data_provider); + auto time = NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}}; + addr_man.Connected(addr, time); }, [&] { - addr_man.SetServices(ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS)); + auto addr = ConsumeService(fuzzed_data_provider); + auto n_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS); + addr_man.SetServices(addr, n_services); }); } const AddrMan& const_addr_man{addr_man}; @@ -270,12 +281,19 @@ FUZZ_TARGET(addrman, .init = initialize_addrman) if (fuzzed_data_provider.ConsumeBool()) { network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS); } - (void)const_addr_man.GetAddr( - /*max_addresses=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), - /*max_pct=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), - network, - /*filtered=*/fuzzed_data_provider.ConsumeBool()); - (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), network); + auto max_addresses = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); + auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); + auto filtered = fuzzed_data_provider.ConsumeBool(); + (void)const_addr_man.GetAddr(max_addresses, max_pct, network, filtered); + + std::unordered_set<Network> nets; + for (const auto& net : ALL_NETWORKS) { + if (fuzzed_data_provider.ConsumeBool()) { + nets.insert(net); + } + } + (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), nets); + std::optional<bool> in_new; if (fuzzed_data_provider.ConsumeBool()) { in_new = fuzzed_data_provider.ConsumeBool(); diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp index 45316b6b21..81761c7bf9 100644 --- a/src/test/fuzz/autofile.cpp +++ b/src/test/fuzz/autofile.cpp @@ -56,7 +56,6 @@ FUZZ_TARGET(autofile) WriteToStream(fuzzed_data_provider, auto_file); }); } - (void)auto_file.Get(); (void)auto_file.IsNull(); if (fuzzed_data_provider.ConsumeBool()) { FILE* f = auto_file.release(); diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index b26151f63c..4165cc6b2c 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -78,7 +78,9 @@ FUZZ_TARGET(banman, .init = initialize_banman) contains_invalid = true; } } - ban_man.Ban(net_addr, ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); + auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider); + auto since_unix_epoch = fuzzed_data_provider.ConsumeBool(); + ban_man.Ban(net_addr, ban_time_offset, since_unix_epoch); }, [&] { CSubNet subnet{ConsumeSubNet(fuzzed_data_provider)}; @@ -86,7 +88,9 @@ FUZZ_TARGET(banman, .init = initialize_banman) if (!subnet.IsValid()) { contains_invalid = true; } - ban_man.Ban(subnet, ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); + auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider); + auto since_unix_epoch = fuzzed_data_provider.ConsumeBool(); + ban_man.Ban(subnet, ban_time_offset, since_unix_epoch); }, [&] { ban_man.ClearBanned(); diff --git a/src/test/fuzz/base_encode_decode.cpp b/src/test/fuzz/base_encode_decode.cpp index d322416d34..0cc8cb5886 100644 --- a/src/test/fuzz/base_encode_decode.cpp +++ b/src/test/fuzz/base_encode_decode.cpp @@ -14,6 +14,9 @@ #include <string> #include <vector> +using util::TrimString; +using util::TrimStringView; + FUZZ_TARGET(base_encode_decode) { const std::string random_encoded_string(buffer.begin(), buffer.end()); 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..f1fa15d8a3 100644 --- a/src/test/fuzz/bip324.cpp +++ b/src/test/fuzz/bip324.cpp @@ -4,12 +4,13 @@ #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 <algorithm> #include <cstdint> #include <vector> @@ -56,12 +57,12 @@ 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()); - assert(initiator.GetSendGarbageTerminator() == responder.GetReceiveGarbageTerminator()); - assert(initiator.GetReceiveGarbageTerminator() == responder.GetSendGarbageTerminator()); + assert(std::ranges::equal(initiator.GetSessionID(), responder.GetSessionID())); + assert(std::ranges::equal(initiator.GetSendGarbageTerminator(), responder.GetReceiveGarbageTerminator())); + assert(std::ranges::equal(initiator.GetReceiveGarbageTerminator(), responder.GetSendGarbageTerminator())); LIMITED_WHILE(provider.remaining_bytes(), 1000) { // Mode: @@ -79,10 +80,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 new file mode 100644 index 0000000000..ce6be0499c --- /dev/null +++ b/src/test/fuzz/bitset.cpp @@ -0,0 +1,316 @@ +// 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 <random.h> +#include <span.h> +#include <test/fuzz/util.h> +#include <util/bitset.h> + +#include <bitset> +#include <vector> + +namespace { + +/** Pop the first byte from a byte-span, and return it. */ +uint8_t ReadByte(FuzzBufferType& buffer) +{ + if (buffer.empty()) return 0; + uint8_t ret = buffer.front(); + buffer = buffer.subspan(1); + return ret; +} + +/** Perform a simulation fuzz test on BitSet type S. */ +template<typename S> +void TestType(FuzzBufferType buffer) +{ + /** This fuzz test's design is based on the assumption that the actual bits stored in the + * 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. */ + InsecureRandomContext rng(buffer.size() + 0x10000 * S::Size()); + + using Sim = std::bitset<S::Size()>; + // Up to 4 real BitSets (initially 2). + std::vector<S> real(2); + // Up to 4 std::bitsets with the same corresponding contents. + std::vector<Sim> sim(2); + + /* Compare sim[idx] with real[idx], using all inspector operations. */ + auto compare_fn = [&](unsigned idx) { + /* iterators and operator[] */ + auto it = real[idx].begin(); + unsigned first = S::Size(); + unsigned last = S::Size(); + for (unsigned i = 0; i < S::Size(); ++i) { + bool match = (it != real[idx].end()) && *it == i; + assert(sim[idx][i] == real[idx][i]); + assert(match == real[idx][i]); + assert((it == real[idx].end()) != (it != real[idx].end())); + if (match) { + ++it; + if (first == S::Size()) first = i; + last = i; + } + } + assert(it == real[idx].end()); + assert(!(it != real[idx].end())); + /* Any / None */ + assert(sim[idx].any() == real[idx].Any()); + assert(sim[idx].none() == real[idx].None()); + /* First / Last */ + if (sim[idx].any()) { + assert(first == real[idx].First()); + assert(last == real[idx].Last()); + } + /* Count */ + assert(sim[idx].count() == real[idx].Count()); + }; + + LIMITED_WHILE(buffer.size() > 0, 1000) { + // Read one byte to determine which operation to execute on the BitSets. + int command = ReadByte(buffer) % 64; + // Read another byte that determines which bitsets will be involved. + unsigned args = ReadByte(buffer); + unsigned dest = ((args & 7) * sim.size()) >> 3; + unsigned src = (((args >> 3) & 7) * sim.size()) >> 3; + unsigned aux = (((args >> 6) & 3) * sim.size()) >> 2; + // Args are in range for non-empty sim, or sim is completely empty and will be grown + assert((sim.empty() && dest == 0 && src == 0 && aux == 0) || + (!sim.empty() && dest < sim.size() && src < sim.size() && aux < sim.size())); + + // Pick one operation based on value of command. Not all operations are always applicable. + // Loop through the applicable ones until command reaches 0 (which avoids the need to + // compute the number of applicable commands ahead of time). + while (true) { + if (dest < sim.size() && command-- == 0) { + /* Set() (true) */ + unsigned val = ReadByte(buffer) % S::Size(); + assert(sim[dest][val] == real[dest][val]); + sim[dest].set(val); + real[dest].Set(val); + break; + } else if (dest < sim.size() && command-- == 0) { + /* Reset() */ + unsigned val = ReadByte(buffer) % S::Size(); + assert(sim[dest][val] == real[dest][val]); + sim[dest].reset(val); + real[dest].Reset(val); + break; + } else if (dest < sim.size() && command-- == 0) { + /* Set() (conditional) */ + unsigned val = ReadByte(buffer) % S::Size(); + assert(sim[dest][val] == real[dest][val]); + sim[dest].set(val, args >> 7); + real[dest].Set(val, args >> 7); + break; + } else if (sim.size() < 4 && command-- == 0) { + /* Construct empty. */ + sim.resize(sim.size() + 1); + real.resize(real.size() + 1); + break; + } else if (sim.size() < 4 && command-- == 0) { + /* Construct singleton. */ + unsigned val = ReadByte(buffer) % S::Size(); + std::bitset<S::Size()> newset; + newset[val] = true; + sim.push_back(newset); + real.push_back(S::Singleton(val)); + break; + } else if (dest < sim.size() && command-- == 0) { + /* Make random. */ + compare_fn(dest); + sim[dest].reset(); + real[dest] = S{}; + for (unsigned i = 0; i < S::Size(); ++i) { + if (rng.randbool()) { + sim[dest][i] = true; + real[dest].Set(i); + } + } + break; + } else if (dest < sim.size() && command-- == 0) { + /* Assign initializer list. */ + 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}; + sim[dest].set(r1); + sim[dest].set(r2); + sim[dest].set(r3); + break; + } else if (!sim.empty() && command-- == 0) { + /* Destruct. */ + compare_fn(sim.size() - 1); + sim.pop_back(); + real.pop_back(); + break; + } else if (sim.size() < 4 && src < sim.size() && command-- == 0) { + /* Copy construct. */ + sim.emplace_back(sim[src]); + real.emplace_back(real[src]); + break; + } else if (src < sim.size() && dest < sim.size() && command-- == 0) { + /* Copy assign. */ + compare_fn(dest); + sim[dest] = sim[src]; + real[dest] = real[src]; + break; + } else if (src < sim.size() && dest < sim.size() && command-- == 0) { + /* swap() function. */ + swap(sim[dest], sim[src]); + swap(real[dest], real[src]); + break; + } else if (sim.size() < 4 && command-- == 0) { + /* Construct with initializer list. */ + unsigned r1 = rng.randrange(S::Size()); + unsigned r2 = rng.randrange(S::Size()); + sim.emplace_back(); + sim.back().set(r1); + sim.back().set(r2); + real.push_back(S{r1, r2}); + break; + } else if (dest < sim.size() && command-- == 0) { + /* Fill() + copy assign. */ + unsigned len = ReadByte(buffer) % S::Size(); + compare_fn(dest); + sim[dest].reset(); + for (unsigned i = 0; i < len; ++i) sim[dest][i] = true; + real[dest] = S::Fill(len); + break; + } else if (src < sim.size() && command-- == 0) { + /* Iterator copy based compare. */ + unsigned val = ReadByte(buffer) % S::Size(); + /* In a first loop, compare begin..end, and copy to it_copy at some point. */ + auto it = real[src].begin(), it_copy = it; + for (unsigned i = 0; i < S::Size(); ++i) { + if (i == val) it_copy = it; + bool match = (it != real[src].end()) && *it == i; + assert(match == sim[src][i]); + if (match) ++it; + } + assert(it == real[src].end()); + /* Then compare from the copied point again to end. */ + for (unsigned i = val; i < S::Size(); ++i) { + bool match = (it_copy != real[src].end()) && *it_copy == i; + assert(match == sim[src][i]); + if (match) ++it_copy; + } + assert(it_copy == real[src].end()); + break; + } else if (src < sim.size() && dest < sim.size() && command-- == 0) { + /* operator|= */ + compare_fn(dest); + sim[dest] |= sim[src]; + real[dest] |= real[src]; + break; + } else if (src < sim.size() && dest < sim.size() && command-- == 0) { + /* operator&= */ + compare_fn(dest); + sim[dest] &= sim[src]; + real[dest] &= real[src]; + break; + } else if (src < sim.size() && dest < sim.size() && command-- == 0) { + /* operator-= */ + compare_fn(dest); + sim[dest] &= ~sim[src]; + real[dest] -= real[src]; + break; + } else if (src < sim.size() && dest < sim.size() && command-- == 0) { + /* operator^= */ + compare_fn(dest); + sim[dest] ^= sim[src]; + real[dest] ^= real[src]; + break; + } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { + /* operator| */ + compare_fn(dest); + sim[dest] = sim[src] | sim[aux]; + real[dest] = real[src] | real[aux]; + break; + } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { + /* operator& */ + compare_fn(dest); + sim[dest] = sim[src] & sim[aux]; + real[dest] = real[src] & real[aux]; + break; + } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { + /* operator- */ + compare_fn(dest); + sim[dest] = sim[src] & ~sim[aux]; + real[dest] = real[src] - real[aux]; + break; + } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { + /* operator^ */ + compare_fn(dest); + sim[dest] = sim[src] ^ sim[aux]; + real[dest] = real[src] ^ real[aux]; + break; + } else if (src < sim.size() && aux < sim.size() && command-- == 0) { + /* IsSupersetOf() and IsSubsetOf() */ + bool is_superset = (sim[aux] & ~sim[src]).none(); + bool is_subset = (sim[src] & ~sim[aux]).none(); + assert(real[src].IsSupersetOf(real[aux]) == is_superset); + assert(real[src].IsSubsetOf(real[aux]) == is_subset); + assert(real[aux].IsSupersetOf(real[src]) == is_subset); + assert(real[aux].IsSubsetOf(real[src]) == is_superset); + break; + } else if (src < sim.size() && aux < sim.size() && command-- == 0) { + /* operator== and operator!= */ + assert((sim[src] == sim[aux]) == (real[src] == real[aux])); + assert((sim[src] != sim[aux]) == (real[src] != real[aux])); + break; + } else if (src < sim.size() && aux < sim.size() && command-- == 0) { + /* Overlaps() */ + assert((sim[src] & sim[aux]).any() == real[src].Overlaps(real[aux])); + assert((sim[src] & sim[aux]).any() == real[aux].Overlaps(real[src])); + break; + } + } + } + /* Fully compare the final state. */ + for (unsigned i = 0; i < sim.size(); ++i) { + compare_fn(i); + } +} + +} // namespace + +FUZZ_TARGET(bitset) +{ + unsigned typdat = ReadByte(buffer) % 8; + if (typdat == 0) { + /* 16 bits */ + TestType<bitset_detail::IntBitSet<uint16_t>>(buffer); + TestType<bitset_detail::MultiIntBitSet<uint16_t, 1>>(buffer); + } else if (typdat == 1) { + /* 32 bits */ + TestType<bitset_detail::MultiIntBitSet<uint16_t, 2>>(buffer); + TestType<bitset_detail::IntBitSet<uint32_t>>(buffer); + } else if (typdat == 2) { + /* 48 bits */ + TestType<bitset_detail::MultiIntBitSet<uint16_t, 3>>(buffer); + } else if (typdat == 3) { + /* 64 bits */ + TestType<bitset_detail::IntBitSet<uint64_t>>(buffer); + TestType<bitset_detail::MultiIntBitSet<uint64_t, 1>>(buffer); + TestType<bitset_detail::MultiIntBitSet<uint32_t, 2>>(buffer); + TestType<bitset_detail::MultiIntBitSet<uint16_t, 4>>(buffer); + } else if (typdat == 4) { + /* 96 bits */ + TestType<bitset_detail::MultiIntBitSet<uint32_t, 3>>(buffer); + } else if (typdat == 5) { + /* 128 bits */ + TestType<bitset_detail::MultiIntBitSet<uint64_t, 2>>(buffer); + TestType<bitset_detail::MultiIntBitSet<uint32_t, 4>>(buffer); + } else if (typdat == 6) { + /* 192 bits */ + TestType<bitset_detail::MultiIntBitSet<uint64_t, 3>>(buffer); + } else if (typdat == 7) { + /* 256 bits */ + TestType<bitset_detail::MultiIntBitSet<uint64_t, 4>>(buffer); + } +} 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/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp index e30c19b265..a6a042a25c 100644 --- a/src/test/fuzz/buffered_file.cpp +++ b/src/test/fuzz/buffered_file.cpp @@ -25,7 +25,9 @@ FUZZ_TARGET(buffered_file) ConsumeRandomLengthByteVector<std::byte>(fuzzed_data_provider), }; try { - opt_buffered_file.emplace(fuzzed_file, fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096)); + auto n_buf_size = fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096); + auto n_rewind_in = fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096); + opt_buffered_file.emplace(fuzzed_file, n_buf_size, n_rewind_in); } catch (const std::ios_base::failure&) { } if (opt_buffered_file && !fuzzed_file.IsNull()) { diff --git a/src/test/fuzz/cluster_linearize.cpp b/src/test/fuzz/cluster_linearize.cpp new file mode 100644 index 0000000000..5b3770636a --- /dev/null +++ b/src/test/fuzz/cluster_linearize.cpp @@ -0,0 +1,1120 @@ +// 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 <random.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{depgraph.Positions()} {} + + /** 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{depgraph.Positions()} {} + + /** 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 = depgraph.Positions(); + 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}; +} + +/** Stitch connected components together in a DepGraph, guaranteeing its corresponding cluster is connected. */ +template<typename BS> +void MakeConnected(DepGraph<BS>& depgraph) +{ + auto todo = depgraph.Positions(); + auto comp = depgraph.FindConnectedComponent(todo); + Assume(depgraph.IsConnected(comp)); + todo -= comp; + while (todo.Any()) { + auto nextcomp = depgraph.FindConnectedComponent(todo); + Assume(depgraph.IsConnected(nextcomp)); + depgraph.AddDependencies(BS::Singleton(comp.Last()), nextcomp.First()); + todo -= nextcomp; + comp = nextcomp; + } +} + +/** 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 = depgraph.Positions(); + // 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_depgraph_sim) +{ + // Simulation test to verify the full behavior of DepGraph. + + FuzzedDataProvider provider(buffer.data(), buffer.size()); + + /** Real DepGraph being tested. */ + DepGraph<TestBitSet> real; + /** Simulated DepGraph (sim[i] is std::nullopt if position i does not exist; otherwise, + * sim[i]->first is its individual feerate, and sim[i]->second is its set of ancestors. */ + std::array<std::optional<std::pair<FeeFrac, TestBitSet>>, TestBitSet::Size()> sim; + /** The number of non-nullopt position in sim. */ + ClusterIndex num_tx_sim{0}; + + /** Read a valid index of a transaction from the provider. */ + auto idx_fn = [&]() { + auto offset = provider.ConsumeIntegralInRange<ClusterIndex>(0, num_tx_sim - 1); + for (ClusterIndex i = 0; i < sim.size(); ++i) { + if (!sim[i].has_value()) continue; + if (offset == 0) return i; + --offset; + } + assert(false); + return ClusterIndex(-1); + }; + + /** Read a valid subset of the transactions from the provider. */ + auto subset_fn = [&]() { + auto range = (uint64_t{1} << num_tx_sim) - 1; + const auto mask = provider.ConsumeIntegralInRange<uint64_t>(0, range); + auto mask_shifted = mask; + TestBitSet subset; + for (ClusterIndex i = 0; i < sim.size(); ++i) { + if (!sim[i].has_value()) continue; + if (mask_shifted & 1) { + subset.Set(i); + } + mask_shifted >>= 1; + } + assert(mask_shifted == 0); + return subset; + }; + + /** Read any set of transactions from the provider (including unused positions). */ + auto set_fn = [&]() { + auto range = (uint64_t{1} << sim.size()) - 1; + const auto mask = provider.ConsumeIntegralInRange<uint64_t>(0, range); + TestBitSet set; + for (ClusterIndex i = 0; i < sim.size(); ++i) { + if ((mask >> i) & 1) { + set.Set(i); + } + } + return set; + }; + + /** Propagate ancestor information in sim. */ + auto anc_update_fn = [&]() { + while (true) { + bool updates{false}; + for (ClusterIndex chl = 0; chl < sim.size(); ++chl) { + if (!sim[chl].has_value()) continue; + for (auto par : sim[chl]->second) { + if (!sim[chl]->second.IsSupersetOf(sim[par]->second)) { + sim[chl]->second |= sim[par]->second; + updates = true; + } + } + } + if (!updates) break; + } + }; + + /** Compare the state of transaction i in the simulation with the real one. */ + auto check_fn = [&](ClusterIndex i) { + // Compare used positions. + assert(real.Positions()[i] == sim[i].has_value()); + if (sim[i].has_value()) { + // Compare feerate. + assert(real.FeeRate(i) == sim[i]->first); + // Compare ancestors (note that SanityCheck verifies correspondence between ancestors + // and descendants, so we can restrict ourselves to ancestors here). + assert(real.Ancestors(i) == sim[i]->second); + } + }; + + LIMITED_WHILE(provider.remaining_bytes() > 0, 1000) { + uint8_t command = provider.ConsumeIntegral<uint8_t>(); + if (num_tx_sim == 0 || ((command % 3) <= 0 && num_tx_sim < TestBitSet::Size())) { + // AddTransaction. + auto fee = provider.ConsumeIntegralInRange<int64_t>(-0x8000000000000, 0x7ffffffffffff); + auto size = provider.ConsumeIntegralInRange<int32_t>(1, 0x3fffff); + FeeFrac feerate{fee, size}; + // Apply to DepGraph. + auto idx = real.AddTransaction(feerate); + // Verify that the returned index is correct. + assert(!sim[idx].has_value()); + for (ClusterIndex i = 0; i < TestBitSet::Size(); ++i) { + if (!sim[i].has_value()) { + assert(idx == i); + break; + } + } + // Update sim. + sim[idx] = {feerate, TestBitSet::Singleton(idx)}; + ++num_tx_sim; + continue; + } + if ((command % 3) <= 1 && num_tx_sim > 0) { + // AddDependencies. + ClusterIndex child = idx_fn(); + auto parents = subset_fn(); + // Apply to DepGraph. + real.AddDependencies(parents, child); + // Apply to sim. + sim[child]->second |= parents; + continue; + } + if (num_tx_sim > 0) { + // Remove transactions. + auto del = set_fn(); + // Propagate all ancestry information before deleting anything in the simulation (as + // intermediary transactions may be deleted which impact connectivity). + anc_update_fn(); + // Compare the state of the transactions being deleted. + for (auto i : del) check_fn(i); + // Apply to DepGraph. + real.RemoveTransactions(del); + // Apply to sim. + for (ClusterIndex i = 0; i < sim.size(); ++i) { + if (sim[i].has_value()) { + if (del[i]) { + --num_tx_sim; + sim[i] = std::nullopt; + } else { + sim[i]->second -= del; + } + } + } + continue; + } + // This should be unreachable (one of the 3 above actions should always be possible). + assert(false); + } + + // Compare the real obtained depgraph against the simulation. + anc_update_fn(); + for (ClusterIndex i = 0; i < sim.size(); ++i) check_fn(i); + assert(real.TxCount() == num_tx_sim); + // Sanity check the result (which includes round-tripping serialization, if applicable). + SanityCheck(real); +} + +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 = depgraph.Positions(); + 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 == depgraph.Positions()) { + 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 : depgraph.Positions()) { + 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_make_connected) +{ + // Verify that MakeConnected makes graphs connected. + + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + MakeConnected(depgraph); + SanityCheck(depgraph); + assert(depgraph.IsConnected()); +} + +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 = depgraph.Positions(); + for (const auto& chunk_feerate : chunking) { + assert(todo.Any()); + SetInfo<TestBitSet> accumulator, best; + for (ClusterIndex idx : linearization) { + if (todo[idx]) { + accumulator.Set(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 = depgraph.Positions(); + while (todo.Any()) { + // Call the ancestor finder's FindCandidateSet for what remains of the graph. + assert(!anc_finder.AllDone()); + assert(todo.Count() == anc_finder.NumRemaining()); + 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()); + assert(anc_finder.NumRemaining() == 0); +} + +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, a depgraph, and whether to make it connected, from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + uint64_t rng_seed{0}; + uint8_t make_connected{1}; + try { + reader >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> make_connected; + } catch (const std::ios_base::failure&) {} + // The most complicated graphs are connected ones (other ones just split up). Optionally force + // the graph to be connected. + if (make_connected) MakeConnected(depgraph); + + // 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 = depgraph.Positions(); + while (todo.Any()) { + assert(!src_finder.AllDone()); + assert(!smp_finder.AllDone()); + assert(!exh_finder.AllDone()); + assert(!anc_finder.AllDone()); + assert(anc_finder.NumRemaining() == todo.Count()); + + // 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 maximum number of non-empty topological + // subsets a (connected) cluster with N transactions can have. Even when the cluster is no + // longer connected after removing certain transactions, this holds, because the connected + // components are searched separately. + assert(iterations_done <= (uint64_t{1} << (todo.Count() - 1))); + // Additionally, test that no more than sqrt(2^N)+1 iterations are required. This is just + // an empirical bound that seems to hold, without proof. Still, add a test for it so we + // can learn about counterexamples if they exist. + if (iterations_done >= 1 && todo.Count() <= 63) { + Assume((iterations_done - 1) * (iterations_done - 1) <= uint64_t{1} << todo.Count()); + } + + // 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()); + assert(anc_finder.NumRemaining() == 0); +} + +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 = depgraph.Positions(); + 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.Set(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, a depgraph, and whether to make it connected from + // the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + uint64_t rng_seed{0}; + uint64_t iter_count{0}; + uint8_t make_connected{1}; + try { + reader >> VARINT(iter_count) >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> make_connected; + } catch (const std::ios_base::failure&) {} + // The most complicated graphs are connected ones (other ones just split up). Optionally force + // the graph to be connected. + if (make_connected) MakeConnected(depgraph); + + // 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-1) iterations, with steps k=1..n. That sum is + // 2^n - 1. + const uint64_t n = depgraph.TxCount(); + if (n <= 19 && iter_count > (uint64_t{1} << n)) { + assert(optimal); + } + // Additionally, if the assumption of sqrt(2^k)+1 iterations per step holds, plus ceil(k/4) + // start-up cost per step, plus ceil(n^2/64) start-up cost overall, we can compute the upper + // bound for a whole linearization (summing for k=1..n) using the Python expression + // [sum((k+3)//4 + int(math.sqrt(2**k)) + 1 for k in range(1, n + 1)) + (n**2 + 63) // 64 for n in range(0, 35)]: + static constexpr uint64_t MAX_OPTIMAL_ITERS[] = { + 0, 4, 8, 12, 18, 26, 37, 51, 70, 97, 133, 182, 251, 346, 480, 666, 927, 1296, 1815, 2545, + 3576, 5031, 7087, 9991, 14094, 19895, 28096, 39690, 56083, 79263, 112041, 158391, 223936, + 316629, 447712 + }; + if (n < std::size(MAX_OPTIMAL_ITERS) && iter_count >= MAX_OPTIMAL_ITERS[n]) { + Assume(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; + for (ClusterIndex i : depgraph.Positions()) perm_linearization.push_back(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.PositionRange(); ++i) { + if (depgraph_gen.Positions()[i]) { + depgraph_tree.AddTransaction(depgraph_gen.FeeRate(i)); + } else { + // For holes, add a dummy transaction which is deleted below, so that non-hole + // transactions retain their position. + depgraph_tree.AddTransaction(FeeFrac{}); + } + } + depgraph_tree.RemoveTransactions(TestBitSet::Fill(depgraph_gen.PositionRange()) - depgraph_gen.Positions()); + + if (direction & 1) { + for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) { + auto children = depgraph_gen.GetReducedChildren(i); + if (children.Any()) { + depgraph_tree.AddDependencies(TestBitSet::Singleton(i), children.First()); + } + } + } else { + for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) { + auto parents = depgraph_gen.GetReducedParents(i); + if (parents.Any()) { + depgraph_tree.AddDependencies(TestBitSet::Singleton(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/connman.cpp b/src/test/fuzz/connman.cpp index 8f5f6a6071..beefc9d82e 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -91,17 +91,15 @@ FUZZ_TARGET(connman, .init = initialize_connman) (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); }); }, [&] { - (void)connman.GetAddresses( - /*max_addresses=*/fuzzed_data_provider.ConsumeIntegral<size_t>(), - /*max_pct=*/fuzzed_data_provider.ConsumeIntegral<size_t>(), - /*network=*/std::nullopt, - /*filtered=*/fuzzed_data_provider.ConsumeBool()); + auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>(); + auto max_pct = fuzzed_data_provider.ConsumeIntegral<size_t>(); + auto filtered = fuzzed_data_provider.ConsumeBool(); + (void)connman.GetAddresses(max_addresses, max_pct, /*network=*/std::nullopt, filtered); }, [&] { - (void)connman.GetAddresses( - /*requestor=*/random_node, - /*max_addresses=*/fuzzed_data_provider.ConsumeIntegral<size_t>(), - /*max_pct=*/fuzzed_data_provider.ConsumeIntegral<size_t>()); + auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>(); + auto max_pct = fuzzed_data_provider.ConsumeIntegral<size_t>(); + (void)connman.GetAddresses(/*requestor=*/random_node, max_addresses, max_pct); }, [&] { (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp index ca8c1cd033..aa478277e3 100644 --- a/src/test/fuzz/crypto.cpp +++ b/src/test/fuzz/crypto.cpp @@ -22,7 +22,9 @@ FUZZ_TARGET(crypto) FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider); if (data.empty()) { - data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); + auto new_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096); + auto x = fuzzed_data_provider.ConsumeIntegral<uint8_t>(); + data.resize(new_size, x); } CHash160 hash160; @@ -44,7 +46,9 @@ FUZZ_TARGET(crypto) if (fuzzed_data_provider.ConsumeBool()) { data = ConsumeRandomLengthByteVector(fuzzed_data_provider); if (data.empty()) { - data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); + auto new_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096); + auto x = fuzzed_data_provider.ConsumeIntegral<uint8_t>(); + data.resize(new_size, x); } } diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp index 50c77bf699..fe47f18923 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> @@ -28,11 +28,10 @@ FUZZ_TARGET(crypto_chacha20) chacha20.SetKey(key); }, [&] { - chacha20.Seek( - { - fuzzed_data_provider.ConsumeIntegral<uint32_t>(), - fuzzed_data_provider.ConsumeIntegral<uint64_t>() - }, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); + ChaCha20::Nonce96 nonce{ + fuzzed_data_provider.ConsumeIntegral<uint32_t>(), + fuzzed_data_provider.ConsumeIntegral<uint64_t>()}; + chacha20.Seek(nonce, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); }, [&] { std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); @@ -53,7 +52,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 +77,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..0700ba7fb6 --- /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(), 100) + { + // 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(), 100) + { + // 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/crypto_common.cpp b/src/test/fuzz/crypto_common.cpp index 8e07dfedb9..5a76d4e1a9 100644 --- a/src/test/fuzz/crypto_common.cpp +++ b/src/test/fuzz/crypto_common.cpp @@ -35,6 +35,10 @@ FUZZ_TARGET(crypto_common) WriteLE64(writele64_arr.data(), random_u64); assert(ReadLE64(writele64_arr.data()) == random_u64); + std::array<uint8_t, 2> writebe16_arr; + WriteBE16(writebe16_arr.data(), random_u16); + assert(ReadBE16(writebe16_arr.data()) == random_u16); + std::array<uint8_t, 4> writebe32_arr; WriteBE32(writebe32_arr.data(), random_u32); assert(ReadBE32(writebe32_arr.data()) == random_u32); diff --git a/src/test/fuzz/cuckoocache.cpp b/src/test/fuzz/cuckoocache.cpp index 50a71ee03f..f8a5bde3e6 100644 --- a/src/test/fuzz/cuckoocache.cpp +++ b/src/test/fuzz/cuckoocache.cpp @@ -41,7 +41,9 @@ FUZZ_TARGET(cuckoocache) if (fuzzed_data_provider.ConsumeBool()) { cuckoo_cache.insert(fuzzed_data_provider.ConsumeBool()); } else { - cuckoo_cache.contains(fuzzed_data_provider.ConsumeBool(), fuzzed_data_provider.ConsumeBool()); + auto e = fuzzed_data_provider.ConsumeBool(); + auto erase = fuzzed_data_provider.ConsumeBool(); + cuckoo_cache.contains(e, erase); } } fuzzed_data_provider_ptr = nullptr; diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index b9a5560ffb..765daa3db7 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -15,14 +15,24 @@ MockedDescriptorConverter MOCKED_DESC_CONVERTER; /** Test a successfully parsed descriptor. */ -static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy) +static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy, std::optional<bool>& is_ranged, std::optional<bool>& is_solvable) { // Trivial helpers. (void)desc.IsRange(); - const bool is_solvable{desc.IsSolvable()}; (void)desc.IsSingleType(); (void)desc.GetOutputType(); + if (is_ranged.has_value()) { + assert(desc.IsRange() == *is_ranged); + } else { + is_ranged = desc.IsRange(); + } + if (is_solvable.has_value()) { + assert(desc.IsSolvable() == *is_solvable); + } else { + is_solvable = desc.IsSolvable(); + } + // Serialization to string representation. (void)desc.ToString(); (void)desc.ToPrivateString(sig_provider, dummy); @@ -48,7 +58,7 @@ static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_prov const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)}; const auto max_elems{desc.MaxSatisfactionElems()}; // We must be able to estimate the max satisfaction size for any solvable descriptor (but combo). - const bool is_nontop_or_nonsolvable{!is_solvable || !desc.GetOutputType()}; + const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()}; const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems}; assert(is_input_size_info_set || is_nontop_or_nonsolvable); } @@ -72,25 +82,45 @@ 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; std::string error; const auto desc = Parse(*descriptor, signing_provider, error); - if (desc) TestDescriptor(*desc, signing_provider, error); + std::optional<bool> is_ranged; + std::optional<bool> is_solvable; + for (const auto& d : desc) { + assert(d); + TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable); + } } } 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; std::string error; for (const bool require_checksum : {true, false}) { const auto desc = Parse(descriptor, signing_provider, error, require_checksum); - if (desc) TestDescriptor(*desc, signing_provider, error); + std::optional<bool> is_ranged; + std::optional<bool> is_solvable; + for (const auto& d : desc) { + assert(d); + TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable); + } } } diff --git a/src/test/fuzz/fees.cpp b/src/test/fuzz/fees.cpp index 38a8c6798e..5c760be13d 100644 --- a/src/test/fuzz/fees.cpp +++ b/src/test/fuzz/fees.cpp @@ -2,17 +2,19 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/messages.h> #include <consensus/amount.h> #include <policy/fees.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> -#include <util/fees.h> #include <cstdint> #include <string> #include <vector> +using common::StringForFeeReason; + FUZZ_TARGET(fees) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 9a54a44bd3..bba2dd8e3a 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> @@ -48,7 +49,7 @@ static std::vector<const char*> g_args; static void SetArgs(int argc, char** argv) { for (int i = 1; i < argc; ++i) { // Only take into account arguments that start with `--`. The others are for the fuzz engine: - // `fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5` + // `fuzz -runs=1 fuzz_corpora/address_deserialize_v2 --checkaddrman=5` if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == '-') { g_args.push_back(argv[i]); } @@ -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,8 +102,15 @@ void ResetCoverageCounters() {} void initialize() { - // Terminate immediately if a fuzzing harness ever tries to create a TCP socket. - CreateSock = [](const sa_family_t&) -> std::unique_ptr<Sock> { std::terminate(); }; + // 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. + SeedRandomStateForTest(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(); }; // Terminate immediately if a fuzzing harness ever tries to perform a DNS lookup. g_dns_lookup = [](const std::string& name, bool allow_lookup) { diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h index ca74d53de7..c468cd39e3 100644 --- a/src/test/fuzz/fuzz.h +++ b/src/test/fuzz/fuzz.h @@ -5,10 +5,9 @@ #ifndef BITCOIN_TEST_FUZZ_FUZZ_H #define BITCOIN_TEST_FUZZ_FUZZ_H -#include <span.h> - #include <cstdint> #include <functional> +#include <span> #include <string_view> /** @@ -23,7 +22,7 @@ #define LIMITED_WHILE(condition, limit) \ for (unsigned _count{limit}; (condition) && _count; --_count) -using FuzzBufferType = Span<const uint8_t>; +using FuzzBufferType = std::span<const uint8_t>; using TypeTestOneInput = std::function<void(FuzzBufferType)>; struct FuzzTargetOptions { diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp index f67b820d11..3dcf1ed3d5 100644 --- a/src/test/fuzz/hex.cpp +++ b/src/test/fuzz/hex.cpp @@ -10,7 +10,9 @@ #include <uint256.h> #include <univalue.h> #include <util/strencodings.h> +#include <util/transaction_identifier.h> +#include <algorithm> #include <cassert> #include <cstdint> #include <string> @@ -21,15 +23,26 @@ FUZZ_TARGET(hex) const std::string random_hex_string(buffer.begin(), buffer.end()); const std::vector<unsigned char> data = ParseHex(random_hex_string); const std::vector<std::byte> bytes{ParseHex<std::byte>(random_hex_string)}; - assert(AsBytes(Span{data}) == Span{bytes}); + assert(std::ranges::equal(AsBytes(Span{data}), bytes)); const std::string hex_data = HexStr(data); if (IsHex(random_hex_string)) { assert(ToLower(random_hex_string) == hex_data); } - (void)IsHexNumber(random_hex_string); - uint256 result; - (void)ParseHashStr(random_hex_string, result); - (void)uint256S(random_hex_string); + if (uint256::FromHex(random_hex_string)) { + assert(random_hex_string.length() == 64); + assert(Txid::FromHex(random_hex_string)); + assert(Wtxid::FromHex(random_hex_string)); + assert(uint256::FromUserHex(random_hex_string)); + } + if (const auto result{uint256::FromUserHex(random_hex_string)}) { + const auto result_string{result->ToString()}; // ToString() returns a fixed-length string without "0x" prefix + assert(result_string.length() == 64); + assert(IsHex(result_string)); + assert(TryParseHex(result_string)); + assert(Txid::FromHex(result_string)); + assert(Wtxid::FromHex(result_string)); + assert(uint256::FromHex(result_string)); + } try { (void)HexToPubKey(random_hex_string); } catch (const UniValue&) { diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp new file mode 100644 index 0000000000..51517187a0 --- /dev/null +++ b/src/test/fuzz/i2p.cpp @@ -0,0 +1,63 @@ +// 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 <common/args.h> +#include <i2p.h> +#include <netaddress.h> +#include <netbase.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> +#include <test/util/setup_common.h> +#include <util/fs_helpers.h> +#include <util/threadinterrupt.h> + +void initialize_i2p() +{ + static const auto testing_setup = MakeNoLogFileContext<>(); +} + +FUZZ_TARGET(i2p, .init = initialize_i2p) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + + SetMockTime(ConsumeTime(fuzzed_data_provider)); + + // Mock CreateSock() to create FuzzedSock. + auto CreateSockOrig = CreateSock; + CreateSock = [&fuzzed_data_provider](int, int, int) { + return std::make_unique<FuzzedSock>(fuzzed_data_provider); + }; + + const fs::path private_key_path = gArgs.GetDataDirNet() / "fuzzed_i2p_private_key"; + const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), 7656}; + const Proxy sam_proxy{addr, false}; + CThreadInterrupt interrupt; + + i2p::sam::Session session{private_key_path, sam_proxy, &interrupt}; + i2p::Connection conn; + + if (session.Listen(conn)) { + if (session.Accept(conn)) { + try { + (void)conn.sock->RecvUntilTerminator('\n', 10ms, interrupt, i2p::sam::MAX_MSG_SIZE); + } catch (const std::runtime_error&) { + } + } + } + + bool proxy_error; + + if (session.Connect(CService{}, conn, proxy_error)) { + try { + conn.sock->SendComplete("verack\n", 10ms, interrupt); + } catch (const std::runtime_error&) { + } + } + + fs::remove_all(private_key_path); + + CreateSock = CreateSockOrig; +} diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index db246bb84e..b9e3154106 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -40,6 +40,8 @@ #include <set> #include <vector> +using util::ToString; + void initialize_integer() { SelectParams(ChainType::REGTEST); @@ -67,7 +69,7 @@ FUZZ_TARGET(integer, .init = initialize_integer) const bool b = fuzzed_data_provider.ConsumeBool(); const Consensus::Params& consensus_params = Params().GetConsensus(); - (void)CheckProofOfWork(u256, u32, consensus_params); + (void)CheckProofOfWorkImpl(u256, u32, consensus_params); if (u64 <= MAX_MONEY) { const uint64_t compressed_money_amount = CompressAmount(u64); assert(u64 == DecompressAmount(compressed_money_amount)); @@ -76,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); @@ -138,7 +140,7 @@ FUZZ_TARGET(integer, .init = initialize_integer) const arith_uint256 au256 = UintToArith256(u256); assert(ArithToUint256(au256) == u256); - assert(uint256S(au256.GetHex()) == u256); + assert(uint256::FromHex(au256.GetHex()).value() == u256); (void)au256.bits(); (void)au256.GetCompact(/* fNegative= */ false); (void)au256.GetCompact(/* fNegative= */ true); diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp index 82f3a306c5..62b49106cd 100644 --- a/src/test/fuzz/kitchen_sink.cpp +++ b/src/test/fuzz/kitchen_sink.cpp @@ -2,13 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/messages.h> #include <merkleblock.h> +#include <node/types.h> #include <policy/fees.h> #include <rpc/util.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> -#include <util/error.h> #include <util/translation.h> #include <array> @@ -16,17 +17,15 @@ #include <optional> #include <vector> +using common::TransactionErrorString; +using node::TransactionError; + namespace { constexpr TransactionError ALL_TRANSACTION_ERROR[] = { - TransactionError::OK, TransactionError::MISSING_INPUTS, - TransactionError::ALREADY_IN_CHAIN, - TransactionError::P2P_DISABLED, + TransactionError::ALREADY_IN_UTXO_SET, TransactionError::MEMPOOL_REJECTED, TransactionError::MEMPOOL_ERROR, - TransactionError::INVALID_PSBT, - TransactionError::PSBT_MISMATCH, - TransactionError::SIGHASH_MISMATCH, TransactionError::MAX_FEE_EXCEEDED, }; }; // namespace diff --git a/src/test/fuzz/locale.cpp b/src/test/fuzz/locale.cpp index 0f2985b504..68db842247 100644 --- a/src/test/fuzz/locale.cpp +++ b/src/test/fuzz/locale.cpp @@ -51,7 +51,7 @@ FUZZ_TARGET(locale) int64_t parseint64_out_without_locale; const bool parseint64_without_locale = ParseInt64(random_string, &parseint64_out_without_locale); const int64_t random_int64 = fuzzed_data_provider.ConsumeIntegral<int64_t>(); - const std::string tostring_without_locale = ToString(random_int64); + const std::string tostring_without_locale = util::ToString(random_int64); // The variable `random_int32` is no longer used, but the harness still needs to // consume the same data that it did previously to not invalidate existing seeds. const int32_t random_int32 = fuzzed_data_provider.ConsumeIntegral<int32_t>(); @@ -75,7 +75,7 @@ FUZZ_TARGET(locale) if (parseint64_without_locale) { assert(parseint64_out_without_locale == parseint64_out_with_locale); } - const std::string tostring_with_locale = ToString(random_int64); + const std::string tostring_with_locale = util::ToString(random_int64); assert(tostring_without_locale == tostring_with_locale); const std::string strprintf_int_with_locale = strprintf("%d", random_int64); assert(strprintf_int_without_locale == strprintf_int_with_locale); diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp index 75baaa2754..99bbad6591 100644 --- a/src/test/fuzz/message.cpp +++ b/src/test/fuzz/message.cpp @@ -3,12 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> +#include <common/signmessage.h> #include <key_io.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> #include <util/chaintype.h> -#include <util/message.h> #include <util/strencodings.h> #include <cassert> @@ -39,7 +39,9 @@ FUZZ_TARGET(message, .init = initialize_message) } { (void)MessageHash(random_message); - (void)MessageVerify(fuzzed_data_provider.ConsumeRandomLengthString(1024), fuzzed_data_provider.ConsumeRandomLengthString(1024), random_message); + auto address = fuzzed_data_provider.ConsumeRandomLengthString(1024); + auto signature = fuzzed_data_provider.ConsumeRandomLengthString(1024); + (void)MessageVerify(address, signature, random_message); (void)SigningResultString(fuzzed_data_provider.PickValueInArray({SigningResult::OK, SigningResult::PRIVATE_KEY_NOT_AVAILABLE, SigningResult::SIGNING_FAILED})); } } diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp index 84f9bb4ad0..51de4d0166 100644 --- a/src/test/fuzz/mini_miner.cpp +++ b/src/test/fuzz/mini_miner.cpp @@ -7,11 +7,13 @@ #include <test/util/txmempool.h> #include <test/util/mining.h> -#include <node/mini_miner.h> #include <node/miner.h> +#include <node/mini_miner.h> #include <primitives/transaction.h> #include <random.h> #include <txmempool.h> +#include <util/check.h> +#include <util/translation.h> #include <deque> #include <vector> @@ -33,7 +35,9 @@ void initialize_miner() FUZZ_TARGET(mini_miner, .init = initialize_miner) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - CTxMemPool pool{CTxMemPool::Options{}}; + bilingual_str error; + CTxMemPool pool{CTxMemPool::Options{}, error}; + Assert(error.empty()); std::vector<COutPoint> outpoints; std::deque<COutPoint> available_coins = g_available_coins; LOCK2(::cs_main, pool.cs); @@ -109,7 +113,9 @@ FUZZ_TARGET(mini_miner, .init = initialize_miner) FUZZ_TARGET(mini_miner_selection, .init = initialize_miner) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - CTxMemPool pool{CTxMemPool::Options{}}; + bilingual_str error; + CTxMemPool pool{CTxMemPool::Options{}, error}; + Assert(error.empty()); // Make a copy to preserve determinism. std::deque<COutPoint> available_coins = g_available_coins; std::vector<CTransactionRef> transactions; @@ -182,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..5b9e168856 100644 --- a/src/test/fuzz/miniscript.cpp +++ b/src/test/fuzz/miniscript.cpp @@ -13,6 +13,8 @@ #include <test/fuzz/util.h> #include <util/strencodings.h> +#include <algorithm> + namespace { using Fragment = miniscript::Fragment; @@ -47,9 +49,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; @@ -293,7 +295,7 @@ const struct CheckerContext: BaseSignatureChecker { XOnlyPubKey pk{pubkey}; auto it = TEST_DATA.schnorr_sigs.find(pk); if (it == TEST_DATA.schnorr_sigs.end()) return false; - return it->second.first == sig; + return std::ranges::equal(it->second.first, sig); } bool CheckLockTime(const CScriptNum& nLockTime) const override { return nLockTime.GetInt64() & 1; } bool CheckSequence(const CScriptNum& nSequence) const override { return nSequence.GetInt64() & 1; } diff --git a/src/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp index 8304e6fdb8..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( @@ -43,16 +43,28 @@ FUZZ_TARGET(muhash) }, [&] { // Test that dividing a MuHash by itself brings it back to it's initial state + + // See note about clang + self-assignment in test/uint256_tests.cpp + #if defined(__clang__) + # pragma clang diagnostic push + # pragma clang diagnostic ignored "-Wself-assign-overloaded" + #endif + muhash /= muhash; + + #if defined(__clang__) + # pragma clang diagnostic pop + #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..6c1ed11d45 --- /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 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_headers_presync.cpp b/src/test/fuzz/p2p_headers_presync.cpp new file mode 100644 index 0000000000..2670aa8ee4 --- /dev/null +++ b/src/test/fuzz/p2p_headers_presync.cpp @@ -0,0 +1,216 @@ +#include <blockencodings.h> +#include <net.h> +#include <net_processing.h> +#include <netmessagemaker.h> +#include <node/peerman_args.h> +#include <pow.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <test/util/net.h> +#include <test/util/script.h> +#include <test/util/setup_common.h> +#include <uint256.h> +#include <validation.h> + +namespace { +constexpr uint32_t FUZZ_MAX_HEADERS_RESULTS{16}; + +class HeadersSyncSetup : public TestingSetup +{ + std::vector<CNode*> m_connections; + +public: + HeadersSyncSetup(const ChainType chain_type, TestOpts opts) : TestingSetup(chain_type, opts) + { + PeerManager::Options peerman_opts; + node::ApplyArgsManOptions(*m_node.args, peerman_opts); + peerman_opts.max_headers_result = FUZZ_MAX_HEADERS_RESULTS; + m_node.peerman = PeerManager::make(*m_node.connman, *m_node.addrman, + m_node.banman.get(), *m_node.chainman, + *m_node.mempool, *m_node.warnings, peerman_opts); + + CConnman::Options options; + options.m_msgproc = m_node.peerman.get(); + m_node.connman->Init(options); + } + + void ResetAndInitialize() EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex); + void SendMessage(FuzzedDataProvider& fuzzed_data_provider, CSerializedNetMsg&& msg) + EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex); +}; + +void HeadersSyncSetup::ResetAndInitialize() +{ + m_connections.clear(); + auto& connman = static_cast<ConnmanTestMsg&>(*m_node.connman); + connman.StopNodes(); + + NodeId id{0}; + std::vector<ConnectionType> conn_types = { + ConnectionType::OUTBOUND_FULL_RELAY, + ConnectionType::BLOCK_RELAY, + ConnectionType::INBOUND + }; + + for (auto conn_type : conn_types) { + CAddress addr{}; + m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false)); + CNode& p2p_node = *m_connections.back(); + + connman.Handshake( + /*node=*/p2p_node, + /*successfully_connected=*/true, + /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS), + /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS), + /*version=*/PROTOCOL_VERSION, + /*relay_txs=*/true); + + connman.AddTestNode(p2p_node); + } +} + +void HeadersSyncSetup::SendMessage(FuzzedDataProvider& fuzzed_data_provider, CSerializedNetMsg&& msg) +{ + auto& connman = static_cast<ConnmanTestMsg&>(*m_node.connman); + CNode& connection = *PickValue(fuzzed_data_provider, m_connections); + + connman.FlushSendBuffer(connection); + (void)connman.ReceiveMsgFrom(connection, std::move(msg)); + connection.fPauseSend = false; + try { + connman.ProcessMessagesOnce(connection); + } catch (const std::ios_base::failure&) { + } + m_node.peerman->SendMessages(&connection); +} + +CBlockHeader ConsumeHeader(FuzzedDataProvider& fuzzed_data_provider, const uint256& prev_hash, uint32_t prev_nbits) +{ + CBlockHeader header; + header.nNonce = 0; + // Either use the previous difficulty or let the fuzzer choose + header.nBits = fuzzed_data_provider.ConsumeBool() ? + prev_nbits : + fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0x17058EBE, 0x1D00FFFF); + header.nTime = ConsumeTime(fuzzed_data_provider); + header.hashPrevBlock = prev_hash; + header.nVersion = fuzzed_data_provider.ConsumeIntegral<int32_t>(); + return header; +} + +CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const uint256& prev_hash, uint32_t prev_nbits) +{ + auto header = ConsumeHeader(fuzzed_data_provider, prev_hash, prev_nbits); + // In order to reach the headers acceptance logic, the block is + // constructed in a way that will pass the mutation checks. + CBlock block{header}; + CMutableTransaction tx; + tx.vin.resize(1); + tx.vout.resize(1); + tx.vout[0].nValue = 0; + tx.vin[0].scriptSig.resize(2); + block.vtx.push_back(MakeTransactionRef(tx)); + block.hashMerkleRoot = block.vtx[0]->GetHash(); + return block; +} + +void FinalizeHeader(CBlockHeader& header, const ChainstateManager& chainman) +{ + while (!CheckProofOfWork(header.GetHash(), header.nBits, chainman.GetParams().GetConsensus())) { + ++(header.nNonce); + } +} + +// Global setup works for this test as state modification (specifically in the +// block index) would indicate a bug. +HeadersSyncSetup* g_testing_setup; + +void initialize() +{ + static auto setup = MakeNoLogFileContext<HeadersSyncSetup>(ChainType::MAIN, {.extra_args = {"-checkpoints=0"}}); + g_testing_setup = setup.get(); +} +} // namespace + +FUZZ_TARGET(p2p_headers_presync, .init = initialize) +{ + ChainstateManager& chainman = *g_testing_setup->m_node.chainman; + + LOCK(NetEventsInterface::g_msgproc_mutex); + + g_testing_setup->ResetAndInitialize(); + + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + + CBlockHeader base{chainman.GetParams().GenesisBlock()}; + SetMockTime(base.nTime); + + // The chain is just a single block, so this is equal to 1 + size_t original_index_size{WITH_LOCK(cs_main, return chainman.m_blockman.m_block_index.size())}; + arith_uint256 total_work{WITH_LOCK(cs_main, return chainman.m_best_header->nChainWork)}; + + std::vector<CBlockHeader> all_headers; + + LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) + { + auto finalized_block = [&]() { + CBlock block = ConsumeBlock(fuzzed_data_provider, base.GetHash(), base.nBits); + FinalizeHeader(block, chainman); + return block; + }; + + // Send low-work headers, compact blocks, and blocks + CallOneOf( + fuzzed_data_provider, + [&]() NO_THREAD_SAFETY_ANALYSIS { + // Send FUZZ_MAX_HEADERS_RESULTS headers + std::vector<CBlock> headers; + headers.resize(FUZZ_MAX_HEADERS_RESULTS); + for (CBlock& header : headers) { + header = ConsumeHeader(fuzzed_data_provider, base.GetHash(), base.nBits); + FinalizeHeader(header, chainman); + base = header; + } + + all_headers.insert(all_headers.end(), headers.begin(), headers.end()); + + auto headers_msg = NetMsg::Make(NetMsgType::HEADERS, TX_WITH_WITNESS(headers)); + g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg)); + }, + [&]() NO_THREAD_SAFETY_ANALYSIS { + // Send a compact block + auto block = finalized_block(); + CBlockHeaderAndShortTxIDs cmpct_block{block, fuzzed_data_provider.ConsumeIntegral<uint64_t>()}; + + all_headers.push_back(block); + + auto headers_msg = NetMsg::Make(NetMsgType::CMPCTBLOCK, TX_WITH_WITNESS(cmpct_block)); + g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg)); + }, + [&]() NO_THREAD_SAFETY_ANALYSIS { + // Send a block + auto block = finalized_block(); + + all_headers.push_back(block); + + auto headers_msg = NetMsg::Make(NetMsgType::BLOCK, TX_WITH_WITNESS(block)); + g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg)); + }); + } + + // This is a conservative overestimate, as base is only moved forward when sending headers. In theory, + // the longest chain generated by this test is 1600 (FUZZ_MAX_HEADERS_RESULTS * 100) headers. In that case, + // this variable will accurately reflect the chain's total work. + total_work += CalculateClaimedHeadersWork(all_headers); + + // This test should never create a chain with more work than MinimumChainWork. + assert(total_work < chainman.MinimumChainWork()); + + // The headers/blocks sent in this test should never be stored, as the chains don't have the work required + // to meet the anti-DoS work threshold. So, if at any point the block index grew in size, then there's a bug + // in the headers pre-sync logic. + assert(WITH_LOCK(cs_main, return chainman.m_blockman.m_block_index.size()) == original_index_size); + + g_testing_setup->m_node.validation_signals->SyncWithValidationInterfaceQueue(); +} diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp index 767238d103..cf3ef45c0a 100644 --- a/src/test/fuzz/p2p_transport_serialization.cpp +++ b/src/test/fuzz/p2p_transport_serialization.cpp @@ -10,9 +10,9 @@ #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 <algorithm> #include <cassert> #include <cstdint> #include <limits> @@ -104,7 +104,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 +165,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; }; @@ -187,12 +186,12 @@ void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDa // Compare with expected more. if (expect_more[side].has_value()) assert(!bytes.empty() == *expect_more[side]); // Verify consistency between the two results. - assert(bytes == bytes_next); + assert(std::ranges::equal(bytes, bytes_next)); assert(msg_type == msg_type_next); if (more_nonext) assert(more_next); // Compare with previously reported output. assert(to_send[side].size() <= bytes.size()); - assert(to_send[side] == Span{bytes}.first(to_send[side].size())); + assert(std::ranges::equal(to_send[side], Span{bytes}.first(to_send[side].size()))); to_send[side].resize(bytes.size()); std::copy(bytes.begin(), bytes.end(), to_send[side].begin()); // Remember 'more' results. @@ -280,7 +279,7 @@ void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDa // The m_type must match what is expected. assert(received.m_type == expected[side].front().m_type); // The data must match what is expected. - assert(MakeByteSpan(received.m_recv) == MakeByteSpan(expected[side].front().data)); + assert(std::ranges::equal(received.m_recv, MakeByteSpan(expected[side].front().data))); expected[side].pop_front(); progress = true; } @@ -337,7 +336,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 +352,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 +376,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 +387,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 +398,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/package_eval.cpp b/src/test/fuzz/package_eval.cpp index c201118bce..652c7a7609 100644 --- a/src/test/fuzz/package_eval.cpp +++ b/src/test/fuzz/package_eval.cpp @@ -6,7 +6,7 @@ #include <node/context.h> #include <node/mempool_args.h> #include <node/miner.h> -#include <policy/v3_policy.h> +#include <policy/truc_policy.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -15,7 +15,9 @@ #include <test/util/script.h> #include <test/util/setup_common.h> #include <test/util/txmempool.h> +#include <util/check.h> #include <util/rbf.h> +#include <util/translation.h> #include <validation.h> #include <validationinterface.h> @@ -107,7 +109,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chains SetMockTime(time); } -CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node) +std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node) { // Take the default options for tests... CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)}; @@ -126,8 +128,13 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte mempool_opts.check_ratio = 1; mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool(); + bilingual_str error; // ...and construct a CTxMemPool from it - return CTxMemPool{mempool_opts}; + auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)}; + // ... ignore the error since it might be beneficial to fuzz even when the + // mempool size is unreasonably small + Assert(error.empty() || error.original.starts_with("-maxmempool must be at least ")); + return mempool; } FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool) @@ -149,8 +156,8 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool) auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints); node.validation_signals->RegisterSharedValidationInterface(outpoints_updater); - CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)}; - MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_); + auto tx_pool_{MakeMempool(fuzzed_data_provider, node)}; + MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get()); chainstate.SetMempool(&tx_pool); @@ -173,7 +180,7 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool) // Create transaction to add to the mempool const CTransactionRef tx = [&] { CMutableTransaction tx_mut; - tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? 3 : CTransaction::CURRENT_VERSION; + tx_mut.version = fuzzed_data_provider.ConsumeBool() ? TRUC_VERSION : CTransaction::CURRENT_VERSION; tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>(); // Last tx will sweep all outpoints in package const auto num_in = last_tx ? package_outpoints.size() : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, mempool_outpoints.size()); @@ -218,7 +225,7 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool) tx_mut.vin.emplace_back(); } - // Make a p2pk output to make sigops adjusted vsize to violate v3, potentially, which is never spent + // Make a p2pk output to make sigops adjusted vsize to violate TRUC rules, potentially, which is never spent if (last_tx && amount_in > 1000 && fuzzed_data_provider.ConsumeBool()) { tx_mut.vout.emplace_back(1000, CScript() << std::vector<unsigned char>(33, 0x02) << OP_CHECKSIG); // Don't add any other outputs. @@ -307,13 +314,13 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool) // just use result_package.m_state here. This makes the expect_valid check meaningless, but // we can still verify that the contents of m_tx_results are consistent with m_state. const bool expect_valid{result_package.m_state.IsValid()}; - Assert(!CheckPackageMempoolAcceptResult(txs, result_package, expect_valid, nullptr)); + Assert(!CheckPackageMempoolAcceptResult(txs, result_package, expect_valid, &tx_pool)); } else { // This is empty if it fails early checks, or "full" if transactions are looked at deeper Assert(result_package.m_tx_results.size() == txs.size() || result_package.m_tx_results.empty()); } - CheckMempoolV3Invariants(tx_pool); + CheckMempoolTRUCInvariants(tx_pool); } node.validation_signals->UnregisterSharedValidationInterface(outpoints_updater); 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/partially_downloaded_block.cpp b/src/test/fuzz/partially_downloaded_block.cpp index 2bf47930f4..77952cab9e 100644 --- a/src/test/fuzz/partially_downloaded_block.cpp +++ b/src/test/fuzz/partially_downloaded_block.cpp @@ -10,6 +10,8 @@ #include <test/util/setup_common.h> #include <test/util/txmempool.h> #include <txmempool.h> +#include <util/check.h> +#include <util/translation.h> #include <cstddef> #include <cstdint> @@ -50,9 +52,11 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb) return; } - CBlockHeaderAndShortTxIDs cmpctblock{*block}; + CBlockHeaderAndShortTxIDs cmpctblock{*block, fuzzed_data_provider.ConsumeIntegral<uint64_t>()}; - CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)}; + bilingual_str error; + CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error}; + Assert(error.empty()); PartiallyDownloadedBlock pdb{&pool}; // Set of available transactions (mempool or extra_txn) diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index a4e1947b9f..2942740395 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -85,9 +85,18 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator) }); (void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>()); EstimationResult result; - (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS), fuzzed_data_provider.ConsumeBool() ? &result : nullptr); + auto conf_target = fuzzed_data_provider.ConsumeIntegral<int>(); + auto success_threshold = fuzzed_data_provider.ConsumeFloatingPoint<double>(); + auto horizon = fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS); + auto* result_ptr = fuzzed_data_provider.ConsumeBool() ? &result : nullptr; + (void)block_policy_estimator.estimateRawFee(conf_target, success_threshold, horizon, result_ptr); + FeeCalculation fee_calculation; - (void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool()); + conf_target = fuzzed_data_provider.ConsumeIntegral<int>(); + auto* fee_calc_ptr = fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr; + auto conservative = fuzzed_data_provider.ConsumeBool(); + (void)block_policy_estimator.estimateSmartFee(conf_target, fee_calc_ptr, conservative); + (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS)); } { diff --git a/src/test/fuzz/poolresource.cpp b/src/test/fuzz/poolresource.cpp index f764d9f8db..dd8d5b07e5 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(std::ranges::equal(entry.span, expect)); } void Deallocate(const Entry& entry) diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp index 05cdb740e4..dba999ce4f 100644 --- a/src/test/fuzz/pow.cpp +++ b/src/test/fuzz/pow.cpp @@ -80,7 +80,7 @@ FUZZ_TARGET(pow, .init = initialize_pow) { const std::optional<uint256> hash = ConsumeDeserializable<uint256>(fuzzed_data_provider); if (hash) { - (void)CheckProofOfWork(*hash, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), consensus_params); + (void)CheckProofOfWorkImpl(*hash, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), consensus_params); } } } diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp index 9cea32e304..fffa099391 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]); } @@ -212,15 +210,20 @@ FUZZ_TARGET(prevector) LIMITED_WHILE(prov.remaining_bytes(), 3000) { switch (prov.ConsumeIntegralInRange<int>(0, 13 + 3 * (test.size() > 0))) { - case 0: - test.insert(prov.ConsumeIntegralInRange<size_t>(0, test.size()), prov.ConsumeIntegral<int>()); - break; + case 0: { + auto position = prov.ConsumeIntegralInRange<size_t>(0, test.size()); + auto value = prov.ConsumeIntegral<int>(); + test.insert(position, value); + } break; case 1: test.resize(std::max(0, std::min(30, (int)test.size() + prov.ConsumeIntegralInRange<int>(0, 4) - 2))); break; - case 2: - test.insert(prov.ConsumeIntegralInRange<size_t>(0, test.size()), 1 + prov.ConsumeBool(), prov.ConsumeIntegral<int>()); - break; + case 2: { + auto position = prov.ConsumeIntegralInRange<size_t>(0, test.size()); + auto count = 1 + prov.ConsumeBool(); + auto value = prov.ConsumeIntegral<int>(); + test.insert(position, count, value); + } break; case 3: { int del = prov.ConsumeIntegralInRange<int>(0, test.size()); int beg = prov.ConsumeIntegralInRange<int>(0, test.size() - del); @@ -257,9 +260,11 @@ FUZZ_TARGET(prevector) case 9: test.clear(); break; - case 10: - test.assign(prov.ConsumeIntegralInRange<size_t>(0, 32767), prov.ConsumeIntegral<int>()); - break; + case 10: { + auto n = prov.ConsumeIntegralInRange<size_t>(0, 32767); + auto value = prov.ConsumeIntegral<int>(); + test.assign(n, value); + } break; case 11: test.swap(); break; @@ -269,9 +274,11 @@ FUZZ_TARGET(prevector) case 13: test.move(); break; - case 14: - test.update(prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1), prov.ConsumeIntegral<int>()); - break; + case 14: { + auto pos = prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1); + auto value = prov.ConsumeIntegral<int>(); + test.update(pos, value); + } break; case 15: test.erase(prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1)); break; 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/rbf.cpp b/src/test/fuzz/rbf.cpp index 64785948f6..eb981352ec 100644 --- a/src/test/fuzz/rbf.cpp +++ b/src/test/fuzz/rbf.cpp @@ -13,6 +13,8 @@ #include <test/util/setup_common.h> #include <test/util/txmempool.h> #include <txmempool.h> +#include <util/check.h> +#include <util/translation.h> #include <cstdint> #include <optional> @@ -56,7 +58,9 @@ FUZZ_TARGET(rbf, .init = initialize_rbf) return; } - CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)}; + bilingual_str error; + CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error}; + Assert(error.empty()); LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS) { @@ -87,10 +91,14 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); SetMockTime(ConsumeTime(fuzzed_data_provider)); - std::optional<CMutableTransaction> child = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS); - if (!child) return; + // "Real" virtual size is not important for this test since ConsumeTxMemPoolEntry generates its own virtual size values + // so we construct small transactions for performance reasons. Child simply needs an input for later to perhaps connect to parent. + CMutableTransaction child; + child.vin.resize(1); - CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)}; + bilingual_str error; + CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error}; + Assert(error.empty()); // Add a bunch of parent-child pairs to the mempool, and remember them. std::vector<CTransaction> mempool_txs; @@ -107,15 +115,13 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf) LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS) { // Make sure txns only have one input, and that a unique input is given to avoid circular references - std::optional<CMutableTransaction> parent = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS); - if (!parent) { - return; - } + CMutableTransaction parent; assert(iter <= g_outpoints.size()); - parent->vin.resize(1); - parent->vin[0].prevout = g_outpoints[iter++]; + parent.vin.resize(1); + parent.vin[0].prevout = g_outpoints[iter++]; + parent.vout.emplace_back(0, CScript()); - mempool_txs.emplace_back(*parent); + mempool_txs.emplace_back(parent); const auto parent_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()); running_vsize_total += parent_entry.GetTxSize(); if (running_vsize_total > std::numeric_limits<int32_t>::max()) { @@ -124,10 +130,10 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf) break; } pool.addUnchecked(parent_entry); - if (fuzzed_data_provider.ConsumeBool() && !child->vin.empty()) { - child->vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0}; + if (fuzzed_data_provider.ConsumeBool()) { + child.vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0}; } - mempool_txs.emplace_back(*child); + mempool_txs.emplace_back(child); const auto child_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()); running_vsize_total += child_entry.GetTxSize(); if (running_vsize_total > std::numeric_limits<int32_t>::max()) { diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index 2325bf0941..4db37ab7b7 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -36,9 +36,12 @@ #include <vector> enum class ChainType; +using util::Join; +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} { } @@ -140,6 +143,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{ "getnetworkhashps", "getnetworkinfo", "getnodeaddresses", + "getorphantxs", "getpeerinfo", "getprioritisedtransactions", "getrawaddrman", 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_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp index 511b581f60..5a8b599df6 100644 --- a/src/test/fuzz/script_assets_test_minimizer.cpp +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -17,6 +17,8 @@ #include <string> #include <vector> +using util::SplitString; + // This fuzz "test" can be used to minimize test cases for script_assets_test in // src/test/script_tests.cpp. While it written as a fuzz test, and can be used as such, // fuzzing the inputs is unlikely to construct useful test cases. diff --git a/src/test/fuzz/script_format.cpp b/src/test/fuzz/script_format.cpp index 10150dcd7f..e26c42ae38 100644 --- a/src/test/fuzz/script_format.cpp +++ b/src/test/fuzz/script_format.cpp @@ -30,5 +30,7 @@ FUZZ_TARGET(script_format, .init = initialize_script_format) (void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool()); UniValue o1(UniValue::VOBJ); - ScriptToUniv(script, /*out=*/o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool(), /*include_address=*/fuzzed_data_provider.ConsumeBool()); + auto include_hex = fuzzed_data_provider.ConsumeBool(); + auto include_address = fuzzed_data_provider.ConsumeBool(); + ScriptToUniv(script, /*out=*/o1, include_hex, include_address); } diff --git a/src/test/fuzz/script_interpreter.cpp b/src/test/fuzz/script_interpreter.cpp index 5e76443abe..9e3ad02b2e 100644 --- a/src/test/fuzz/script_interpreter.cpp +++ b/src/test/fuzz/script_interpreter.cpp @@ -25,12 +25,18 @@ FUZZ_TARGET(script_interpreter) const CTransaction tx_to{*mtx}; const unsigned int in = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); if (in < tx_to.vin.size()) { - (void)SignatureHash(script_code, tx_to, in, fuzzed_data_provider.ConsumeIntegral<int>(), ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}), nullptr); + auto n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>(); + auto amount = ConsumeMoney(fuzzed_data_provider); + auto sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}); + (void)SignatureHash(script_code, tx_to, in, n_hash_type, amount, sigversion, nullptr); const std::optional<CMutableTransaction> mtx_precomputed = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS); if (mtx_precomputed) { const CTransaction tx_precomputed{*mtx_precomputed}; const PrecomputedTransactionData precomputed_transaction_data{tx_precomputed}; - (void)SignatureHash(script_code, tx_to, in, fuzzed_data_provider.ConsumeIntegral<int>(), ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}), &precomputed_transaction_data); + n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>(); + amount = ConsumeMoney(fuzzed_data_provider); + sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}); + (void)SignatureHash(script_code, tx_to, in, n_hash_type, amount, sigversion, &precomputed_transaction_data); } } } diff --git a/src/test/fuzz/spanparsing.cpp b/src/test/fuzz/script_parsing.cpp index b8996632bc..d29a6ea90c 100644 --- a/src/test/fuzz/spanparsing.cpp +++ b/src/test/fuzz/script_parsing.cpp @@ -2,11 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <script/parsing.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> -#include <util/spanparsing.h> +#include <util/string.h> -FUZZ_TARGET(spanparsing) +using util::Split; + +FUZZ_TARGET(script_parsing) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const size_t query_size = fuzzed_data_provider.ConsumeIntegral<size_t>(); @@ -15,16 +18,16 @@ FUZZ_TARGET(spanparsing) const Span<const char> const_span{span_str}; Span<const char> mut_span = const_span; - (void)spanparsing::Const(query, mut_span); + (void)script::Const(query, mut_span); mut_span = const_span; - (void)spanparsing::Func(query, mut_span); + (void)script::Func(query, mut_span); mut_span = const_span; - (void)spanparsing::Expr(mut_span); + (void)script::Expr(mut_span); if (!query.empty()) { mut_span = const_span; - (void)spanparsing::Split(mut_span, query.front()); + (void)Split(mut_span, query.front()); } } 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/script_sign.cpp b/src/test/fuzz/script_sign.cpp index 4695bc611b..9fa5e0b7d8 100644 --- a/src/test/fuzz/script_sign.cpp +++ b/src/test/fuzz/script_sign.cpp @@ -13,6 +13,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/util/transaction_utils.h> #include <util/chaintype.h> #include <util/translation.h> @@ -111,7 +112,10 @@ FUZZ_TARGET(script_sign, .init = initialize_script_sign) } if (n_in < script_tx_to.vin.size()) { SignatureData empty; - (void)SignSignature(provider, ConsumeScript(fuzzed_data_provider), script_tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>(), empty); + auto from_pub_key = ConsumeScript(fuzzed_data_provider); + auto amount = ConsumeMoney(fuzzed_data_provider); + auto n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>(); + (void)SignSignature(provider, from_pub_key, script_tx_to, n_in, amount, n_hash_type, empty); MutableTransactionSignatureCreator signature_creator{tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>()}; std::vector<unsigned char> vch_sig; CKeyID address; @@ -122,7 +126,9 @@ FUZZ_TARGET(script_sign, .init = initialize_script_sign) } else { address = CKeyID{ConsumeUInt160(fuzzed_data_provider)}; } - (void)signature_creator.CreateSig(provider, vch_sig, address, ConsumeScript(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0})); + auto script_code = ConsumeScript(fuzzed_data_provider); + auto sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}); + (void)signature_creator.CreateSig(provider, vch_sig, address, script_code, sigversion); } std::map<COutPoint, Coin> coins{ConsumeCoins(fuzzed_data_provider)}; std::map<int, bilingual_str> input_errors; diff --git a/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp index 0435626356..9f84ac9713 100644 --- a/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp +++ b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp @@ -17,7 +17,7 @@ int ec_seckey_export_der(const secp256k1_context* ctx, unsigned char* seckey, si FUZZ_TARGET(secp256k1_ec_seckey_import_export_der) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_NONE); { std::vector<uint8_t> out32(32); (void)ec_seckey_import_der(secp256k1_context_sign, out32.data(), ConsumeFixedLengthByteVector(fuzzed_data_provider, CKey::SIZE).data(), CKey::SIZE); diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp index af81fcb593..17d1787586 100644 --- a/src/test/fuzz/socks5.cpp +++ b/src/test/fuzz/socks5.cpp @@ -41,8 +41,8 @@ FUZZ_TARGET(socks5, .init = initialize_socks5) FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider); // This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within // a few seconds of fuzzing. - (void)Socks5(fuzzed_data_provider.ConsumeRandomLengthString(512), - fuzzed_data_provider.ConsumeIntegral<uint16_t>(), - fuzzed_data_provider.ConsumeBool() ? &proxy_credentials : nullptr, - fuzzed_sock); + auto str_dest = fuzzed_data_provider.ConsumeRandomLengthString(512); + auto port = fuzzed_data_provider.ConsumeIntegral<uint16_t>(); + auto* auth = fuzzed_data_provider.ConsumeBool() ? &proxy_credentials : nullptr; + (void)Socks5(str_dest, port, auth, fuzzed_sock); } diff --git a/src/test/fuzz/span.cpp b/src/test/fuzz/span.cpp index 8f753948df..cd436d582f 100644 --- a/src/test/fuzz/span.cpp +++ b/src/test/fuzz/span.cpp @@ -30,10 +30,4 @@ FUZZ_TARGET(span) (void)span.subspan(idx, span.size() - idx); (void)span[idx]; } - - std::string another_str = fuzzed_data_provider.ConsumeBytesAsString(32); - const Span<const char> another_span{another_str}; - assert((span <= another_span) != (span > another_span)); - assert((span == another_span) != (span != another_span)); - assert((span >= another_span) != (span < another_span)); } diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index 631da13803..443d7241b5 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -1,10 +1,11 @@ -// 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. #include <blockfilter.h> #include <clientversion.h> #include <common/args.h> +#include <common/messages.h> #include <common/settings.h> #include <common/system.h> #include <common/url.h> @@ -21,8 +22,6 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> -#include <util/error.h> -#include <util/fees.h> #include <util/strencodings.h> #include <util/string.h> #include <util/translation.h> @@ -37,6 +36,16 @@ enum class FeeEstimateMode; +using common::AmountErrMsg; +using common::AmountHighWarn; +using common::FeeModeFromString; +using common::ResolveErrMsg; +using util::ContainsNoNUL; +using util::Join; +using util::RemovePrefix; +using util::SplitString; +using util::TrimString; + FUZZ_TARGET(string) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); @@ -92,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/system.cpp b/src/test/fuzz/system.cpp index 73ae89b52a..2ab5b7ed39 100644 --- a/src/test/fuzz/system.cpp +++ b/src/test/fuzz/system.cpp @@ -44,23 +44,31 @@ FUZZ_TARGET(system, .init = initialize_system) args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16)); }, [&] { - args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16); + auto str_value = fuzzed_data_provider.ConsumeRandomLengthString(16); + args_manager.SoftSetArg(str_arg, str_value); }, [&] { - args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16); + auto str_value = fuzzed_data_provider.ConsumeRandomLengthString(16); + args_manager.ForceSetArg(str_arg, str_value); }, [&] { - args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool()); + auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16); + auto f_value = fuzzed_data_provider.ConsumeBool(); + args_manager.SoftSetBoolArg(str_arg, f_value); }, [&] { - const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN}); + const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::CLI_COMMANDS, OptionsCategory::IPC, OptionsCategory::HIDDEN}); // Avoid hitting: // common/args.cpp:563: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16)); if (args_manager.GetArgFlags(argument_name) != std::nullopt) { return; } - args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND, options_category); + auto help = fuzzed_data_provider.ConsumeRandomLengthString(16); + auto flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND; + args_manager.AddArg(argument_name, help, flags, options_category); }, [&] { // Avoid hitting: diff --git a/src/test/fuzz/timeoffsets.cpp b/src/test/fuzz/timeoffsets.cpp index 019337a94a..dfa4dd705d 100644 --- a/src/test/fuzz/timeoffsets.cpp +++ b/src/test/fuzz/timeoffsets.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <node/timeoffsets.h> +#include <node/warnings.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/util/setup_common.h> @@ -19,7 +20,8 @@ void initialize_timeoffsets() FUZZ_TARGET(timeoffsets, .init = initialize_timeoffsets) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - TimeOffsets offsets{}; + node::Warnings warnings{}; + TimeOffsets offsets{warnings}; LIMITED_WHILE(fuzzed_data_provider.remaining_bytes() > 0, 4'000) { (void)offsets.Median(); offsets.Add(std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<std::chrono::seconds::rep>()}); diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index 9f0aedf29b..64861311db 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -6,7 +6,7 @@ #include <node/context.h> #include <node/mempool_args.h> #include <node/miner.h> -#include <policy/v3_policy.h> +#include <policy/truc_policy.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -15,12 +15,15 @@ #include <test/util/script.h> #include <test/util/setup_common.h> #include <test/util/txmempool.h> +#include <util/check.h> #include <util/rbf.h> +#include <util/translation.h> #include <validation.h> #include <validationinterface.h> using node::BlockAssembler; using node::NodeContext; +using util::ToString; namespace { @@ -116,7 +119,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chains SetMockTime(time); } -CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node) +std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node) { // Take the default options for tests... CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)}; @@ -126,7 +129,12 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool(); // ...and construct a CTxMemPool from it - return CTxMemPool{mempool_opts}; + bilingual_str error; + auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)}; + // ... ignore the error since it might be beneficial to fuzz even when the + // mempool size is unreasonably small + Assert(error.empty() || error.original.starts_with("-maxmempool must be at least ")); + return mempool; } void CheckATMPInvariants(const MempoolAcceptResult& res, bool txid_in_mempool, bool wtxid_in_mempool) @@ -198,8 +206,8 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool) constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN}; SetMempoolConstraints(*node.args, fuzzed_data_provider); - CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)}; - MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_); + auto tx_pool_{MakeMempool(fuzzed_data_provider, node)}; + MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get()); chainstate.SetMempool(&tx_pool); @@ -226,7 +234,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool) // Create transaction to add to the mempool const CTransactionRef tx = [&] { CMutableTransaction tx_mut; - tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? 3 : CTransaction::CURRENT_VERSION; + tx_mut.version = fuzzed_data_provider.ConsumeBool() ? TRUC_VERSION : CTransaction::CURRENT_VERSION; tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>(); const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size()); const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size() * 2); @@ -312,7 +320,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool) if (accepted) { Assert(added.size() == 1); // For now, no package acceptance Assert(tx == *added.begin()); - CheckMempoolV3Invariants(tx_pool); + CheckMempoolTRUCInvariants(tx_pool); } else { // Do not consider rejected transaction removed removed.erase(tx); @@ -376,8 +384,8 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool) } SetMempoolConstraints(*node.args, fuzzed_data_provider); - CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)}; - MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_); + auto tx_pool_{MakeMempool(fuzzed_data_provider, node)}; + MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get()); chainstate.SetMempool(&tx_pool); @@ -405,7 +413,7 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool) const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID; if (accepted) { txids.push_back(tx->GetHash()); - CheckMempoolV3Invariants(tx_pool); + CheckMempoolTRUCInvariants(tx_pool); } } Finish(fuzzed_data_provider, tx_pool, chainstate); 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 259b00fcae..425b9559a7 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -43,9 +43,9 @@ CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, { CMutableTransaction tx_mut; const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool(); - tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? + tx_mut.version = fuzzed_data_provider.ConsumeBool() ? CTransaction::CURRENT_VERSION : - fuzzed_data_provider.ConsumeIntegral<int32_t>(); + fuzzed_data_provider.ConsumeIntegral<uint32_t>(); tx_mut.nLockTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_in); const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_out); @@ -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/CMakeLists.txt b/src/test/fuzz/util/CMakeLists.txt new file mode 100644 index 0000000000..f73a1a83c2 --- /dev/null +++ b/src/test/fuzz/util/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_library(test_fuzz STATIC EXCLUDE_FROM_ALL + descriptor.cpp + mempool.cpp + net.cpp + ../fuzz.cpp + ../util.cpp +) + +target_link_libraries(test_fuzz + PRIVATE + core_interface + test_util + bitcoin_node + Boost::headers +) + +if(NOT FUZZ_BINARY_LINKS_WITHOUT_MAIN_FUNCTION) + target_compile_definitions(test_fuzz PRIVATE PROVIDE_FUZZ_MAIN_FUNCTION) +endif() 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 5e7aae670e..b02c4edbad 100644 --- a/src/test/fuzz/util/net.cpp +++ b/src/test/fuzz/util/net.cpp @@ -182,6 +182,12 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const EWOULDBLOCK, }; assert(buf != nullptr || len == 0); + + // Do the latency before any of the "return" statements. + if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { + std::this_thread::sleep_for(std::chrono::milliseconds{2}); + } + if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; if (r == -1) { @@ -189,47 +195,41 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const } return r; } - std::vector<uint8_t> random_bytes; - bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; - if (m_peek_data.has_value()) { - // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. - random_bytes = m_peek_data.value(); + + size_t copied_so_far{0}; + + if (!m_peek_data.empty()) { + // `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`. + const size_t copy_len{std::min(len, m_peek_data.size())}; + std::memcpy(buf, m_peek_data.data(), copy_len); + copied_so_far += copy_len; if ((flags & MSG_PEEK) == 0) { - m_peek_data.reset(); + m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len); } - pad_to_len_bytes = false; - } else if ((flags & MSG_PEEK) != 0) { - // New call with `MSG_PEEK`. - random_bytes = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len); - if (!random_bytes.empty()) { - m_peek_data = random_bytes; - pad_to_len_bytes = false; - } - } else { - random_bytes = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len); } - if (random_bytes.empty()) { - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); - } - return r; + + if (copied_so_far == len) { + return copied_so_far; } - // `random_bytes` might exceed the size of `buf` if e.g. Recv is called with - // len=N and MSG_PEEK first and afterwards called with len=M (M < N) and - // without MSG_PEEK. - size_t recv_len{std::min(random_bytes.size(), len)}; - std::memcpy(buf, random_bytes.data(), recv_len); - if (pad_to_len_bytes) { - if (len > random_bytes.size()) { - std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); - } - return len; + + auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far); + if (new_data.empty()) return copied_so_far; + + std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size()); + copied_so_far += new_data.size(); + + if ((flags & MSG_PEEK) != 0) { + m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end()); } - if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { - std::this_thread::sleep_for(std::chrono::milliseconds{2}); + + if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) { + return copied_so_far; } - return recv_len; + + // Pad to len bytes. + std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far); + + return len; } int FuzzedSock::Connect(const sockaddr*, socklen_t) const @@ -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; @@ -414,10 +414,10 @@ bool FuzzedSock::IsConnected(std::string& errmsg) const void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept { - connman.Handshake(node, - /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(), - /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), - /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), - /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()), - /*relay_txs=*/fuzzed_data_provider.ConsumeBool()); + auto successfully_connected = fuzzed_data_provider.ConsumeBool(); + auto remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS); + auto local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS); + auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()); + auto relay_txs = fuzzed_data_provider.ConsumeBool(); + connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs); } diff --git a/src/test/fuzz/util/net.h b/src/test/fuzz/util/net.h index ed02680676..1a5902329e 100644 --- a/src/test/fuzz/util/net.h +++ b/src/test/fuzz/util/net.h @@ -43,7 +43,7 @@ class FuzzedSock : public Sock * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next * `Recv()` call we must return the same data, thus we remember it here. */ - mutable std::optional<std::vector<uint8_t>> m_peek_data; + mutable std::vector<uint8_t> m_peek_data; /** * Whether to pretend that the socket is select(2)-able. This is randomly set in the diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index 8c9c67a91c..1241bba8be 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -1,39 +1,79 @@ -// Copyright (c) 2021-2022 The Bitcoin Core developers +// Copyright (c) 2021-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 <chain.h> #include <chainparams.h> +#include <coins.h> +#include <consensus/consensus.h> #include <consensus/validation.h> +#include <node/blockstorage.h> #include <node/utxo_snapshot.h> +#include <primitives/block.h> +#include <primitives/transaction.h> +#include <serialize.h> +#include <span.h> +#include <streams.h> +#include <sync.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> #include <test/util/mining.h> #include <test/util/setup_common.h> -#include <util/chaintype.h> +#include <uint256.h> +#include <util/check.h> #include <util/fs.h> +#include <util/result.h> #include <validation.h> -#include <validationinterface.h> + +#include <cstdint> +#include <functional> +#include <ios> +#include <memory> +#include <optional> +#include <vector> using node::SnapshotMetadata; namespace { const std::vector<std::shared_ptr<CBlock>>* g_chain; +TestingSetup* g_setup; +template <bool INVALID> void initialize_chain() { const auto params{CreateChainParams(ArgsManager{}, ChainType::REGTEST)}; static const auto chain{CreateBlockChain(2 * COINBASE_MATURITY, *params)}; g_chain = &chain; + static const auto setup{ + MakeNoLogFileContext<TestingSetup>(ChainType::REGTEST, + TestOpts{ + .setup_net = false, + .setup_validation_interface = false, + .min_validation_cache = true, + }), + }; + if constexpr (INVALID) { + auto& chainman{*setup->m_node.chainman}; + for (const auto& block : chain) { + BlockValidationState dummy; + bool processed{chainman.ProcessNewBlockHeaders({{block->GetBlockHeader()}}, true, dummy)}; + Assert(processed); + const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))}; + Assert(index); + } + } + g_setup = setup.get(); } -FUZZ_TARGET(utxo_snapshot, .init = initialize_chain) +template <bool INVALID> +void utxo_snapshot_fuzz(FuzzBufferType buffer) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - std::unique_ptr<const TestingSetup> setup{MakeNoLogFileContext<const TestingSetup>()}; - const auto& node = setup->m_node; - auto& chainman{*node.chainman}; + auto& setup{*g_setup}; + bool dirty_chainman{false}; // Re-use the global chainman, but reset it when it is dirty + auto& chainman{*setup.m_node.chainman}; const auto snapshot_path = gArgs.GetDataDirNet() / "fuzzed_snapshot.dat"; @@ -41,29 +81,68 @@ 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 { + 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++; + } + } + if constexpr (INVALID) { + // Append an invalid coin to ensure invalidity. This error will be + // detected late in PopulateAndValidateSnapshot, and allows the + // INVALID fuzz target to reach more potential code coverage. + const auto& coinbase{g_chain->back()->vtx.back()}; + outfile << coinbase->GetHash(); + WriteCompactSize(outfile, 1); // number of coins for the hash + WriteCompactSize(outfile, 999); // index of coin + outfile << Coin{coinbase->vout[0], /*nHeightIn=*/999, /*fCoinBaseIn=*/0}; + } } 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; } catch (const std::ios_base::failure&) { return false; } - return chainman.ActivateSnapshot(infile, metadata, /*in_memory=*/true); + return !!chainman.ActivateSnapshot(infile, metadata, /*in_memory=*/true); }}; if (fuzzed_data_provider.ConsumeBool()) { - for (const auto& block : *g_chain) { - BlockValidationState dummy; - bool processed{chainman.ProcessNewBlockHeaders({*block}, true, dummy)}; - Assert(processed); - const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))}; - Assert(index); + // Consume the bool, but skip the code for the INVALID fuzz target + if constexpr (!INVALID) { + for (const auto& block : *g_chain) { + BlockValidationState dummy; + bool processed{chainman.ProcessNewBlockHeaders({{block->GetBlockHeader()}}, true, dummy)}; + Assert(processed); + const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))}; + Assert(index); + } + dirty_chainman = true; } } @@ -73,21 +152,49 @@ 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); + dirty_chainman = true; } else { Assert(!chainman.SnapshotBlockhash()); Assert(!chainman.ActiveChainstate().m_from_snapshot_blockhash); } // Snapshot should refuse to load a second time regardless of validity Assert(!ActivateFuzzedSnapshot()); + if constexpr (INVALID) { + // Activating the snapshot, or any other action that makes the chainman + // "dirty" can and must not happen for the INVALID fuzz target + Assert(!dirty_chainman); + } + if (dirty_chainman) { + setup.m_node.chainman.reset(); + setup.m_make_chainman(); + setup.LoadVerifyActivateChainstate(); + } } + +// There are two fuzz targets: +// +// The target 'utxo_snapshot', which allows valid snapshots, but is slow, +// because it has to reset the chainstate manager on almost all fuzz inputs. +// Otherwise, a dirty header tree or dirty chainstate could leak from one fuzz +// input execution into the next, which makes execution non-deterministic. +// +// The target 'utxo_snapshot_invalid', which is fast and does not require any +// expensive state to be reset. +FUZZ_TARGET(utxo_snapshot /*valid*/, .init = initialize_chain<false>) { utxo_snapshot_fuzz<false>(buffer); } +FUZZ_TARGET(utxo_snapshot_invalid, .init = initialize_chain<true>) { utxo_snapshot_fuzz<true>(buffer); } + } // namespace 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/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp index 00678742c9..c70d9ddf1e 100644 --- a/src/test/fuzz/validation_load_mempool.cpp +++ b/src/test/fuzz/validation_load_mempool.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <kernel/mempool_persist.h> +#include <node/mempool_persist.h> #include <node/mempool_args.h> #include <node/mempool_persist_args.h> @@ -13,14 +13,16 @@ #include <test/util/setup_common.h> #include <test/util/txmempool.h> #include <txmempool.h> +#include <util/check.h> #include <util/time.h> +#include <util/translation.h> #include <validation.h> #include <cstdint> #include <vector> -using kernel::DumpMempool; -using kernel::LoadMempool; +using node::DumpMempool; +using node::LoadMempool; using node::MempoolPath; @@ -40,7 +42,9 @@ FUZZ_TARGET(validation_load_mempool, .init = initialize_validation_load_mempool) SetMockTime(ConsumeTime(fuzzed_data_provider)); FuzzedFileProvider fuzzed_file_provider{fuzzed_data_provider}; - CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)}; + bilingual_str error; + CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error}; + Assert(error.empty()); auto& chainstate{static_cast<DummyChainState&>(g_setup->m_node.chainman->ActiveChainstate())}; chainstate.SetMempool(&pool); diff --git a/src/test/fuzz/vecdeque.cpp b/src/test/fuzz/vecdeque.cpp new file mode 100644 index 0000000000..3bb858ee8a --- /dev/null +++ b/src/test/fuzz/vecdeque.cpp @@ -0,0 +1,491 @@ +// 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 <random.h> +#include <span.h> +#include <test/fuzz/util.h> +#include <util/vecdeque.h> + +#include <deque> +#include <stdint.h> + +namespace { + +/** The maximum number of simultaneous buffers kept by the test. */ +static constexpr size_t MAX_BUFFERS{3}; +/** How many elements are kept in a buffer at most. */ +static constexpr size_t MAX_BUFFER_SIZE{48}; +/** How many operations are performed at most on the buffers in one test. */ +static constexpr size_t MAX_OPERATIONS{1024}; + +/** Perform a simulation fuzz test on VecDeque type T. + * + * T must be constructible from a uint64_t seed, comparable to other T, copyable, and movable. + */ +template<typename T, bool CheckNoneLeft> +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. + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>() ^ rng_tweak); + + // Real circular buffers. + std::vector<VecDeque<T>> real; + real.reserve(MAX_BUFFERS); + // Simulated circular buffers. + std::vector<std::deque<T>> sim; + sim.reserve(MAX_BUFFERS); + // Temporary object of type T. + std::optional<T> tmp; + + // Compare a real and a simulated buffer. + auto compare_fn = [](const VecDeque<T>& r, const std::deque<T>& s) { + assert(r.size() == s.size()); + assert(r.empty() == s.empty()); + assert(r.capacity() >= r.size()); + if (s.size() == 0) return; + assert(r.front() == s.front()); + assert(r.back() == s.back()); + for (size_t i = 0; i < s.size(); ++i) { + assert(r[i] == s[i]); + } + }; + + LIMITED_WHILE(provider.remaining_bytes(), MAX_OPERATIONS) { + int command = provider.ConsumeIntegral<uint8_t>() % 64; + unsigned idx = real.empty() ? 0 : provider.ConsumeIntegralInRange<unsigned>(0, real.size() - 1); + const size_t num_buffers = sim.size(); + // Pick one operation based on value of command. Not all operations are always applicable. + // Loop through the applicable ones until command reaches 0 (which avoids the need to + // compute the number of applicable commands ahead of time). + const bool non_empty{num_buffers != 0}; + const bool non_full{num_buffers < MAX_BUFFERS}; + const bool partially_full{non_empty && non_full}; + const bool multiple_exist{num_buffers > 1}; + const bool existing_buffer_non_full{non_empty && sim[idx].size() < MAX_BUFFER_SIZE}; + const bool existing_buffer_non_empty{non_empty && !sim[idx].empty()}; + assert(non_full || non_empty); + while (true) { + if (non_full && command-- == 0) { + /* Default construct. */ + real.emplace_back(); + sim.emplace_back(); + break; + } + if (non_empty && command-- == 0) { + /* resize() */ + compare_fn(real[idx], sim[idx]); + size_t new_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE); + real[idx].resize(new_size); + sim[idx].resize(new_size); + assert(real[idx].size() == new_size); + break; + } + if (non_empty && command-- == 0) { + /* clear() */ + compare_fn(real[idx], sim[idx]); + real[idx].clear(); + sim[idx].clear(); + assert(real[idx].empty()); + break; + } + if (non_empty && command-- == 0) { + /* Copy construct default. */ + compare_fn(real[idx], sim[idx]); + real[idx] = VecDeque<T>(); + sim[idx].clear(); + assert(real[idx].size() == 0); + break; + } + if (non_empty && command-- == 0) { + /* Destruct. */ + compare_fn(real.back(), sim.back()); + real.pop_back(); + sim.pop_back(); + break; + } + if (partially_full && command-- == 0) { + /* Copy construct. */ + real.emplace_back(real[idx]); + sim.emplace_back(sim[idx]); + break; + } + if (partially_full && command-- == 0) { + /* Move construct. */ + VecDeque<T> copy(real[idx]); + real.emplace_back(std::move(copy)); + sim.emplace_back(sim[idx]); + break; + } + if (multiple_exist && command-- == 0) { + /* swap() */ + swap(real[idx], real[(idx + 1) % num_buffers]); + swap(sim[idx], sim[(idx + 1) % num_buffers]); + break; + } + if (multiple_exist && command-- == 0) { + /* Copy assign. */ + compare_fn(real[idx], sim[idx]); + real[idx] = real[(idx + 1) % num_buffers]; + sim[idx] = sim[(idx + 1) % num_buffers]; + break; + } + if (multiple_exist && command-- == 0) { + /* Move assign. */ + VecDeque<T> copy(real[(idx + 1) % num_buffers]); + compare_fn(real[idx], sim[idx]); + real[idx] = std::move(copy); + sim[idx] = sim[(idx + 1) % num_buffers]; + break; + } + if (non_empty && command-- == 0) { + /* Self swap() */ + swap(real[idx], real[idx]); + break; + } + if (non_empty && command-- == 0) { + /* Self-copy assign. */ + real[idx] = real[idx]; + break; + } + if (non_empty && command-- == 0) { + /* Self-move assign. */ + // Do not use std::move(real[idx]) here: -Wself-move correctly warns about that. + real[idx] = static_cast<VecDeque<T>&&>(real[idx]); + break; + } + if (non_empty && command-- == 0) { + /* reserve() */ + size_t res_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE); + size_t old_cap = real[idx].capacity(); + size_t old_size = real[idx].size(); + real[idx].reserve(res_size); + assert(real[idx].size() == old_size); + assert(real[idx].capacity() == std::max(old_cap, res_size)); + break; + } + if (non_empty && command-- == 0) { + /* shrink_to_fit() */ + size_t old_size = real[idx].size(); + real[idx].shrink_to_fit(); + assert(real[idx].size() == old_size); + assert(real[idx].capacity() == old_size); + break; + } + if (existing_buffer_non_full && command-- == 0) { + /* push_back() (copying) */ + tmp = T(rng.rand64()); + size_t old_size = real[idx].size(); + size_t old_cap = real[idx].capacity(); + real[idx].push_back(*tmp); + sim[idx].push_back(*tmp); + assert(real[idx].size() == old_size + 1); + if (old_cap > old_size) { + assert(real[idx].capacity() == old_cap); + } else { + assert(real[idx].capacity() > old_cap); + assert(real[idx].capacity() <= 2 * (old_cap + 1)); + } + break; + } + if (existing_buffer_non_full && command-- == 0) { + /* push_back() (moving) */ + tmp = T(rng.rand64()); + size_t old_size = real[idx].size(); + size_t old_cap = real[idx].capacity(); + sim[idx].push_back(*tmp); + real[idx].push_back(std::move(*tmp)); + assert(real[idx].size() == old_size + 1); + if (old_cap > old_size) { + assert(real[idx].capacity() == old_cap); + } else { + assert(real[idx].capacity() > old_cap); + assert(real[idx].capacity() <= 2 * (old_cap + 1)); + } + break; + } + if (existing_buffer_non_full && command-- == 0) { + /* emplace_back() */ + uint64_t seed{rng.rand64()}; + size_t old_size = real[idx].size(); + size_t old_cap = real[idx].capacity(); + sim[idx].emplace_back(seed); + real[idx].emplace_back(seed); + assert(real[idx].size() == old_size + 1); + if (old_cap > old_size) { + assert(real[idx].capacity() == old_cap); + } else { + assert(real[idx].capacity() > old_cap); + assert(real[idx].capacity() <= 2 * (old_cap + 1)); + } + break; + } + if (existing_buffer_non_full && command-- == 0) { + /* push_front() (copying) */ + tmp = T(rng.rand64()); + size_t old_size = real[idx].size(); + size_t old_cap = real[idx].capacity(); + real[idx].push_front(*tmp); + sim[idx].push_front(*tmp); + assert(real[idx].size() == old_size + 1); + if (old_cap > old_size) { + assert(real[idx].capacity() == old_cap); + } else { + assert(real[idx].capacity() > old_cap); + assert(real[idx].capacity() <= 2 * (old_cap + 1)); + } + break; + } + if (existing_buffer_non_full && command-- == 0) { + /* push_front() (moving) */ + tmp = T(rng.rand64()); + size_t old_size = real[idx].size(); + size_t old_cap = real[idx].capacity(); + sim[idx].push_front(*tmp); + real[idx].push_front(std::move(*tmp)); + assert(real[idx].size() == old_size + 1); + if (old_cap > old_size) { + assert(real[idx].capacity() == old_cap); + } else { + assert(real[idx].capacity() > old_cap); + assert(real[idx].capacity() <= 2 * (old_cap + 1)); + } + break; + } + if (existing_buffer_non_full && command-- == 0) { + /* emplace_front() */ + uint64_t seed{rng.rand64()}; + size_t old_size = real[idx].size(); + size_t old_cap = real[idx].capacity(); + sim[idx].emplace_front(seed); + real[idx].emplace_front(seed); + assert(real[idx].size() == old_size + 1); + if (old_cap > old_size) { + assert(real[idx].capacity() == old_cap); + } else { + assert(real[idx].capacity() > old_cap); + assert(real[idx].capacity() <= 2 * (old_cap + 1)); + } + break; + } + if (existing_buffer_non_empty && command-- == 0) { + /* front() [modifying] */ + tmp = T(rng.rand64()); + size_t old_size = real[idx].size(); + assert(sim[idx].front() == real[idx].front()); + sim[idx].front() = *tmp; + real[idx].front() = std::move(*tmp); + assert(real[idx].size() == old_size); + break; + } + if (existing_buffer_non_empty && command-- == 0) { + /* back() [modifying] */ + tmp = T(rng.rand64()); + size_t old_size = real[idx].size(); + assert(sim[idx].back() == real[idx].back()); + sim[idx].back() = *tmp; + real[idx].back() = *tmp; + assert(real[idx].size() == old_size); + break; + } + if (existing_buffer_non_empty && command-- == 0) { + /* operator[] [modifying] */ + 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]); + sim[idx][pos] = *tmp; + real[idx][pos] = std::move(*tmp); + assert(real[idx].size() == old_size); + break; + } + if (existing_buffer_non_empty && command-- == 0) { + /* pop_front() */ + assert(sim[idx].front() == real[idx].front()); + size_t old_size = real[idx].size(); + sim[idx].pop_front(); + real[idx].pop_front(); + assert(real[idx].size() == old_size - 1); + break; + } + if (existing_buffer_non_empty && command-- == 0) { + /* pop_back() */ + assert(sim[idx].back() == real[idx].back()); + size_t old_size = real[idx].size(); + sim[idx].pop_back(); + real[idx].pop_back(); + assert(real[idx].size() == old_size - 1); + break; + } + } + } + + /* Fully compare the final state. */ + for (unsigned i = 0; i < sim.size(); ++i) { + // Make sure const getters work. + const VecDeque<T>& realbuf = real[i]; + const std::deque<T>& simbuf = sim[i]; + compare_fn(realbuf, simbuf); + for (unsigned j = 0; j < sim.size(); ++j) { + assert((realbuf == real[j]) == (simbuf == sim[j])); + assert(((realbuf <=> real[j]) >= 0) == (simbuf >= sim[j])); + assert(((realbuf <=> real[j]) <= 0) == (simbuf <= sim[j])); + } + // Clear out the buffers so we can check below that no objects exist anymore. + sim[i].clear(); + real[i].clear(); + } + + if constexpr (CheckNoneLeft) { + tmp = std::nullopt; + T::CheckNoneExist(); + } +} + +/** Data structure with built-in tracking of all existing objects. */ +template<size_t Size> +class TrackedObj +{ + static_assert(Size > 0); + + /* Data type for map that actually stores the object data. + * + * The key is a pointer to the TrackedObj, the value is the uint64_t it was initialized with. + * Default-constructed and moved-from objects hold an std::nullopt. + */ + using track_map_type = std::map<const TrackedObj<Size>*, std::optional<uint64_t>>; + +private: + + /** Actual map. */ + static inline track_map_type g_tracker; + + /** Iterators into the tracker map for this object. + * + * This is an array of size Size, all holding the same value, to give the object configurable + * size. The value is g_tracker.end() if this object is not fully initialized. */ + typename track_map_type::iterator m_track_entry[Size]; + + void Check() const + { + auto it = g_tracker.find(this); + for (size_t i = 0; i < Size; ++i) { + assert(m_track_entry[i] == it); + } + } + + /** Create entry for this object in g_tracker and populate m_track_entry. */ + void Register() + { + auto [it, inserted] = g_tracker.emplace(this, std::nullopt); + assert(inserted); + for (size_t i = 0; i < Size; ++i) { + m_track_entry[i] = it; + } + } + + void Deregister() + { + Check(); + assert(m_track_entry[0] != g_tracker.end()); + g_tracker.erase(m_track_entry[0]); + for (size_t i = 0; i < Size; ++i) { + m_track_entry[i] = g_tracker.end(); + } + } + + /** Get value corresponding to this object in g_tracker. */ + std::optional<uint64_t>& Deref() + { + Check(); + assert(m_track_entry[0] != g_tracker.end()); + return m_track_entry[0]->second; + } + + /** Get value corresponding to this object in g_tracker. */ + const std::optional<uint64_t>& Deref() const + { + Check(); + assert(m_track_entry[0] != g_tracker.end()); + return m_track_entry[0]->second; + } + +public: + ~TrackedObj() { Deregister(); } + TrackedObj() { Register(); } + + TrackedObj(uint64_t value) + { + Register(); + Deref() = value; + } + + TrackedObj(const TrackedObj& other) + { + Register(); + Deref() = other.Deref(); + } + + TrackedObj(TrackedObj&& other) + { + Register(); + Deref() = other.Deref(); + other.Deref() = std::nullopt; + } + + TrackedObj& operator=(const TrackedObj& other) + { + if (this == &other) return *this; + Deref() = other.Deref(); + return *this; + } + + TrackedObj& operator=(TrackedObj&& other) + { + if (this == &other) return *this; + Deref() = other.Deref(); + other.Deref() = std::nullopt; + return *this; + } + + friend bool operator==(const TrackedObj& a, const TrackedObj& b) + { + return a.Deref() == b.Deref(); + } + + friend std::strong_ordering operator<=>(const TrackedObj& a, const TrackedObj& b) + { + // Libc++ 15 & 16 do not support std::optional<T>::operator<=> yet. See + // https://reviews.llvm.org/D146392. + if (!a.Deref().has_value() || !b.Deref().has_value()) { + return a.Deref().has_value() <=> b.Deref().has_value(); + } + return *a.Deref() <=> *b.Deref(); + } + + static void CheckNoneExist() + { + assert(g_tracker.empty()); + } +}; + +} // namespace + +FUZZ_TARGET(vecdeque) +{ + // Run the test with simple uints (which satisfy all the trivial properties). + static_assert(std::is_trivially_copyable_v<uint32_t>); + static_assert(std::is_trivially_destructible_v<uint64_t>); + TestType<uint8_t, false>(buffer, 1); + TestType<uint16_t, false>(buffer, 2); + TestType<uint32_t, false>(buffer, 3); + TestType<uint64_t, false>(buffer, 4); + + // Run the test with TrackedObjs (which do not). + static_assert(!std::is_trivially_copyable_v<TrackedObj<3>>); + static_assert(!std::is_trivially_destructible_v<TrackedObj<17>>); + TestType<TrackedObj<1>, true>(buffer, 5); + TestType<TrackedObj<3>, true>(buffer, 6); + TestType<TrackedObj<17>, true>(buffer, 7); +} diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index c73b675388..8734735fd5 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -16,6 +16,8 @@ #include <boost/test/unit_test.hpp> +using util::SplitString; + BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup) void ResetArgs(ArgsManager& local_args, const std::string& strArg) diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index f0d2b9ed72..f56f7232c3 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -11,7 +11,7 @@ #include <boost/test/unit_test.hpp> -BOOST_AUTO_TEST_SUITE(hash_tests) +BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(murmurhash3) { @@ -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); @@ -124,9 +124,9 @@ BOOST_AUTO_TEST_CASE(siphash) HashWriter ss{}; CMutableTransaction tx; - // Note these tests were originally written with tx.nVersion=1 + // Note these tests were originally written with tx.version=1 // and the test would be affected by default tx version bumps if not fixed. - tx.nVersion = 1; + tx.version = 1; ss << TX_WITH_WITNESS(tx); BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL); @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(siphash) for (int i = 0; i < 16; ++i) { uint64_t k1 = ctx.rand64(); uint64_t k2 = ctx.rand64(); - uint256 x = InsecureRand256(); + uint256 x = m_rng.rand256(); uint32_t n = ctx.rand32(); uint8_t nb[4]; WriteLE32(nb, n); diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp index d7249d88f4..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} { @@ -39,15 +39,14 @@ public: private: const BCLog::Level m_prev_log_level; - const std::function<std::unique_ptr<Sock>(const sa_family_t&)> m_create_sock_orig; + const decltype(CreateSock) m_create_sock_orig; }; BOOST_FIXTURE_TEST_SUITE(i2p_tests, EnvTestingSetup) BOOST_AUTO_TEST_CASE(unlimited_recv) { - // Mock CreateSock() to create MockSock. - CreateSock = [](const sa_family_t&) { + CreateSock = [](int, int, int) { return std::make_unique<StaticContentsSock>(std::string(i2p::sam::MAX_MSG_SIZE + 1, 'a')); }; @@ -69,7 +68,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv) BOOST_AUTO_TEST_CASE(listen_ok_accept_fail) { size_t num_sockets{0}; - CreateSock = [&num_sockets](const sa_family_t&) { + CreateSock = [&num_sockets](int, int, int) { // clang-format off ++num_sockets; // First socket is the control socket for creating the session. @@ -133,9 +132,7 @@ BOOST_AUTO_TEST_CASE(listen_ok_accept_fail) BOOST_AUTO_TEST_CASE(damaged_private_key) { - const auto CreateSockOrig = CreateSock; - - CreateSock = [](const sa_family_t&) { + CreateSock = [](int, int, int) { return std::make_unique<StaticContentsSock>("HELLO REPLY RESULT=OK VERSION=3.1\n" "SESSION STATUS RESULT=OK DESTINATION=\n"); }; @@ -172,8 +169,6 @@ BOOST_AUTO_TEST_CASE(damaged_private_key) BOOST_CHECK(!session.Connect(CService{}, conn, proxy_error)); } } - - CreateSock = CreateSockOrig; } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/ipc_test.capnp b/src/test/ipc_test.capnp index 55a3dc2683..46cd08b94a 100644 --- a/src/test/ipc_test.capnp +++ b/src/test/ipc_test.capnp @@ -9,10 +9,15 @@ $Cxx.namespace("gen"); using Proxy = import "/mp/proxy.capnp"; $Proxy.include("test/ipc_test.h"); -$Proxy.includeTypes("ipc/capnp/common-types.h"); +$Proxy.includeTypes("test/ipc_test_types.h"); + +using Mining = import "../ipc/capnp/mining.capnp"; interface FooInterface $Proxy.wrap("FooImplementation") { add @0 (a :Int32, b :Int32) -> (result :Int32); passOutPoint @1 (arg :Data) -> (result :Data); passUniValue @2 (arg :Text) -> (result :Text); + passTransaction @3 (arg :Data) -> (result :Data); + passVectorChar @4 (arg :Data) -> (result :Data); + passBlockState @5 (arg :Mining.BlockValidationState) -> (result :Mining.BlockValidationState); } diff --git a/src/test/ipc_test.cpp b/src/test/ipc_test.cpp index ce4edaceb0..af37434980 100644 --- a/src/test/ipc_test.cpp +++ b/src/test/ipc_test.cpp @@ -2,19 +2,47 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <interfaces/init.h> +#include <ipc/capnp/protocol.h> +#include <ipc/process.h> +#include <ipc/protocol.h> #include <logging.h> #include <mp/proxy-types.h> #include <test/ipc_test.capnp.h> #include <test/ipc_test.capnp.proxy.h> #include <test/ipc_test.h> +#include <tinyformat.h> +#include <validation.h> #include <future> +#include <thread> #include <kj/common.h> #include <kj/memory.h> #include <kj/test.h> +#include <stdexcept> #include <boost/test/unit_test.hpp> +//! Remote init class. +class TestInit : public interfaces::Init +{ +public: + std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); } +}; + +//! Generate a temporary path with temp_directory_path and mkstemp +static std::string TempPath(std::string_view pattern) +{ + std::string temp{fs::PathToString(fs::path{fs::temp_directory_path()} / fs::PathFromString(std::string{pattern}))}; + temp.push_back('\0'); + int fd{mkstemp(temp.data())}; + BOOST_CHECK_GE(fd, 0); + BOOST_CHECK_EQUAL(close(fd), 0); + temp.resize(temp.size() - 1); + fs::remove(fs::PathFromString(temp)); + return temp; +} + //! Unit test that tests execution of IPC calls without actually creating a //! separate process. This test is primarily intended to verify behavior of type //! conversion code that converts C++ objects to Cap'n Proto messages and vice @@ -23,18 +51,18 @@ //! The test creates a thread which creates a FooImplementation object (defined //! in ipc_test.h) and a two-way pipe accepting IPC requests which call methods //! on the object through FooInterface (defined in ipc_test.capnp). -void IpcTest() +void IpcPipeTest() { // Setup: create FooImplemention object and listen for FooInterface requests std::promise<std::unique_ptr<mp::ProxyClient<gen::FooInterface>>> foo_promise; std::function<void()> disconnect_client; std::thread thread([&]() { - mp::EventLoop loop("IpcTest", [](bool raise, const std::string& log) { LogPrintf("LOG%i: %s\n", raise, log); }); + mp::EventLoop loop("IpcPipeTest", [](bool raise, const std::string& log) { LogPrintf("LOG%i: %s\n", raise, log); }); auto pipe = loop.m_io_context.provider->newTwoWayPipe(); auto connection_client = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[0])); auto foo_client = std::make_unique<mp::ProxyClient<gen::FooInterface>>( - connection_client->m_rpc_system.bootstrap(mp::ServerVatId().vat_id).castAs<gen::FooInterface>(), + connection_client->m_rpc_system->bootstrap(mp::ServerVatId().vat_id).castAs<gen::FooInterface>(), connection_client.get(), /* destroy_connection= */ false); foo_promise.set_value(std::move(foo_client)); disconnect_client = [&] { loop.sync([&] { connection_client.reset(); }); }; @@ -61,7 +89,107 @@ void IpcTest() UniValue uni2{foo->passUniValue(uni1)}; BOOST_CHECK_EQUAL(uni1.write(), uni2.write()); + CMutableTransaction mtx; + mtx.version = 2; + mtx.nLockTime = 3; + mtx.vin.emplace_back(txout1); + mtx.vout.emplace_back(COIN, CScript()); + CTransactionRef tx1{MakeTransactionRef(mtx)}; + CTransactionRef tx2{foo->passTransaction(tx1)}; + BOOST_CHECK(*Assert(tx1) == *Assert(tx2)); + + std::vector<char> vec1{'H', 'e', 'l', 'l', 'o'}; + std::vector<char> vec2{foo->passVectorChar(vec1)}; + BOOST_CHECK_EQUAL(std::string_view(vec1.begin(), vec1.end()), std::string_view(vec2.begin(), vec2.end())); + + BlockValidationState bs1; + bs1.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, "reject reason", "debug message"); + BlockValidationState bs2{foo->passBlockState(bs1)}; + BOOST_CHECK_EQUAL(bs1.IsValid(), bs2.IsValid()); + BOOST_CHECK_EQUAL(bs1.IsError(), bs2.IsError()); + BOOST_CHECK_EQUAL(bs1.IsInvalid(), bs2.IsInvalid()); + BOOST_CHECK_EQUAL(static_cast<int>(bs1.GetResult()), static_cast<int>(bs2.GetResult())); + BOOST_CHECK_EQUAL(bs1.GetRejectReason(), bs2.GetRejectReason()); + BOOST_CHECK_EQUAL(bs1.GetDebugMessage(), bs2.GetDebugMessage()); + + BlockValidationState bs3; + BlockValidationState bs4{foo->passBlockState(bs3)}; + BOOST_CHECK_EQUAL(bs3.IsValid(), bs4.IsValid()); + BOOST_CHECK_EQUAL(bs3.IsError(), bs4.IsError()); + BOOST_CHECK_EQUAL(bs3.IsInvalid(), bs4.IsInvalid()); + BOOST_CHECK_EQUAL(static_cast<int>(bs3.GetResult()), static_cast<int>(bs4.GetResult())); + BOOST_CHECK_EQUAL(bs3.GetRejectReason(), bs4.GetRejectReason()); + BOOST_CHECK_EQUAL(bs3.GetDebugMessage(), bs4.GetDebugMessage()); + // Test cleanup: disconnect pipe and join thread disconnect_client(); thread.join(); } + +//! Test ipc::Protocol connect() and serve() methods connecting over a socketpair. +void IpcSocketPairTest() +{ + int fds[2]; + BOOST_CHECK_EQUAL(socketpair(AF_UNIX, SOCK_STREAM, 0, fds), 0); + std::unique_ptr<interfaces::Init> init{std::make_unique<TestInit>()}; + std::unique_ptr<ipc::Protocol> protocol{ipc::capnp::MakeCapnpProtocol()}; + std::promise<void> promise; + std::thread thread([&]() { + protocol->serve(fds[0], "test-serve", *init, [&] { promise.set_value(); }); + }); + promise.get_future().wait(); + std::unique_ptr<interfaces::Init> remote_init{protocol->connect(fds[1], "test-connect")}; + std::unique_ptr<interfaces::Echo> remote_echo{remote_init->makeEcho()}; + BOOST_CHECK_EQUAL(remote_echo->echo("echo test"), "echo test"); + remote_echo.reset(); + remote_init.reset(); + thread.join(); +} + +//! Test ipc::Process bind() and connect() methods connecting over a unix socket. +void IpcSocketTest(const fs::path& datadir) +{ + std::unique_ptr<interfaces::Init> init{std::make_unique<TestInit>()}; + std::unique_ptr<ipc::Protocol> protocol{ipc::capnp::MakeCapnpProtocol()}; + std::unique_ptr<ipc::Process> process{ipc::MakeProcess()}; + + std::string invalid_bind{"invalid:"}; + BOOST_CHECK_THROW(process->bind(datadir, "test_bitcoin", invalid_bind), std::invalid_argument); + BOOST_CHECK_THROW(process->connect(datadir, "test_bitcoin", invalid_bind), std::invalid_argument); + + auto bind_and_listen{[&](const std::string& bind_address) { + std::string address{bind_address}; + int serve_fd = process->bind(datadir, "test_bitcoin", address); + BOOST_CHECK_GE(serve_fd, 0); + BOOST_CHECK_EQUAL(address, bind_address); + protocol->listen(serve_fd, "test-serve", *init); + }}; + + auto connect_and_test{[&](const std::string& connect_address) { + std::string address{connect_address}; + int connect_fd{process->connect(datadir, "test_bitcoin", address)}; + BOOST_CHECK_EQUAL(address, connect_address); + std::unique_ptr<interfaces::Init> remote_init{protocol->connect(connect_fd, "test-connect")}; + std::unique_ptr<interfaces::Echo> remote_echo{remote_init->makeEcho()}; + BOOST_CHECK_EQUAL(remote_echo->echo("echo test"), "echo test"); + }}; + + // Need to specify explicit socket addresses outside the data directory, because the data + // directory path is so long that the default socket address and any other + // addresses in the data directory would fail with errors like: + // Address 'unix' path '"/tmp/test_common_Bitcoin Core/ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff/test_bitcoin.sock"' exceeded maximum socket path length + std::vector<std::string> addresses{ + strprintf("unix:%s", TempPath("bitcoin_sock0_XXXXXX")), + strprintf("unix:%s", TempPath("bitcoin_sock1_XXXXXX")), + }; + + // Bind and listen on multiple addresses + for (const auto& address : addresses) { + bind_and_listen(address); + } + + // Connect and test each address multiple times. + for (int i : {0, 1, 0, 0, 1}) { + connect_and_test(addresses[i]); + } +} diff --git a/src/test/ipc_test.h b/src/test/ipc_test.h index bcfcc2125c..2d215a20f1 100644 --- a/src/test/ipc_test.h +++ b/src/test/ipc_test.h @@ -7,6 +7,8 @@ #include <primitives/transaction.h> #include <univalue.h> +#include <util/fs.h> +#include <validation.h> class FooImplementation { @@ -14,8 +16,13 @@ public: int add(int a, int b) { return a + b; } COutPoint passOutPoint(COutPoint o) { return o; } UniValue passUniValue(UniValue v) { return v; } + CTransactionRef passTransaction(CTransactionRef t) { return t; } + std::vector<char> passVectorChar(std::vector<char> v) { return v; } + BlockValidationState passBlockState(BlockValidationState s) { return s; } }; -void IpcTest(); +void IpcPipeTest(); +void IpcSocketPairTest(); +void IpcSocketTest(const fs::path& datadir); #endif // BITCOIN_TEST_IPC_TEST_H diff --git a/src/test/ipc_test_types.h b/src/test/ipc_test_types.h new file mode 100644 index 0000000000..b1d4829aa7 --- /dev/null +++ b/src/test/ipc_test_types.h @@ -0,0 +1,12 @@ +// 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. + +#ifndef BITCOIN_TEST_IPC_TEST_TYPES_H +#define BITCOIN_TEST_IPC_TEST_TYPES_H + +#include <ipc/capnp/common-types.h> +#include <ipc/capnp/mining-types.h> +#include <test/ipc_test.capnp.h> + +#endif // BITCOIN_TEST_IPC_TEST_TYPES_H diff --git a/src/test/ipc_tests.cpp b/src/test/ipc_tests.cpp index 6e144b0f41..35a4f61117 100644 --- a/src/test/ipc_tests.cpp +++ b/src/test/ipc_tests.cpp @@ -2,12 +2,41 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <ipc/process.h> #include <test/ipc_test.h> + +#include <test/util/setup_common.h> #include <boost/test/unit_test.hpp> -BOOST_AUTO_TEST_SUITE(ipc_tests) +BOOST_FIXTURE_TEST_SUITE(ipc_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(ipc_tests) { - IpcTest(); + IpcPipeTest(); + IpcSocketPairTest(); + IpcSocketTest(m_args.GetDataDirNet()); } + +// Test address parsing. +BOOST_AUTO_TEST_CASE(parse_address_test) +{ + std::unique_ptr<ipc::Process> process{ipc::MakeProcess()}; + fs::path datadir{"/var/empty/notexist"}; + auto check_notexist{[](const std::system_error& e) { return e.code() == std::errc::no_such_file_or_directory; }}; + auto check_address{[&](std::string address, std::string expect_address, std::string expect_error) { + if (expect_error.empty()) { + BOOST_CHECK_EXCEPTION(process->connect(datadir, "test_bitcoin", address), std::system_error, check_notexist); + } else { + BOOST_CHECK_EXCEPTION(process->connect(datadir, "test_bitcoin", address), std::invalid_argument, HasReason(expect_error)); + } + BOOST_CHECK_EQUAL(address, expect_address); + }}; + check_address("unix", "unix:/var/empty/notexist/test_bitcoin.sock", ""); + check_address("unix:", "unix:/var/empty/notexist/test_bitcoin.sock", ""); + check_address("unix:path.sock", "unix:/var/empty/notexist/path.sock", ""); + check_address("unix:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.sock", + "unix:/var/empty/notexist/0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.sock", + "Unix address path \"/var/empty/notexist/0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.sock\" exceeded maximum socket path length"); + check_address("invalid", "invalid", "Unrecognized address 'invalid'"); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index 66b4e09ebf..4dd77edc16 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -10,12 +10,13 @@ #include <script/script.h> #include <test/util/json.h> #include <test/util/setup_common.h> +#include <univalue.h> #include <util/chaintype.h> #include <util/strencodings.h> #include <boost/test/unit_test.hpp> -#include <univalue.h> +#include <algorithm> BOOST_FIXTURE_TEST_SUITE(key_io_tests, BasicTestingSetup) @@ -46,7 +47,7 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse) privkey = DecodeSecret(exp_base58string); BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest); BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest); - BOOST_CHECK_MESSAGE(Span{privkey} == Span{exp_payload}, "key mismatch:" + strTest); + BOOST_CHECK_MESSAGE(std::ranges::equal(privkey, exp_payload), "key mismatch:" + strTest); // Private key must be invalid public key destination = DecodeDestination(exp_base58string); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 1ec6de78cb..90e04bed87 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> @@ -19,6 +20,9 @@ #include <boost/test/unit_test.hpp> +using namespace util::hex_literals; +using util::ToString; + static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"; static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"; static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"; @@ -140,19 +144,22 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(key1.Sign(hashMsg, detsig)); BOOST_CHECK(key1C.Sign(hashMsg, detsigc)); BOOST_CHECK(detsig == detsigc); - BOOST_CHECK(detsig == ParseHex("304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK_EQUAL(HexStr(detsig), "304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"); + BOOST_CHECK(key2.Sign(hashMsg, detsig)); BOOST_CHECK(key2C.Sign(hashMsg, detsigc)); BOOST_CHECK(detsig == detsigc); - BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); + BOOST_CHECK_EQUAL(HexStr(detsig), "3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"); + BOOST_CHECK(key1.SignCompact(hashMsg, detsig)); BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc)); - BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); - BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK_EQUAL(HexStr(detsig), "1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"); + BOOST_CHECK_EQUAL(HexStr(detsigc), "205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"); + BOOST_CHECK(key2.SignCompact(hashMsg, detsig)); BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc)); - BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); - BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); + BOOST_CHECK_EQUAL(HexStr(detsig), "1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"); + BOOST_CHECK_EQUAL(HexStr(detsigc), "2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"); } BOOST_AUTO_TEST_CASE(key_signature_tests) @@ -297,19 +304,32 @@ 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. for (int i = 0; i < 10; ++i) { uint256 merkle_root; - if (i) merkle_root = InsecureRand256(); + if (i) merkle_root = m_rng.rand256(); auto tweaked = pubkey.CreateTapTweak(i ? &merkle_root : nullptr); BOOST_CHECK(tweaked); XOnlyPubKey tweaked_key = tweaked->first; - aux256 = InsecureRand256(); + aux256 = m_rng.rand256(); 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)); } } } @@ -320,7 +340,7 @@ BOOST_AUTO_TEST_CASE(key_ellswift) CKey key = DecodeSecret(secret); BOOST_CHECK(key.IsValid()); - uint256 ent32 = InsecureRand256(); + uint256 ent32 = m_rng.rand256(); auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32})); CPubKey decoded_pubkey = ellswift.Decode(); @@ -336,11 +356,38 @@ BOOST_AUTO_TEST_CASE(key_ellswift) BOOST_AUTO_TEST_CASE(bip341_test_h) { - std::vector<unsigned char> G_uncompressed = ParseHex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"); + constexpr auto G_uncompressed{"0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"_hex}; HashWriter hw; - hw.write(MakeByteSpan(G_uncompressed)); + hw.write(G_uncompressed); XOnlyPubKey H{hw.GetSHA256()}; 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_NONE); + + CKey key; + key.MakeNewKey(true); + uint256 merkle_root = m_rng.rand256(); + + // 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/logging_tests.cpp b/src/test/logging_tests.cpp index 88e3ec94b7..77ec81e597 100644 --- a/src/test/logging_tests.cpp +++ b/src/test/logging_tests.cpp @@ -17,6 +17,9 @@ #include <boost/test/unit_test.hpp> +using util::SplitString; +using util::TrimString; + BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup) static void ResetLogger() @@ -80,15 +83,15 @@ BOOST_AUTO_TEST_CASE(logging_timer) BOOST_CHECK_EQUAL(micro_timer.LogMsg("msg").substr(0, result_prefix.size()), result_prefix); } -BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup) +BOOST_FIXTURE_TEST_CASE(logging_LogPrintStr, LogSetup) { LogInstance().m_log_sourcelocations = true; - LogPrintf_("fn1", "src1", 1, BCLog::LogFlags::NET, BCLog::Level::Debug, "foo1: %s\n", "bar1"); - LogPrintf_("fn2", "src2", 2, BCLog::LogFlags::NET, BCLog::Level::Info, "foo2: %s\n", "bar2"); - LogPrintf_("fn3", "src3", 3, BCLog::LogFlags::ALL, BCLog::Level::Debug, "foo3: %s\n", "bar3"); - LogPrintf_("fn4", "src4", 4, BCLog::LogFlags::ALL, BCLog::Level::Info, "foo4: %s\n", "bar4"); - LogPrintf_("fn5", "src5", 5, BCLog::LogFlags::NONE, BCLog::Level::Debug, "foo5: %s\n", "bar5"); - LogPrintf_("fn6", "src6", 6, BCLog::LogFlags::NONE, BCLog::Level::Info, "foo6: %s\n", "bar6"); + LogInstance().LogPrintStr("foo1: bar1", "fn1", "src1", 1, BCLog::LogFlags::NET, BCLog::Level::Debug); + LogInstance().LogPrintStr("foo2: bar2", "fn2", "src2", 2, BCLog::LogFlags::NET, BCLog::Level::Info); + LogInstance().LogPrintStr("foo3: bar3", "fn3", "src3", 3, BCLog::LogFlags::ALL, BCLog::Level::Debug); + LogInstance().LogPrintStr("foo4: bar4", "fn4", "src4", 4, BCLog::LogFlags::ALL, BCLog::Level::Info); + LogInstance().LogPrintStr("foo5: bar5", "fn5", "src5", 5, BCLog::LogFlags::NONE, BCLog::Level::Debug); + LogInstance().LogPrintStr("foo6: bar6", "fn6", "src6", 6, BCLog::LogFlags::NONE, BCLog::Level::Info); std::ifstream file{tmp_log_path}; std::vector<std::string> log_lines; for (std::string log; std::getline(file, log);) { @@ -108,13 +111,11 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup) BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacrosDeprecated, LogSetup) { LogPrintf("foo5: %s\n", "bar5"); - LogPrint(BCLog::NET, "foo6: %s\n", "bar6"); LogPrintLevel(BCLog::NET, BCLog::Level::Trace, "foo4: %s\n", "bar4"); // not logged LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "foo7: %s\n", "bar7"); LogPrintLevel(BCLog::NET, BCLog::Level::Info, "foo8: %s\n", "bar8"); LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "foo9: %s\n", "bar9"); LogPrintLevel(BCLog::NET, BCLog::Level::Error, "foo10: %s\n", "bar10"); - LogPrintfCategory(BCLog::VALIDATION, "foo11: %s\n", "bar11"); std::ifstream file{tmp_log_path}; std::vector<std::string> log_lines; for (std::string log; std::getline(file, log);) { @@ -122,23 +123,21 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacrosDeprecated, LogSetup) } std::vector<std::string> expected = { "foo5: bar5", - "[net] foo6: bar6", "[net] foo7: bar7", "[net:info] foo8: bar8", "[net:warning] foo9: bar9", "[net:error] foo10: bar10", - "[validation:info] foo11: bar11", }; BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end()); } BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros, LogSetup) { - LogTrace(BCLog::NET, "foo6: %s\n", "bar6"); // not logged - LogDebug(BCLog::NET, "foo7: %s\n", "bar7"); - LogInfo("foo8: %s\n", "bar8"); - LogWarning("foo9: %s\n", "bar9"); - LogError("foo10: %s\n", "bar10"); + LogTrace(BCLog::NET, "foo6: %s", "bar6"); // not logged + LogDebug(BCLog::NET, "foo7: %s", "bar7"); + LogInfo("foo8: %s", "bar8"); + LogWarning("foo9: %s", "bar9"); + LogError("foo10: %s", "bar10"); std::ifstream file{tmp_log_path}; std::vector<std::string> log_lines; for (std::string log; std::getline(file, log);) { @@ -168,7 +167,7 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros_CategoryName, LogSetup) std::vector<std::string> expected; for (const auto& [category, name] : expected_category_names) { - LogPrint(category, "foo: %s\n", "bar"); + LogDebug(category, "foo: %s\n", "bar"); std::string expected_log = "["; expected_log += name; expected_log += "] foo: bar"; diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 66f7be3c4e..2b1cf8595d 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -23,110 +23,6 @@ static uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vecto return hash; } -/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */ -static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector<uint256>* pbranch) { - if (pbranch) pbranch->clear(); - if (leaves.size() == 0) { - if (pmutated) *pmutated = false; - if (proot) *proot = uint256(); - return; - } - bool mutated = false; - // count is the number of leaves processed so far. - uint32_t count = 0; - // inner is an array of eagerly computed subtree hashes, indexed by tree - // level (0 being the leaves). - // For example, when count is 25 (11001 in binary), inner[4] is the hash of - // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to - // the last leaf. The other inner entries are undefined. - uint256 inner[32]; - // Which position in inner is a hash that depends on the matching leaf. - int matchlevel = -1; - // First process all leaves into 'inner' values. - while (count < leaves.size()) { - uint256 h = leaves[count]; - bool matchh = count == branchpos; - count++; - int level; - // For each of the lower bits in count that are 0, do 1 step. Each - // corresponds to an inner value that existed before processing the - // current leaf, and each needs a hash to combine it. - for (level = 0; !(count & ((uint32_t{1}) << level)); level++) { - if (pbranch) { - if (matchh) { - pbranch->push_back(inner[level]); - } else if (matchlevel == level) { - pbranch->push_back(h); - matchh = true; - } - } - mutated |= (inner[level] == h); - h = Hash(inner[level], h); - } - // Store the resulting hash at inner position level. - inner[level] = h; - if (matchh) { - matchlevel = level; - } - } - // Do a final 'sweep' over the rightmost branch of the tree to process - // odd levels, and reduce everything to a single top value. - // Level is the level (counted from the bottom) up to which we've sweeped. - int level = 0; - // As long as bit number level in count is zero, skip it. It means there - // is nothing left at this level. - while (!(count & ((uint32_t{1}) << level))) { - level++; - } - uint256 h = inner[level]; - bool matchh = matchlevel == level; - while (count != ((uint32_t{1}) << level)) { - // If we reach this point, h is an inner value that is not the top. - // We combine it with itself (Bitcoin's special rule for odd levels in - // the tree) to produce a higher level one. - if (pbranch && matchh) { - pbranch->push_back(h); - } - h = Hash(h, h); - // Increment count to the value it would have if two entries at this - // level had existed. - count += ((uint32_t{1}) << level); - level++; - // And propagate the result upwards accordingly. - while (!(count & ((uint32_t{1}) << level))) { - if (pbranch) { - if (matchh) { - pbranch->push_back(inner[level]); - } else if (matchlevel == level) { - pbranch->push_back(h); - matchh = true; - } - } - h = Hash(inner[level], h); - level++; - } - } - // Return result. - if (pmutated) *pmutated = mutated; - if (proot) *proot = h; -} - -static std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) { - std::vector<uint256> ret; - MerkleComputation(leaves, nullptr, nullptr, position, &ret); - return ret; -} - -static std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position) -{ - std::vector<uint256> leaves; - leaves.resize(block.vtx.size()); - for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s]->GetHash(); - } - return ComputeMerkleBranch(leaves, position); -} - // Older version of the merkle root computation code, for comparison. static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::vector<uint256>& vMerkleTree) { @@ -184,7 +80,7 @@ BOOST_AUTO_TEST_CASE(merkle_test) { for (int i = 0; i < 32; i++) { // Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes. - int ntx = (i <= 16) ? i : 17 + (InsecureRandRange(4000)); + int ntx = (i <= 16) ? i : 17 + (m_rng.randrange(4000)); // Try up to 3 mutations. for (int mutate = 0; mutate <= 3; mutate++) { int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first. @@ -237,7 +133,7 @@ BOOST_AUTO_TEST_CASE(merkle_test) // If ntx <= 16, try all branches. Otherwise, try 16 random ones. int mtx = loop; if (ntx > 16) { - mtx = InsecureRandRange(ntx); + mtx = m_rng.randrange(ntx); } std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx); std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); 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/miner_tests.cpp b/src/test/miner_tests.cpp index d50af4c175..6cf2757b2d 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -14,8 +14,10 @@ #include <test/util/txmempool.h> #include <txmempool.h> #include <uint256.h> +#include <util/check.h> #include <util/strencodings.h> #include <util/time.h> +#include <util/translation.h> #include <validation.h> #include <versionbits.h> @@ -25,6 +27,7 @@ #include <boost/test/unit_test.hpp> +using namespace util::hex_literals; using node::BlockAssembler; using node::CBlockTemplate; @@ -46,7 +49,9 @@ struct MinerTestingSetup : public TestingSetup { // pointer is not accessed, when the new one should be accessed // instead. m_node.mempool.reset(); - m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node)); + bilingual_str error; + m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node), error); + Assert(error.empty()); return *m_node.mempool; } BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool); @@ -363,7 +368,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) { CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); + next->phashBlock = new uint256(m_rng.rand256()); m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; @@ -375,7 +380,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) { CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); + next->phashBlock = new uint256(m_rng.rand256()); m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; @@ -421,7 +426,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: std::vector<int> prevheights; // relative height locked - tx.nVersion = 2; + tx.version = 2; tx.vin.resize(1); prevheights.resize(1); tx.vin[0].prevout.hash = txFirst[0]->GetHash(); // only 1 transaction @@ -603,7 +608,7 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { // Note that by default, these tests run with size accounting enabled. - CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; + CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG; std::unique_ptr<CBlockTemplate> pblocktemplate; CTxMemPool& tx_mempool{*m_node.mempool}; @@ -622,7 +627,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->nVersion = VERSIONBITS_TOP_BITS; pblock->nTime = m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1; CMutableTransaction txCoinbase(*pblock->vtx[0]); - txCoinbase.nVersion = 1; + txCoinbase.version = 1; txCoinbase.vin[0].scriptSig = CScript{} << (m_node.chainman->ActiveChain().Height() + 1) << bi.extranonce; txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this) txCoinbase.vout[0].scriptPubKey = CScript(); diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 7e39e9e4de..ba3507d49d 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <stdint.h> -#include <string> -#include <vector> - #include <test/util/random.h> #include <test/util/setup_common.h> #include <boost/test/unit_test.hpp> @@ -22,6 +18,13 @@ #include <script/script_error.h> #include <script/signingprovider.h> +#include <algorithm> +#include <cstdint> +#include <string> +#include <vector> + +using namespace util::hex_literals; + namespace { /** TestData groups various kinds of precomputed data necessary in this test. */ @@ -48,9 +51,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) { @@ -274,7 +277,7 @@ public: XOnlyPubKey pk{pubkey}; auto it = g_testdata->schnorr_signatures.find(pk); if (it == g_testdata->schnorr_signatures.end()) return false; - return sig == it->second; + return std::ranges::equal(sig, it->second); } bool CheckLockTime(const CScriptNum& locktime) const override { @@ -340,13 +343,14 @@ void SatisfactionToWitness(miniscript::MiniscriptContext ctx, CScriptWitness& wi witness.stack.push_back(*builder.GetSpendData().scripts.begin()->second.begin()); } +struct MiniScriptTest : BasicTestingSetup { /** Run random satisfaction tests. */ void TestSatisfy(const KeyConverter& converter, const std::string& testcase, const NodeRef& node) { auto script = node->ToScript(converter); auto challenges = FindChallenges(node); // Find all challenges in the generated miniscript. std::vector<Challenge> challist(challenges.begin(), challenges.end()); for (int iter = 0; iter < 3; ++iter) { - Shuffle(challist.begin(), challist.end(), g_insecure_rand_ctx); + std::shuffle(challist.begin(), challist.end(), m_rng); Satisfier satisfier(converter.MsContext()); TestSignatureChecker checker(satisfier); bool prev_mal_success = false, prev_nonmal_success = false; @@ -488,10 +492,11 @@ void Test(const std::string& ms, const std::string& hexscript, const std::string /*opslimit=*/-1, /*stacklimit=*/-1, /*max_wit_size=*/std::nullopt, /*max_tap_wit_size=*/std::nullopt, /*stack_exec=*/std::nullopt); } +}; // struct MiniScriptTest } // namespace -BOOST_FIXTURE_TEST_SUITE(miniscript_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(miniscript_tests, MiniScriptTest) BOOST_AUTO_TEST_CASE(fixed_tests) { @@ -593,11 +598,11 @@ BOOST_AUTO_TEST_CASE(fixed_tests) // - no pubkey before the CHECKSIG constexpr KeyConverter tap_converter{miniscript::MiniscriptContext::TAPSCRIPT}; constexpr KeyConverter wsh_converter{miniscript::MiniscriptContext::P2WSH}; - const auto no_pubkey{ParseHex("ac519c")}; + const auto no_pubkey{"ac519c"_hex_u8}; BOOST_CHECK(miniscript::FromScript({no_pubkey.begin(), no_pubkey.end()}, tap_converter) == nullptr); - const auto incomplete_multi_a{ParseHex("ba20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c")}; + const auto incomplete_multi_a{"ba20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c"_hex_u8}; BOOST_CHECK(miniscript::FromScript({incomplete_multi_a.begin(), incomplete_multi_a.end()}, tap_converter) == nullptr); - const auto incomplete_multi_a_2{ParseHex("ac2079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c")}; + const auto incomplete_multi_a_2{"ac2079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c"_hex_u8}; BOOST_CHECK(miniscript::FromScript({incomplete_multi_a_2.begin(), incomplete_multi_a_2.end()}, tap_converter) == nullptr); // Can use multi_a under Tapscript but not P2WSH. Test("and_v(v:multi_a(2,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a,025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),after(1231488000))", "?", "20d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85aac205601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7ccba529d0400046749b1", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 4, 2, {}, {}, 3); @@ -642,12 +647,12 @@ BOOST_AUTO_TEST_CASE(fixed_tests) // Misc unit tests // A Script with a non minimal push is invalid - std::vector<unsigned char> nonminpush = ParseHex("0000210232780000feff00ffffffffffff21ff005f00ae21ae00000000060602060406564c2102320000060900fe00005f00ae21ae00100000060606060606000000000000000000000000000000000000000000000000000000000000000000"); + constexpr auto nonminpush{"0000210232780000feff00ffffffffffff21ff005f00ae21ae00000000060602060406564c2102320000060900fe00005f00ae21ae00100000060606060606000000000000000000000000000000000000000000000000000000000000000000"_hex_u8}; const CScript nonminpush_script(nonminpush.begin(), nonminpush.end()); BOOST_CHECK(miniscript::FromScript(nonminpush_script, wsh_converter) == nullptr); BOOST_CHECK(miniscript::FromScript(nonminpush_script, tap_converter) == nullptr); // A non-minimal VERIFY (<key> CHECKSIG VERIFY 1) - std::vector<unsigned char> nonminverify = ParseHex("2103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7ac6951"); + constexpr auto nonminverify{"2103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7ac6951"_hex_u8}; const CScript nonminverify_script(nonminverify.begin(), nonminverify.end()); BOOST_CHECK(miniscript::FromScript(nonminverify_script, wsh_converter) == nullptr); BOOST_CHECK(miniscript::FromScript(nonminverify_script, tap_converter) == nullptr); @@ -699,6 +704,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/minisketch_tests.cpp b/src/test/minisketch_tests.cpp index 10506da783..3d2a835113 100644 --- a/src/test/minisketch_tests.cpp +++ b/src/test/minisketch_tests.cpp @@ -14,16 +14,16 @@ using node::MakeMinisketch32; -BOOST_AUTO_TEST_SUITE(minisketch_tests) +BOOST_FIXTURE_TEST_SUITE(minisketch_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(minisketch_test) { for (int i = 0; i < 100; ++i) { - uint32_t errors = 0 + InsecureRandRange(11); - uint32_t start_a = 1 + InsecureRandRange(1000000000); - uint32_t a_not_b = InsecureRandRange(errors + 1); + uint32_t errors = 0 + m_rng.randrange(11); + uint32_t start_a = 1 + m_rng.randrange(1000000000); + uint32_t a_not_b = m_rng.randrange(errors + 1); uint32_t b_not_a = errors - a_not_b; - uint32_t both = InsecureRandRange(10000); + uint32_t both = m_rng.randrange(10000); uint32_t end_a = start_a + a_not_b + both; uint32_t start_b = start_a + a_not_b; uint32_t end_b = start_b + both + b_not_a; diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 7a3e8e3a47..29a73d03d2 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -10,6 +10,7 @@ #include <script/sign.h> #include <script/signingprovider.h> #include <test/util/setup_common.h> +#include <test/util/transaction_utils.h> #include <tinyformat.h> #include <uint256.h> diff --git a/src/test/net_peer_connection_tests.cpp b/src/test/net_peer_connection_tests.cpp index 00bc1fdb6a..e60ce8b99d 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) @@ -43,20 +43,21 @@ static CService ip(uint32_t i) return CService{CNetAddr{s}, Params().GetDefaultPort()}; } +struct PeerTest : LogIPsTestingSetup { /** Create a peer and connect to it. If the optional `address` (IP/CJDNS only) isn't passed, a random address is created. */ -static void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, ConnmanTestMsg& connman, ConnectionType conn_type, bool onion_peer = false, std::optional<std::string> address = std::nullopt) +void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, ConnmanTestMsg& connman, ConnectionType conn_type, bool onion_peer = false, std::optional<std::string> address = std::nullopt) { CAddress addr{}; if (address.has_value()) { addr = CAddress{MaybeFlipIPv6toCJDNS(LookupNumeric(address.value(), Params().GetDefaultPort())), NODE_NONE}; } else if (onion_peer) { - auto tor_addr{g_insecure_rand_ctx.randbytes(ADDR_TORV3_SIZE)}; + auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)}; BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr))); } while (!addr.IsLocal() && !addr.IsRoutable()) { - addr = CAddress{ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE}; + addr = CAddress{ip(m_rng.randbits(32)), NODE_NONE}; } BOOST_REQUIRE(addr.IsValid()); @@ -80,11 +81,12 @@ static void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman connman.AddTestNode(node); } +}; // struct PeerTest -BOOST_AUTO_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection) +BOOST_FIXTURE_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection, PeerTest) { auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); - auto peerman = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {}); + auto peerman = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {}); NodeId id{0}; std::vector<CNode*> nodes; 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/net_tests.cpp b/src/test/net_tests.cpp index b9dff96610..4c72d03ab1 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -32,6 +32,8 @@ #include <string> using namespace std::literals; +using namespace util::hex_literals; +using util::ToString; BOOST_FIXTURE_TEST_SUITE(net_tests, RegTestingSetup) @@ -399,9 +401,9 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) const auto ser_params{CAddress::V2_NETWORK}; // Valid IPv4. - s << Span{ParseHex("01" // network type (IPv4) - "04" // address length - "01020304")}; // address + s << "01" // network type (IPv4) + "04" // address length + "01020304"_hex; // address s >> ser_params(addr); BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsIPv4()); @@ -410,35 +412,35 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_REQUIRE(s.empty()); // Invalid IPv4, valid length but address itself is shorter. - s << Span{ParseHex("01" // network type (IPv4) - "04" // address length - "0102")}; // address + s << "01" // network type (IPv4) + "04" // address length + "0102"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("end of data")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Invalid IPv4, with bogus length. - s << Span{ParseHex("01" // network type (IPv4) - "05" // address length - "01020304")}; // address + s << "01" // network type (IPv4) + "05" // address length + "01020304"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("BIP155 IPv4 address with length 5 (should be 4)")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Invalid IPv4, with extreme length. - s << Span{ParseHex("01" // network type (IPv4) - "fd0102" // address length (513 as CompactSize) - "01020304")}; // address + s << "01" // network type (IPv4) + "fd0102" // address length (513 as CompactSize) + "01020304"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("Address too long: 513 > 512")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Valid IPv6. - s << Span{ParseHex("02" // network type (IPv6) - "10" // address length - "0102030405060708090a0b0c0d0e0f10")}; // address + s << "02" // network type (IPv6) + "10" // address length + "0102030405060708090a0b0c0d0e0f10"_hex; // address s >> ser_params(addr); BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsIPv6()); @@ -447,11 +449,10 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_REQUIRE(s.empty()); // Valid IPv6, contains embedded "internal". - s << Span{ParseHex( - "02" // network type (IPv6) - "10" // address length - "fd6b88c08724ca978112ca1bbdcafac2")}; // address: 0xfd + sha256("bitcoin")[0:5] + - // sha256(name)[0:10] + s << "02" // network type (IPv6) + "10" // address length + "fd6b88c08724ca978112ca1bbdcafac2"_hex; // address: 0xfd + sha256("bitcoin")[0:5] + + // sha256(name)[0:10] s >> ser_params(addr); BOOST_CHECK(addr.IsInternal()); BOOST_CHECK(addr.IsAddrV1Compatible()); @@ -459,44 +460,43 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_REQUIRE(s.empty()); // Invalid IPv6, with bogus length. - s << Span{ParseHex("02" // network type (IPv6) - "04" // address length - "00")}; // address + s << "02" // network type (IPv6) + "04" // address length + "00"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("BIP155 IPv6 address with length 4 (should be 16)")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Invalid IPv6, contains embedded IPv4. - s << Span{ParseHex("02" // network type (IPv6) - "10" // address length - "00000000000000000000ffff01020304")}; // address + s << "02" // network type (IPv6) + "10" // address length + "00000000000000000000ffff01020304"_hex; // address s >> ser_params(addr); BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); // Invalid IPv6, contains embedded TORv2. - s << Span{ParseHex("02" // network type (IPv6) - "10" // address length - "fd87d87eeb430102030405060708090a")}; // address + s << "02" // network type (IPv6) + "10" // address length + "fd87d87eeb430102030405060708090a"_hex; // address s >> ser_params(addr); BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); // TORv2, no longer supported. - s << Span{ParseHex("03" // network type (TORv2) - "0a" // address length - "f1f2f3f4f5f6f7f8f9fa")}; // address + s << "03" // network type (TORv2) + "0a" // address length + "f1f2f3f4f5f6f7f8f9fa"_hex; // address s >> ser_params(addr); BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); // Valid TORv3. - s << Span{ParseHex("04" // network type (TORv3) - "20" // address length - "79bcc625184b05194975c28b66b66b04" // address - "69f7f6556fb1ac3189a79b40dda32f1f" - )}; + s << "04" // network type (TORv3) + "20" // address length + "79bcc625184b05194975c28b66b66b04" // address + "69f7f6556fb1ac3189a79b40dda32f1f"_hex; s >> ser_params(addr); BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsTor()); @@ -506,20 +506,19 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_REQUIRE(s.empty()); // Invalid TORv3, with bogus length. - s << Span{ParseHex("04" // network type (TORv3) - "00" // address length - "00" // address - )}; + s << "04" // network type (TORv3) + "00" // address length + "00"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("BIP155 TORv3 address with length 0 (should be 32)")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Valid I2P. - s << Span{ParseHex("05" // network type (I2P) - "20" // address length - "a2894dabaec08c0051a481a6dac88b64" // address - "f98232ae42d4b6fd2fa81952dfe36a87")}; + s << "05" // network type (I2P) + "20" // address length + "a2894dabaec08c0051a481a6dac88b64" // address + "f98232ae42d4b6fd2fa81952dfe36a87"_hex; s >> ser_params(addr); BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsI2P()); @@ -529,20 +528,18 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_REQUIRE(s.empty()); // Invalid I2P, with bogus length. - s << Span{ParseHex("05" // network type (I2P) - "03" // address length - "00" // address - )}; + s << "05" // network type (I2P) + "03" // address length + "00"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("BIP155 I2P address with length 3 (should be 32)")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Valid CJDNS. - s << Span{ParseHex("06" // network type (CJDNS) - "10" // address length - "fc000001000200030004000500060007" // address - )}; + s << "06" // network type (CJDNS) + "10" // address length + "fc000001000200030004000500060007"_hex; // address s >> ser_params(addr); BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsCJDNS()); @@ -551,49 +548,44 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_REQUIRE(s.empty()); // Invalid CJDNS, wrong prefix. - s << Span{ParseHex("06" // network type (CJDNS) - "10" // address length - "aa000001000200030004000500060007" // address - )}; + s << "06" // network type (CJDNS) + "10" // address length + "aa000001000200030004000500060007"_hex; // address s >> ser_params(addr); BOOST_CHECK(addr.IsCJDNS()); BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); // Invalid CJDNS, with bogus length. - s << Span{ParseHex("06" // network type (CJDNS) - "01" // address length - "00" // address - )}; + s << "06" // network type (CJDNS) + "01" // address length + "00"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("BIP155 CJDNS address with length 1 (should be 16)")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Unknown, with extreme length. - s << Span{ParseHex("aa" // network type (unknown) - "fe00000002" // address length (CompactSize's MAX_SIZE) - "01020304050607" // address - )}; + s << "aa" // network type (unknown) + "fe00000002" // address length (CompactSize's MAX_SIZE) + "01020304050607"_hex; // address BOOST_CHECK_EXCEPTION(s >> ser_params(addr), std::ios_base::failure, HasReason("Address too long: 33554432 > 512")); BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. s.clear(); // Unknown, with reasonable length. - s << Span{ParseHex("aa" // network type (unknown) - "04" // address length - "01020304" // address - )}; + s << "aa" // network type (unknown) + "04" // address length + "01020304"_hex; // address s >> ser_params(addr); BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); // Unknown, with zero length. - s << Span{ParseHex("aa" // network type (unknown) - "00" // address length - "" // address - )}; + s << "aa" // network type (unknown) + "00" // address length + ""_hex; // address s >> ser_params(addr); BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); @@ -1010,10 +1002,10 @@ BOOST_AUTO_TEST_CASE(advertise_local_address) namespace { -CKey GenerateRandomTestKey() noexcept +CKey GenerateRandomTestKey(FastRandomContext& rng) noexcept { CKey key; - uint256 key_data = InsecureRand256(); + uint256 key_data = rng.rand256(); key.Set(key_data.begin(), key_data.end(), true); return key; } @@ -1028,6 +1020,7 @@ CKey GenerateRandomTestKey() noexcept */ class V2TransportTester { + FastRandomContext& m_rng; V2Transport m_transport; //!< V2Transport being tested BIP324Cipher m_cipher; //!< Cipher to help with the other side bool m_test_initiator; //!< Whether m_transport is the initiator (true) or responder (false) @@ -1041,9 +1034,10 @@ class V2TransportTester public: /** Construct a tester object. test_initiator: whether the tested transport is initiator. */ - explicit V2TransportTester(bool test_initiator) - : m_transport{0, test_initiator}, - m_cipher{GenerateRandomTestKey(), MakeByteSpan(InsecureRand256())}, + explicit V2TransportTester(FastRandomContext& rng, bool test_initiator) + : m_rng{rng}, + m_transport{0, test_initiator}, + m_cipher{GenerateRandomTestKey(m_rng), MakeByteSpan(m_rng.rand256())}, m_test_initiator(test_initiator) {} /** Data type returned by Interact: @@ -1067,7 +1061,7 @@ public: bool progress{false}; // Send bytes from m_to_send to the transport. if (!m_to_send.empty()) { - Span<const uint8_t> to_send = Span{m_to_send}.first(1 + InsecureRandRange(m_to_send.size())); + Span<const uint8_t> to_send = Span{m_to_send}.first(1 + m_rng.randrange(m_to_send.size())); size_t old_len = to_send.size(); if (!m_transport.ReceivedBytes(to_send)) { return std::nullopt; // transport error occurred @@ -1078,7 +1072,7 @@ public: } } // Retrieve messages received by the transport. - if (m_transport.ReceivedMessageComplete() && (!progress || InsecureRandBool())) { + if (m_transport.ReceivedMessageComplete() && (!progress || m_rng.randbool())) { bool reject{false}; auto msg = m_transport.GetReceivedMessage({}, reject); if (reject) { @@ -1089,7 +1083,7 @@ public: progress = true; } // Enqueue a message to be sent by the transport to us. - if (!m_msg_to_send.empty() && (!progress || InsecureRandBool())) { + if (!m_msg_to_send.empty() && (!progress || m_rng.randbool())) { if (m_transport.SetMessageToSend(m_msg_to_send.front())) { m_msg_to_send.pop_front(); progress = true; @@ -1097,8 +1091,8 @@ public: } // Receive bytes from the transport. const auto& [recv_bytes, _more, _msg_type] = m_transport.GetBytesToSend(!m_msg_to_send.empty()); - if (!recv_bytes.empty() && (!progress || InsecureRandBool())) { - size_t to_receive = 1 + InsecureRandRange(recv_bytes.size()); + if (!recv_bytes.empty() && (!progress || m_rng.randbool())) { + size_t to_receive = 1 + m_rng.randrange(recv_bytes.size()); m_received.insert(m_received.end(), recv_bytes.begin(), recv_bytes.begin() + to_receive); progress = true; m_transport.MarkBytesSent(to_receive); @@ -1120,7 +1114,7 @@ public: /** Send V1 version message header to the transport. */ void SendV1Version(const MessageStartChars& magic) { - CMessageHeader hdr(magic, "version", 126 + InsecureRandRange(11)); + CMessageHeader hdr(magic, "version", 126 + m_rng.randrange(11)); DataStream ser{}; ser << hdr; m_to_send.insert(m_to_send.end(), UCharCast(ser.data()), UCharCast(ser.data() + ser.size())); @@ -1145,13 +1139,13 @@ public: void SendGarbage(size_t garbage_len) { // Generate random garbage and send it. - SendGarbage(g_insecure_rand_ctx.randbytes<uint8_t>(garbage_len)); + SendGarbage(m_rng.randbytes<uint8_t>(garbage_len)); } /** Schedule garbage (with valid random length) to be sent to the transport. */ void SendGarbage() { - SendGarbage(InsecureRandRange(V2Transport::MAX_GARBAGE_LEN + 1)); + SendGarbage(m_rng.randrange(V2Transport::MAX_GARBAGE_LEN + 1)); } /** Schedule a message to be sent to us by the transport. */ @@ -1254,7 +1248,7 @@ public: for (garblen = 0; garblen <= V2Transport::MAX_GARBAGE_LEN; ++garblen) { BOOST_REQUIRE(m_received.size() >= garblen + BIP324Cipher::GARBAGE_TERMINATOR_LEN); auto term_span = MakeByteSpan(Span{m_received}.subspan(garblen, BIP324Cipher::GARBAGE_TERMINATOR_LEN)); - if (term_span == m_cipher.GetReceiveGarbageTerminator()) break; + if (std::ranges::equal(term_span, m_cipher.GetReceiveGarbageTerminator())) break; } // Copy the garbage to a buffer. m_recv_garbage.assign(m_received.begin(), m_received.begin() + garblen); @@ -1279,7 +1273,7 @@ public: auto ret = ReceivePacket(); BOOST_CHECK(ret.size() == payload.size() + 1); BOOST_CHECK(ret[0] == short_id); - BOOST_CHECK(Span{ret}.subspan(1) == payload); + BOOST_CHECK(std::ranges::equal(Span{ret}.subspan(1), payload)); } /** Expect application packet to have been received, with specified 12-char message type and @@ -1296,7 +1290,7 @@ public: BOOST_CHECK(ret[1 + i] == 0); } } - BOOST_CHECK(Span{ret}.subspan(1 + CMessageHeader::COMMAND_SIZE) == payload); + BOOST_CHECK(std::ranges::equal(Span{ret}.subspan(1 + CMessageHeader::COMMAND_SIZE), payload)); } /** Schedule an encrypted packet with specified message type and payload to be sent to @@ -1334,7 +1328,7 @@ public: /** Introduce a bit error in the data scheduled to be sent. */ void Damage() { - m_to_send[InsecureRandRange(m_to_send.size())] ^= (uint8_t{1} << InsecureRandRange(8)); + m_to_send[m_rng.randrange(m_to_send.size())] ^= (uint8_t{1} << m_rng.randrange(8)); } }; @@ -1344,7 +1338,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) { // A mostly normal scenario, testing a transport in initiator mode. for (int i = 0; i < 10; ++i) { - V2TransportTester tester(true); + V2TransportTester tester(m_rng, true); auto ret = tester.Interact(); BOOST_REQUIRE(ret && ret->empty()); tester.SendKey(); @@ -1357,16 +1351,16 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveGarbage(); tester.ReceiveVersion(); tester.CompareSessionIDs(); - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000)); - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(100000)); + auto msg_data_2 = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendMessage(uint8_t(4), msg_data_1); // cmpctblock short id tester.SendMessage(0, {}); // Invalidly encoded message tester.SendMessage("tx", msg_data_2); // 12-character encoded message type ret = tester.Interact(); BOOST_REQUIRE(ret && ret->size() == 3); - BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "cmpctblock" && Span{(*ret)[0]->m_recv} == MakeByteSpan(msg_data_1)); + BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "cmpctblock" && std::ranges::equal((*ret)[0]->m_recv, MakeByteSpan(msg_data_1))); BOOST_CHECK(!(*ret)[1]); - BOOST_CHECK((*ret)[2] && (*ret)[2]->m_type == "tx" && Span{(*ret)[2]->m_recv} == MakeByteSpan(msg_data_2)); + BOOST_CHECK((*ret)[2] && (*ret)[2]->m_type == "tx" && std::ranges::equal((*ret)[2]->m_recv, MakeByteSpan(msg_data_2))); // Then send a message with a bit error, expecting failure. It's possible this failure does // not occur immediately (when the length descriptor was modified), but it should come @@ -1378,14 +1372,14 @@ BOOST_AUTO_TEST_CASE(v2transport_test) if (!ret) break; // failure BOOST_CHECK(ret->size() == 0); // no message can be delivered // Send another message. - auto msg_data_3 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(10000)); + auto msg_data_3 = m_rng.randbytes<uint8_t>(m_rng.randrange(10000)); tester.SendMessage(uint8_t(12), msg_data_3); // getheaders short id } } // Normal scenario, with a transport in responder node. for (int i = 0; i < 10; ++i) { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendKey(); tester.SendGarbage(); auto ret = tester.Interact(); @@ -1398,17 +1392,17 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveGarbage(); tester.ReceiveVersion(); tester.CompareSessionIDs(); - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000)); - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(100000)); + auto msg_data_2 = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendMessage(uint8_t(14), msg_data_1); // inv short id tester.SendMessage(uint8_t(19), msg_data_2); // pong short id ret = tester.Interact(); BOOST_REQUIRE(ret && ret->size() == 2); - BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "inv" && Span{(*ret)[0]->m_recv} == MakeByteSpan(msg_data_1)); - BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "pong" && Span{(*ret)[1]->m_recv} == MakeByteSpan(msg_data_2)); + BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "inv" && std::ranges::equal((*ret)[0]->m_recv, MakeByteSpan(msg_data_1))); + BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "pong" && std::ranges::equal((*ret)[1]->m_recv, MakeByteSpan(msg_data_2))); // Then send a too-large message. - auto msg_data_3 = g_insecure_rand_ctx.randbytes<uint8_t>(4005000); + auto msg_data_3 = m_rng.randbytes<uint8_t>(4005000); tester.SendMessage(uint8_t(11), msg_data_3); // getdata short id ret = tester.Interact(); BOOST_CHECK(!ret); @@ -1417,18 +1411,18 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Various valid but unusual scenarios. for (int i = 0; i < 50; ++i) { /** Whether an initiator or responder is being tested. */ - bool initiator = InsecureRandBool(); + bool initiator = m_rng.randbool(); /** Use either 0 bytes or the maximum possible (4095 bytes) garbage length. */ - size_t garb_len = InsecureRandBool() ? 0 : V2Transport::MAX_GARBAGE_LEN; + size_t garb_len = m_rng.randbool() ? 0 : V2Transport::MAX_GARBAGE_LEN; /** How many decoy packets to send before the version packet. */ - unsigned num_ignore_version = InsecureRandRange(10); + unsigned num_ignore_version = m_rng.randrange(10); /** What data to send in the version packet (ignored by BIP324 peers, but reserved for future extensions). */ - auto ver_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandBool() ? 0 : InsecureRandRange(1000)); + auto ver_data = m_rng.randbytes<uint8_t>(m_rng.randbool() ? 0 : m_rng.randrange(1000)); /** Whether to immediately send key and garbage out (required for responders, optional otherwise). */ - bool send_immediately = !initiator || InsecureRandBool(); + bool send_immediately = !initiator || m_rng.randbool(); /** How many decoy packets to send before the first and second real message. */ - unsigned num_decoys_1 = InsecureRandRange(1000), num_decoys_2 = InsecureRandRange(1000); - V2TransportTester tester(initiator); + unsigned num_decoys_1 = m_rng.randrange(1000), num_decoys_2 = m_rng.randrange(1000); + V2TransportTester tester(m_rng, initiator); if (send_immediately) { tester.SendKey(); tester.SendGarbage(garb_len); @@ -1442,8 +1436,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveKey(); tester.SendGarbageTerm(); for (unsigned v = 0; v < num_ignore_version; ++v) { - size_t ver_ign_data_len = InsecureRandBool() ? 0 : InsecureRandRange(1000); - auto ver_ign_data = g_insecure_rand_ctx.randbytes<uint8_t>(ver_ign_data_len); + size_t ver_ign_data_len = m_rng.randbool() ? 0 : m_rng.randrange(1000); + auto ver_ign_data = m_rng.randbytes<uint8_t>(ver_ign_data_len); tester.SendVersion(ver_ign_data, true); } tester.SendVersion(ver_data, false); @@ -1453,16 +1447,16 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveVersion(); tester.CompareSessionIDs(); for (unsigned d = 0; d < num_decoys_1; ++d) { - auto decoy_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto decoy_data = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendPacket(/*content=*/decoy_data, /*aad=*/{}, /*ignore=*/true); } - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(4000000)); + auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(4000000)); tester.SendMessage(uint8_t(28), msg_data_1); for (unsigned d = 0; d < num_decoys_2; ++d) { - auto decoy_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto decoy_data = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendPacket(/*content=*/decoy_data, /*aad=*/{}, /*ignore=*/true); } - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto msg_data_2 = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendMessage(uint8_t(13), msg_data_2); // headers short id // Send invalidly-encoded message tester.SendMessage(std::string("blocktxn\x00\x00\x00a", CMessageHeader::COMMAND_SIZE), {}); @@ -1470,8 +1464,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.AddMessage("barfoo", {}); // test sending unknown message type ret = tester.Interact(); BOOST_REQUIRE(ret && ret->size() == 4); - BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "addrv2" && Span{(*ret)[0]->m_recv} == MakeByteSpan(msg_data_1)); - BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "headers" && Span{(*ret)[1]->m_recv} == MakeByteSpan(msg_data_2)); + BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "addrv2" && std::ranges::equal((*ret)[0]->m_recv, MakeByteSpan(msg_data_1))); + BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "headers" && std::ranges::equal((*ret)[1]->m_recv, MakeByteSpan(msg_data_2))); BOOST_CHECK(!(*ret)[2]); BOOST_CHECK((*ret)[3] && (*ret)[3]->m_type == "foobar" && (*ret)[3]->m_recv.empty()); tester.ReceiveMessage("barfoo", {}); @@ -1479,7 +1473,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Too long garbage (initiator). { - V2TransportTester tester(true); + V2TransportTester tester(m_rng, true); auto ret = tester.Interact(); BOOST_REQUIRE(ret && ret->empty()); tester.SendKey(); @@ -1492,7 +1486,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Too long garbage (responder). { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendKey(); tester.SendGarbage(V2Transport::MAX_GARBAGE_LEN + 1); auto ret = tester.Interact(); @@ -1505,23 +1499,23 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Send garbage that includes the first 15 garbage terminator bytes somewhere. { - V2TransportTester tester(true); + V2TransportTester tester(m_rng, true); auto ret = tester.Interact(); BOOST_REQUIRE(ret && ret->empty()); tester.SendKey(); tester.ReceiveKey(); /** The number of random garbage bytes before the included first 15 bytes of terminator. */ - size_t len_before = InsecureRandRange(V2Transport::MAX_GARBAGE_LEN - 16 + 1); + size_t len_before = m_rng.randrange(V2Transport::MAX_GARBAGE_LEN - 16 + 1); /** The number of random garbage bytes after it. */ - size_t len_after = InsecureRandRange(V2Transport::MAX_GARBAGE_LEN - 16 - len_before + 1); + size_t len_after = m_rng.randrange(V2Transport::MAX_GARBAGE_LEN - 16 - len_before + 1); // Construct len_before + 16 + len_after random bytes. - auto garbage = g_insecure_rand_ctx.randbytes<uint8_t>(len_before + 16 + len_after); + auto garbage = m_rng.randbytes<uint8_t>(len_before + 16 + len_after); // Replace the designed 16 bytes in the middle with the to-be-sent garbage terminator. auto garb_term = MakeUCharSpan(tester.GetCipher().GetSendGarbageTerminator()); std::copy(garb_term.begin(), garb_term.begin() + 16, garbage.begin() + len_before); // Introduce a bit error in the last byte of that copied garbage terminator, making only // the first 15 of them match. - garbage[len_before + 15] ^= (uint8_t(1) << InsecureRandRange(8)); + garbage[len_before + 15] ^= (uint8_t(1) << m_rng.randrange(8)); tester.SendGarbage(garbage); tester.SendGarbageTerm(); tester.SendVersion(); @@ -1530,21 +1524,21 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveGarbage(); tester.ReceiveVersion(); tester.CompareSessionIDs(); - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(4000000); // test that receiving 4M payload works - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(4000000); // test that sending 4M payload works - tester.SendMessage(uint8_t(InsecureRandRange(223) + 33), {}); // unknown short id + auto msg_data_1 = m_rng.randbytes<uint8_t>(4000000); // test that receiving 4M payload works + auto msg_data_2 = m_rng.randbytes<uint8_t>(4000000); // test that sending 4M payload works + tester.SendMessage(uint8_t(m_rng.randrange(223) + 33), {}); // unknown short id tester.SendMessage(uint8_t(2), msg_data_1); // "block" short id tester.AddMessage("blocktxn", msg_data_2); // schedule blocktxn to be sent to us ret = tester.Interact(); BOOST_REQUIRE(ret && ret->size() == 2); BOOST_CHECK(!(*ret)[0]); - BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "block" && Span{(*ret)[1]->m_recv} == MakeByteSpan(msg_data_1)); + BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "block" && std::ranges::equal((*ret)[1]->m_recv, MakeByteSpan(msg_data_1))); tester.ReceiveMessage(uint8_t(3), msg_data_2); // "blocktxn" short id } // Send correct network's V1 header { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendV1Version(Params().MessageStart()); auto ret = tester.Interact(); BOOST_CHECK(ret); @@ -1552,7 +1546,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Send wrong network's V1 header { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendV1Version(CChainParams::Main()->MessageStart()); auto ret = tester.Interact(); BOOST_CHECK(!ret); diff --git a/src/test/node_warnings_tests.cpp b/src/test/node_warnings_tests.cpp new file mode 100644 index 0000000000..2bcc2c95ed --- /dev/null +++ b/src/test/node_warnings_tests.cpp @@ -0,0 +1,52 @@ +// 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 <node/warnings.h> +#include <util/translation.h> + +#include <test/util/setup_common.h> + +#include <boost/test/unit_test.hpp> + +BOOST_FIXTURE_TEST_SUITE(node_warnings_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(warnings) +{ + node::Warnings warnings; + // On pre-release builds, a warning is generated automatically + warnings.Unset(node::Warning::PRE_RELEASE_TEST_BUILD); + + // For these tests, we don't care what the exact warnings are, so + // just refer to them as warning_1 and warning_2 + const auto warning_1{node::Warning::CLOCK_OUT_OF_SYNC}; + const auto warning_2{node::Warning::FATAL_INTERNAL_ERROR}; + + // Ensure we start without any warnings + BOOST_CHECK(warnings.GetMessages().size() == 0); + // Add two warnings + BOOST_CHECK(warnings.Set(warning_1, _("warning 1"))); + BOOST_CHECK(warnings.Set(warning_2, _("warning 2"))); + // Unset the second one + BOOST_CHECK(warnings.Unset(warning_2)); + // Since it's already been unset, this should return false + BOOST_CHECK(!warnings.Unset(warning_2)); + // We should now be able to set w2 again + BOOST_CHECK(warnings.Set(warning_2, _("warning 2 - revision 1"))); + // Setting w2 again should return false since it's already set + BOOST_CHECK(!warnings.Set(warning_2, _("warning 2 - revision 2"))); + + // Verify messages are correct + const auto messages{warnings.GetMessages()}; + BOOST_CHECK(messages.size() == 2); + BOOST_CHECK(messages[0].original == "warning 1"); + BOOST_CHECK(messages[1].original == "warning 2 - revision 1"); + + // Clearing all warnings should also clear all messages + BOOST_CHECK(warnings.Unset(warning_1)); + BOOST_CHECK(warnings.Unset(warning_2)); + BOOST_CHECK(warnings.GetMessages().size() == 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp index 450bf6a4fc..799f2c0fec 100644 --- a/src/test/orphanage_tests.cpp +++ b/src/test/orphanage_tests.cpp @@ -3,12 +3,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <arith_uint256.h> +#include <consensus/validation.h> +#include <policy/policy.h> #include <primitives/transaction.h> #include <pubkey.h> #include <script/sign.h> #include <script/signingprovider.h> #include <test/util/random.h> #include <test/util/setup_common.h> +#include <test/util/transaction_utils.h> #include <txorphanage.h> #include <array> @@ -21,24 +24,26 @@ BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup) class TxOrphanageTest : public TxOrphanage { public: - inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + TxOrphanageTest(FastRandomContext& rng) : m_rng{rng} {} + + 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())); + it = m_orphans.lower_bound(Wtxid::FromUint256(m_rng.rand256())); if (it == m_orphans.end()) it = m_orphans.begin(); return it->second.tx; } + + FastRandomContext& m_rng; }; -static void MakeNewKeyWithFastRandomContext(CKey& key, FastRandomContext& rand_ctx = g_insecure_rand_ctx) +static void MakeNewKeyWithFastRandomContext(CKey& key, FastRandomContext& rand_ctx) { std::vector<unsigned char> keydata; keydata = rand_ctx.randbytes(32); @@ -106,21 +111,25 @@ 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}}; + m_rng.Reseed(uint256{33}); - TxOrphanageTest orphanage; + TxOrphanageTest orphanage{m_rng}; CKey key; - MakeNewKeyWithFastRandomContext(key); + MakeNewKeyWithFastRandomContext(key, m_rng); 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++) { CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256()); + tx.vin[0].prevout.hash = Txid::FromUint256(m_rng.rand256()); tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; @@ -172,22 +181,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) @@ -334,4 +373,21 @@ BOOST_AUTO_TEST_CASE(get_children) } } +BOOST_AUTO_TEST_CASE(too_large_orphan_tx) +{ + TxOrphanage orphanage; + CMutableTransaction tx; + tx.vin.resize(1); + + // check that txs larger than MAX_STANDARD_TX_WEIGHT are not added to the orphanage + BulkTransaction(tx, MAX_STANDARD_TX_WEIGHT + 4); + BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(tx)), MAX_STANDARD_TX_WEIGHT + 4); + BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), 0)); + + tx.vout.clear(); + BulkTransaction(tx, MAX_STANDARD_TX_WEIGHT); + BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(tx)), MAX_STANDARD_TX_WEIGHT); + BOOST_CHECK(orphanage.AddTx(MakeTransactionRef(tx), 0)); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/peerman_tests.cpp b/src/test/peerman_tests.cpp index 28866695bc..6de373eef2 100644 --- a/src/test/peerman_tests.cpp +++ b/src/test/peerman_tests.cpp @@ -20,7 +20,8 @@ static void mineBlock(const node::NodeContext& node, std::chrono::seconds block_ { auto curr_time = GetTime<std::chrono::seconds>(); SetMockTime(block_time); // update time so the block is created with it - CBlock block = node::BlockAssembler{node.chainman->ActiveChainstate(), nullptr}.CreateNewBlock(CScript() << OP_TRUE)->block; + node::BlockAssembler::Options options; + CBlock block = node::BlockAssembler{node.chainman->ActiveChainstate(), nullptr, options}.CreateNewBlock(CScript() << OP_TRUE)->block; while (!CheckProofOfWork(block.GetHash(), block.nBits, node.chainman->GetConsensus())) ++block.nNonce; block.fChecked = true; // little speedup SetMockTime(curr_time); // process block at current time @@ -31,7 +32,7 @@ static void mineBlock(const node::NodeContext& node, std::chrono::seconds block_ // Verifying when network-limited peer connections are desirable based on the node's proximity to the tip BOOST_AUTO_TEST_CASE(connections_desirable_service_flags) { - std::unique_ptr<PeerManager> peerman = PeerManager::make(*m_node.connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {}); + std::unique_ptr<PeerManager> peerman = PeerManager::make(*m_node.connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {}); auto consensus = m_node.chainman->GetParams().GetConsensus(); // Check we start connecting to full nodes diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index edecf70c6f..2ba48d717a 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -17,22 +17,26 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree { public: + CPartialMerkleTreeTester(FastRandomContext& rng) : m_rng{rng} {} + // flip one bit in one of the hashes - this should break the authentication void Damage() { - unsigned int n = InsecureRandRange(vHash.size()); - int bit = InsecureRandBits(8); + unsigned int n = m_rng.randrange(vHash.size()); + int bit = m_rng.randbits(8); *(vHash[n].begin() + (bit>>3)) ^= 1<<(bit&7); } + + FastRandomContext& m_rng; }; 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; @@ -59,7 +63,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) std::vector<bool> vMatch(nTx, false); std::vector<uint256> vMatchTxid1; for (unsigned int j=0; j<nTx; j++) { - bool fInclude = InsecureRandBits(att / 2) == 0; + bool fInclude = m_rng.randbits(att / 2) == 0; vMatch[j] = fInclude; if (fInclude) vMatchTxid1.push_back(vTxid[j]); @@ -77,7 +81,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8); // deserialize into a tester copy - CPartialMerkleTreeTester pmt2; + CPartialMerkleTreeTester pmt2{m_rng}; ss >> pmt2; // extract merkle root and matched txids from copy diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 6cadc3290a..83977c1c89 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -1,8 +1,9 @@ -// 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. #include <policy/fees.h> +#include <policy/fees_args.h> #include <policy/policy.h> #include <test/util/txmempool.h> #include <txmempool.h> @@ -18,7 +19,7 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, ChainTestingSetup) BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) { - CBlockPolicyEstimator& feeEst = *Assert(m_node.fee_estimator); + CBlockPolicyEstimator feeEst{FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES}; CTxMemPool& mpool = *Assert(m_node.mempool); m_node.validation_signals->RegisterValidationInterface(&feeEst); TestMemPoolEntryHelper entry; diff --git a/src/test/pool_tests.cpp b/src/test/pool_tests.cpp index 5ad4afa3a1..9d15660126 100644 --- a/src/test/pool_tests.cpp +++ b/src/test/pool_tests.cpp @@ -129,17 +129,17 @@ BOOST_AUTO_TEST_CASE(random_allocations) std::vector<PtrSizeAlignment> ptr_size_alignment{}; for (size_t i = 0; i < 1000; ++i) { // make it a bit more likely to allocate than deallocate - if (ptr_size_alignment.empty() || 0 != InsecureRandRange(4)) { + if (ptr_size_alignment.empty() || 0 != m_rng.randrange(4)) { // allocate a random item - std::size_t alignment = std::size_t{1} << InsecureRandRange(8); // 1, 2, ..., 128 - std::size_t size = (InsecureRandRange(200) / alignment + 1) * alignment; // multiple of alignment + std::size_t alignment = std::size_t{1} << m_rng.randrange(8); // 1, 2, ..., 128 + std::size_t size = (m_rng.randrange(200) / alignment + 1) * alignment; // multiple of alignment void* ptr = resource.Allocate(size, alignment); BOOST_TEST(ptr != nullptr); BOOST_TEST((reinterpret_cast<uintptr_t>(ptr) & (alignment - 1)) == 0); ptr_size_alignment.push_back({ptr, size, alignment}); } else { // deallocate a random item - auto& x = ptr_size_alignment[InsecureRandRange(ptr_size_alignment.size())]; + auto& x = ptr_size_alignment[m_rng.randrange(ptr_size_alignment.size())]; resource.Deallocate(x.ptr, x.bytes, x.alignment); x = ptr_size_alignment.back(); ptr_size_alignment.pop_back(); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 3a44d1da49..76e4600441 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)); } @@ -147,9 +147,9 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) } for (int j = 0; j < 1000; j++) { - CBlockIndex *p1 = &blocks[InsecureRandRange(10000)]; - CBlockIndex *p2 = &blocks[InsecureRandRange(10000)]; - CBlockIndex *p3 = &blocks[InsecureRandRange(10000)]; + CBlockIndex *p1 = &blocks[m_rng.randrange(10000)]; + CBlockIndex *p2 = &blocks[m_rng.randrange(10000)]; + CBlockIndex *p3 = &blocks[m_rng.randrange(10000)]; int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, chainParams->GetConsensus()); BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime()); @@ -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..0588bf9b4a 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> @@ -28,7 +27,6 @@ class prevector_tester { typedef typename pretype::size_type Size; bool passed = true; - FastRandomContext rand_cache; uint256 rand_seed; @@ -58,14 +56,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{}; @@ -209,84 +207,83 @@ public: BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString()); } - prevector_tester() { - SeedInsecureRand(); - rand_seed = InsecureRand256(); - rand_cache = FastRandomContext(rand_seed); + prevector_tester(FastRandomContext& rng) { + rand_seed = rng.rand256(); + rng.Reseed(rand_seed); } }; BOOST_AUTO_TEST_CASE(PrevectorTestInt) { for (int j = 0; j < 64; j++) { - prevector_tester<8, int> test; + prevector_tester<8, int> test{m_rng}; for (int i = 0; i < 2048; i++) { - if (InsecureRandBits(2) == 0) { - test.insert(InsecureRandRange(test.size() + 1), int(InsecureRand32())); + if (m_rng.randbits(2) == 0) { + test.insert(m_rng.randrange(test.size() + 1), int(m_rng.rand32())); } - if (test.size() > 0 && InsecureRandBits(2) == 1) { - test.erase(InsecureRandRange(test.size())); + if (test.size() > 0 && m_rng.randbits(2) == 1) { + test.erase(m_rng.randrange(test.size())); } - if (InsecureRandBits(3) == 2) { - int new_size = std::max(0, std::min(30, (int)test.size() + (int)InsecureRandRange(5) - 2)); + if (m_rng.randbits(3) == 2) { + int new_size = std::max(0, std::min(30, (int)test.size() + (int)m_rng.randrange(5) - 2)); test.resize(new_size); } - if (InsecureRandBits(3) == 3) { - test.insert(InsecureRandRange(test.size() + 1), 1 + InsecureRandBool(), int(InsecureRand32())); + if (m_rng.randbits(3) == 3) { + test.insert(m_rng.randrange(test.size() + 1), 1 + m_rng.randbool(), int(m_rng.rand32())); } - if (InsecureRandBits(3) == 4) { - int del = std::min<int>(test.size(), 1 + (InsecureRandBool())); - int beg = InsecureRandRange(test.size() + 1 - del); + if (m_rng.randbits(3) == 4) { + int del = std::min<int>(test.size(), 1 + (m_rng.randbool())); + int beg = m_rng.randrange(test.size() + 1 - del); test.erase(beg, beg + del); } - if (InsecureRandBits(4) == 5) { - test.push_back(int(InsecureRand32())); + if (m_rng.randbits(4) == 5) { + test.push_back(int(m_rng.rand32())); } - if (test.size() > 0 && InsecureRandBits(4) == 6) { + if (test.size() > 0 && m_rng.randbits(4) == 6) { test.pop_back(); } - if (InsecureRandBits(5) == 7) { + if (m_rng.randbits(5) == 7) { int values[4]; - int num = 1 + (InsecureRandBits(2)); + int num = 1 + (m_rng.randbits(2)); for (int k = 0; k < num; k++) { - values[k] = int(InsecureRand32()); + values[k] = int(m_rng.rand32()); } - test.insert_range(InsecureRandRange(test.size() + 1), values, values + num); + test.insert_range(m_rng.randrange(test.size() + 1), values, values + num); } - if (InsecureRandBits(5) == 8) { - int del = std::min<int>(test.size(), 1 + (InsecureRandBits(2))); - int beg = InsecureRandRange(test.size() + 1 - del); + if (m_rng.randbits(5) == 8) { + int del = std::min<int>(test.size(), 1 + (m_rng.randbits(2))); + int beg = m_rng.randrange(test.size() + 1 - del); test.erase(beg, beg + del); } - if (InsecureRandBits(5) == 9) { - test.reserve(InsecureRandBits(5)); + if (m_rng.randbits(5) == 9) { + test.reserve(m_rng.randbits(5)); } - if (InsecureRandBits(6) == 10) { + if (m_rng.randbits(6) == 10) { test.shrink_to_fit(); } if (test.size() > 0) { - test.update(InsecureRandRange(test.size()), int(InsecureRand32())); + test.update(m_rng.randrange(test.size()), int(m_rng.rand32())); } - if (InsecureRandBits(10) == 11) { + if (m_rng.randbits(10) == 11) { test.clear(); } - if (InsecureRandBits(9) == 12) { - test.assign(InsecureRandBits(5), int(InsecureRand32())); + if (m_rng.randbits(9) == 12) { + test.assign(m_rng.randbits(5), int(m_rng.rand32())); } - if (InsecureRandBits(3) == 3) { + if (m_rng.randbits(3) == 3) { test.swap(); } - if (InsecureRandBits(4) == 8) { + if (m_rng.randbits(4) == 8) { test.copy(); } - if (InsecureRandBits(5) == 18) { + if (m_rng.randbits(5) == 18) { test.move(); } - if (InsecureRandBits(5) == 19) { - unsigned int num = 1 + (InsecureRandBits(4)); + if (m_rng.randbits(5) == 19) { + unsigned int num = 1 + (m_rng.randbits(4)); std::vector<int> values(num); for (int& v : values) { - v = int(InsecureRand32()); + v = int(m_rng.rand32()); } test.resize_uninitialized(values); } diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp index ada61029ee..7d1079fbbe 100644 --- a/src/test/raii_event_tests.cpp +++ b/src/test/raii_event_tests.cpp @@ -86,14 +86,6 @@ BOOST_AUTO_TEST_CASE(raii_event_order) event_set_mem_functions(malloc, realloc, free); } -#else - -BOOST_AUTO_TEST_CASE(raii_event_tests_SKIPPED) -{ - // It would probably be ideal to report skipped, but boost::test doesn't seem to make that practical (at least not in versions available with common distros) - BOOST_TEST_MESSAGE("Skipping raii_event_tess: libevent doesn't support event_set_mem_functions"); -} - #endif // EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED BOOST_AUTO_TEST_SUITE_END() 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/rpc_tests.cpp b/src/test/rpc_tests.cpp index efa078ca74..5089f3e8e3 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -17,6 +17,8 @@ #include <boost/test/unit_test.hpp> +using util::SplitString; + static UniValue JSON(std::string_view json) { UniValue value; @@ -552,7 +554,7 @@ BOOST_AUTO_TEST_CASE(help_example) // test different argument types const RPCArgList& args = {{"foo", "bar"}, {"b", true}, {"n", 1}}; BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", args), "> bitcoin-cli -named test foo=bar b=true n=1\n"); - BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", args), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"foo\":\"bar\",\"b\":true,\"n\":1}}' -H 'content-type: application/json;' http://127.0.0.1:8332/\n"); + BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", args), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"foo\":\"bar\",\"b\":true,\"n\":1}}' -H 'content-type: application/json' http://127.0.0.1:8332/\n"); // test shell escape BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b'ar"}}), "> bitcoin-cli -named test foo='b'''ar'\n"); @@ -565,7 +567,7 @@ BOOST_AUTO_TEST_CASE(help_example) obj_value.pushKV("b", false); obj_value.pushKV("n", 1); BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", obj_value}}), "> bitcoin-cli -named test name='{\"foo\":\"bar\",\"b\":false,\"n\":1}'\n"); - BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", obj_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":{\"foo\":\"bar\",\"b\":false,\"n\":1}}}' -H 'content-type: application/json;' http://127.0.0.1:8332/\n"); + BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", obj_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":{\"foo\":\"bar\",\"b\":false,\"n\":1}}}' -H 'content-type: application/json' http://127.0.0.1:8332/\n"); // test array params UniValue arr_value(UniValue::VARR); @@ -573,7 +575,7 @@ BOOST_AUTO_TEST_CASE(help_example) arr_value.push_back(false); arr_value.push_back(1); BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", arr_value}}), "> bitcoin-cli -named test name='[\"bar\",false,1]'\n"); - BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", arr_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":[\"bar\",false,1]}}' -H 'content-type: application/json;' http://127.0.0.1:8332/\n"); + BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", arr_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":[\"bar\",false,1]}}' -H 'content-type: application/json' http://127.0.0.1:8332/\n"); // test types don't matter for shell BOOST_CHECK_EQUAL(HelpExampleCliNamed("foo", {{"arg", true}}), HelpExampleCliNamed("foo", {{"arg", "true"}})); diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 54dcc218b9..096de0724f 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -11,6 +11,7 @@ #include <script/sign.h> #include <script/signingprovider.h> #include <test/util/setup_common.h> +#include <test/util/transaction_utils.h> #include <validation.h> #include <vector> @@ -113,13 +114,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..e9ce82ca8a 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -16,6 +16,7 @@ #include <univalue.h> +using namespace util::hex_literals; BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup) @@ -128,6 +129,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 +201,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) @@ -362,12 +389,12 @@ BOOST_AUTO_TEST_CASE(script_standard_taproot_builder) BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({128,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), true); BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({129,129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), false); - XOnlyPubKey key_inner{ParseHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")}; - XOnlyPubKey key_1{ParseHex("c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5")}; - XOnlyPubKey key_2{ParseHex("f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9")}; + XOnlyPubKey key_inner{"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"_hex_u8}; + XOnlyPubKey key_1{"c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"_hex_u8}; + XOnlyPubKey key_2{"f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"_hex_u8}; 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..59eb90bd27 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -35,6 +35,8 @@ // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS +using namespace util::hex_literals; + static const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int ParseScriptFlags(std::string strFlags); @@ -110,8 +112,7 @@ static ScriptError_t ParseScriptError(const std::string& name) return SCRIPT_ERR_UNKNOWN_ERROR; } -BOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup) - +struct ScriptTest : BasicTestingSetup { void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, uint32_t flags, const std::string& message, int scriptError, CAmount nValue = 0) { bool expect = (scriptError == SCRIPT_ERR_OK); @@ -122,13 +123,12 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript ScriptError err; const CTransaction txCredit{BuildCreditingTransaction(scriptPubKey, nValue)}; CMutableTransaction tx = BuildSpendingTransaction(scriptSig, scriptWitness, txCredit); - CMutableTransaction tx2 = tx; BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message); BOOST_CHECK_MESSAGE(err == scriptError, FormatScriptError(err) + " where " + FormatScriptError((ScriptError_t)scriptError) + " expected: " + message); // Verify that removing flags from a passing test or adding flags to a failing test does not change the result. for (int i = 0; i < 16; ++i) { - uint32_t extra_flags(InsecureRandBits(16)); + uint32_t extra_flags(m_rng.randbits(16)); uint32_t combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)}; // Weed out some invalid flag combinations. if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue; @@ -136,6 +136,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags)); } } +}; // struct ScriptTest void static NegateSignatureS(std::vector<unsigned char>& vchSig) { // Parse the signature. @@ -369,11 +370,11 @@ public: return *this; } - TestBuilder& Test() + TestBuilder& Test(ScriptTest& test) { TestBuilder copy = *this; // Make a copy so we can rollback the push. DoPush(); - DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, scriptWitness, flags, comment, scriptError, nValue); + test.DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, scriptWitness, flags, comment, scriptError, nValue); *this = copy; return *this; } @@ -425,6 +426,8 @@ std::string JSONPrettyPrint(const UniValue& univalue) } } // namespace +BOOST_FIXTURE_TEST_SUITE(script_tests, ScriptTest) + BOOST_AUTO_TEST_CASE(script_build) { const KeyData keys; @@ -884,7 +887,7 @@ BOOST_AUTO_TEST_CASE(script_build) std::string strGen; #endif for (TestBuilder& test : tests) { - test.Test(); + test.Test(*this); std::string str = JSONPrettyPrint(test.GetJSON()); #ifdef UPDATE_JSON_TESTS strGen += str + ",\n"; @@ -1265,7 +1268,7 @@ BOOST_AUTO_TEST_CASE(sign_invalid_miniscript) // Create a Taproot output which contains a leaf in which a non-32 bytes push is used where a public key is expected // by the Miniscript parser. This offending Script was found by the RPC fuzzer. - const auto invalid_pubkey{ParseHex("173d36c8c9c9c9ffffffffffff0200000000021e1e37373721361818181818181e1e1e1e19000000000000000000b19292929292926b006c9b9b9292")}; + const auto invalid_pubkey{"173d36c8c9c9c9ffffffffffff0200000000021e1e37373721361818181818181e1e1e1e19000000000000000000b19292929292926b006c9b9b9292"_hex_u8}; TaprootBuilder builder; builder.Add(0, {invalid_pubkey}, 0xc0); builder.Finalize(XOnlyPubKey::NUMS_H); @@ -1277,6 +1280,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; @@ -1339,10 +1355,23 @@ BOOST_AUTO_TEST_CASE(script_GetScriptAsm) BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); } +template <typename T> +CScript ToScript(const T& byte_container) +{ + auto span{MakeUCharSpan(byte_container)}; + return {span.begin(), span.end()}; +} + static CScript ScriptFromHex(const std::string& str) { - std::vector<unsigned char> data = ParseHex(str); - return CScript(data.begin(), data.end()); + return ToScript(*Assert(TryParseHex(str))); +} + +BOOST_AUTO_TEST_CASE(script_byte_array_u8_vector_equivalence) +{ + const CScript scriptPubKey1 = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex_v_u8 << OP_CHECKSIG; + const CScript scriptPubKey2 = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG; + BOOST_CHECK(scriptPubKey1 == scriptPubKey2); } BOOST_AUTO_TEST_CASE(script_FindAndDelete) @@ -1370,60 +1399,60 @@ BOOST_AUTO_TEST_CASE(script_FindAndDelete) BOOST_CHECK_EQUAL(FindAndDelete(s, d), 4); BOOST_CHECK(s == expect); - s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack - d = ScriptFromHex("0302ff03"); + s = ToScript("0302ff03"_hex); // PUSH 0x02ff03 onto stack + d = ToScript("0302ff03"_hex); expect = CScript(); BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1); BOOST_CHECK(s == expect); - s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03 - d = ScriptFromHex("0302ff03"); + s = ToScript("0302ff030302ff03"_hex); // PUSH 0x02ff03 PUSH 0x02ff03 + d = ToScript("0302ff03"_hex); expect = CScript(); BOOST_CHECK_EQUAL(FindAndDelete(s, d), 2); BOOST_CHECK(s == expect); - s = ScriptFromHex("0302ff030302ff03"); - d = ScriptFromHex("02"); + s = ToScript("0302ff030302ff03"_hex); + d = ToScript("02"_hex); expect = s; // FindAndDelete matches entire opcodes BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0); BOOST_CHECK(s == expect); - s = ScriptFromHex("0302ff030302ff03"); - d = ScriptFromHex("ff"); + s = ToScript("0302ff030302ff03"_hex); + d = ToScript("ff"_hex); expect = s; BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0); BOOST_CHECK(s == expect); // This is an odd edge case: strip of the push-three-bytes // prefix, leaving 02ff03 which is push-two-bytes: - s = ScriptFromHex("0302ff030302ff03"); - d = ScriptFromHex("03"); - expect = CScript() << ParseHex("ff03") << ParseHex("ff03"); + s = ToScript("0302ff030302ff03"_hex); + d = ToScript("03"_hex); + expect = CScript() << "ff03"_hex << "ff03"_hex; BOOST_CHECK_EQUAL(FindAndDelete(s, d), 2); BOOST_CHECK(s == expect); // Byte sequence that spans multiple opcodes: - s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY - d = ScriptFromHex("feed51"); + s = ToScript("02feed5169"_hex); // PUSH(0xfeed) OP_1 OP_VERIFY + d = ToScript("feed51"_hex); expect = s; BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0); // doesn't match 'inside' opcodes BOOST_CHECK(s == expect); - s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY - d = ScriptFromHex("02feed51"); - expect = ScriptFromHex("69"); + s = ToScript("02feed5169"_hex); // PUSH(0xfeed) OP_1 OP_VERIFY + d = ToScript("02feed51"_hex); + expect = ToScript("69"_hex); BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1); BOOST_CHECK(s == expect); - s = ScriptFromHex("516902feed5169"); - d = ScriptFromHex("feed51"); + s = ToScript("516902feed5169"_hex); + d = ToScript("feed51"_hex); expect = s; BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0); BOOST_CHECK(s == expect); - s = ScriptFromHex("516902feed5169"); - d = ScriptFromHex("02feed51"); - expect = ScriptFromHex("516969"); + s = ToScript("516902feed5169"_hex); + d = ToScript("02feed51"_hex); + expect = ToScript("516969"_hex); BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1); BOOST_CHECK(s == expect); @@ -1441,15 +1470,15 @@ BOOST_AUTO_TEST_CASE(script_FindAndDelete) // Another weird edge case: // End with invalid push (not enough data)... - s = ScriptFromHex("0003feed"); - d = ScriptFromHex("03feed"); // ... can remove the invalid push - expect = ScriptFromHex("00"); + s = ToScript("0003feed"_hex); + d = ToScript("03feed"_hex); // ... can remove the invalid push + expect = ToScript("00"_hex); BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1); BOOST_CHECK(s == expect); - s = ScriptFromHex("0003feed"); - d = ScriptFromHex("00"); - expect = ScriptFromHex("03feed"); + s = ToScript("0003feed"_hex); + d = ToScript("00"_hex); + expect = ToScript("03feed"_hex); BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1); BOOST_CHECK(s == expect); } @@ -1458,13 +1487,13 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps) { // Exercise the HasValidOps functionality CScript script; - script = ScriptFromHex("76a9141234567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac"); // Normal script + script = ToScript("76a9141234567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac"_hex); // Normal script BOOST_CHECK(script.HasValidOps()); - script = ScriptFromHex("76a914ff34567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac"); + script = ToScript("76a914ff34567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac"_hex); BOOST_CHECK(script.HasValidOps()); - script = ScriptFromHex("ff88ac"); // Script with OP_INVALIDOPCODE explicit + script = ToScript("ff88ac"_hex); // Script with OP_INVALIDOPCODE explicit BOOST_CHECK(!script.HasValidOps()); - script = ScriptFromHex("88acc0"); // Script with undefined opcode + script = ToScript("88acc0"_hex); // Script with undefined opcode BOOST_CHECK(!script.HasValidOps()); } @@ -1526,7 +1555,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 +1572,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 +1590,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 +1606,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 +1627,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 +1708,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..4464b0a089 100644 --- a/src/test/serfloat_tests.cpp +++ b/src/test/serfloat_tests.cpp @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(double_serfloat_tests) { // These specific bits are the sign bit, and the 2 top and bottom bits of // exponent and mantissa in the IEEE754 binary64 format. for (int x = 0; x < 512; ++x) { - uint64_t v = InsecureRandBits(64); + uint64_t v = m_rng.randbits(64); int x_pos = 0; for (int v_pos : {0, 1, 50, 51, 52, 53, 61, 62, 63}) { v &= ~(uint64_t{1} << v_pos); @@ -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/settings_tests.cpp b/src/test/settings_tests.cpp index 41190b3579..95f38fc0ce 100644 --- a/src/test/settings_tests.cpp +++ b/src/test/settings_tests.cpp @@ -21,6 +21,8 @@ #include <system_error> #include <vector> +using util::ToString; + inline bool operator==(const common::SettingsValue& a, const common::SettingsValue& b) { return a.write() == b.write(); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index d08d5519a1..d3320878ec 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -82,39 +82,41 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un return ss.GetHash(); } -void static RandomScript(CScript &script) { +struct SigHashTest : BasicTestingSetup { +void RandomScript(CScript &script) { static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; script = CScript(); - int ops = (InsecureRandRange(10)); + int ops = (m_rng.randrange(10)); for (int i=0; i<ops; i++) - script << oplist[InsecureRandRange(std::size(oplist))]; + script << oplist[m_rng.randrange(std::size(oplist))]; } -void static RandomTransaction(CMutableTransaction& tx, bool fSingle) +void RandomTransaction(CMutableTransaction& tx, bool fSingle) { - tx.nVersion = int(InsecureRand32()); + tx.version = m_rng.rand32(); tx.vin.clear(); tx.vout.clear(); - tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0; - int ins = (InsecureRandBits(2)) + 1; - int outs = fSingle ? ins : (InsecureRandBits(2)) + 1; + tx.nLockTime = (m_rng.randbool()) ? m_rng.rand32() : 0; + int ins = (m_rng.randbits(2)) + 1; + int outs = fSingle ? ins : (m_rng.randbits(2)) + 1; for (int in = 0; in < ins; in++) { tx.vin.emplace_back(); CTxIn &txin = tx.vin.back(); - txin.prevout.hash = Txid::FromUint256(InsecureRand256()); - txin.prevout.n = InsecureRandBits(2); + txin.prevout.hash = Txid::FromUint256(m_rng.rand256()); + txin.prevout.n = m_rng.randbits(2); RandomScript(txin.scriptSig); - txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : std::numeric_limits<uint32_t>::max(); + txin.nSequence = (m_rng.randbool()) ? m_rng.rand32() : std::numeric_limits<uint32_t>::max(); } for (int out = 0; out < outs; out++) { tx.vout.emplace_back(); CTxOut &txout = tx.vout.back(); - txout.nValue = InsecureRandMoneyAmount(); + txout.nValue = RandMoney(m_rng); RandomScript(txout.scriptPubKey); } } +}; // struct SigHashTest -BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(sighash_tests, SigHashTest) BOOST_AUTO_TEST_CASE(sighash_test) { @@ -126,12 +128,12 @@ BOOST_AUTO_TEST_CASE(sighash_test) int nRandomTests = 50000; #endif for (int i=0; i<nRandomTests; i++) { - int nHashType{int(InsecureRand32())}; + int nHashType{int(m_rng.rand32())}; CMutableTransaction txTo; RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); CScript scriptCode; RandomScript(scriptCode); - int nIn = InsecureRandRange(txTo.vin.size()); + int nIn = m_rng.randrange(txTo.vin.size()); uint256 sh, sho; sho = SignatureHashOld(scriptCode, CTransaction(txTo), nIn, nHashType); diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 2081acdf4d..aed67d5f3c 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -86,7 +86,7 @@ static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTran */ static void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& witness) { - creationTx.nVersion = 1; + creationTx.version = 1; creationTx.vin.resize(1); creationTx.vin[0].prevout.SetNull(); creationTx.vin[0].scriptSig = CScript(); @@ -94,7 +94,7 @@ static void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CM creationTx.vout[0].nValue = 1; creationTx.vout[0].scriptPubKey = scriptPubKey; - spendingTx.nVersion = 1; + spendingTx.version = 1; spendingTx.vin.resize(1); spendingTx.vin[0].prevout.hash = creationTx.GetHash(); spendingTx.vin[0].prevout.n = 0; diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 050033e43a..7ffa6f641e 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -34,8 +34,8 @@ BOOST_AUTO_TEST_CASE(skiplist_test) } for (int i=0; i < 1000; i++) { - int from = InsecureRandRange(SKIPLIST_LENGTH - 1); - int to = InsecureRandRange(from + 1); + int from = m_rng.randrange(SKIPLIST_LENGTH - 1); + int to = m_rng.randrange(from + 1); BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]); BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]); @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test) // Test 100 random starting points for locators. for (int n=0; n<100; n++) { - int r = InsecureRandRange(150000); + int r = m_rng.randrange(150000); CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000]; CBlockLocator locator = GetLocator(tip); @@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test) } else { // randomly choose something in the range [MTP, MTP*2] int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast(); - int r{int(InsecureRandRange(medianTimePast))}; + int r{int(m_rng.randrange(medianTimePast))}; vBlocksMain[i].nTime = uint32_t(r + medianTimePast); vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax); } @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test) // Verify that FindEarliestAtLeast is correct. for (unsigned int i=0; i<10000; ++i) { // Pick a random element in vBlocksMain. - int r = InsecureRandRange(vBlocksMain.size()); + int r = m_rng.randrange(vBlocksMain.size()); int64_t test_time = vBlocksMain[r].nTime; CBlockIndex* ret = chain.FindEarliestAtLeast(test_time, 0); BOOST_CHECK(ret->nTimeMax >= test_time); diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index e666e11758..777122df6d 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"; @@ -262,7 +261,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file) for (uint8_t j = 0; j < 40; ++j) { file << j; } - std::rewind(file.Get()); + file.seek(0, SEEK_SET); // The buffer size (second arg) must be greater than the rewind // amount (third arg). @@ -392,7 +391,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_skip) for (uint8_t j = 0; j < 40; ++j) { file << j; } - std::rewind(file.Get()); + file.seek(0, SEEK_SET); // The buffer is 25 bytes, allow rewinding 10 bytes. BufferedFile bf{file, 25, 10}; @@ -436,19 +435,19 @@ 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) { AutoFile file{fsbridge::fopen(streams_test_filename, "w+b")}; - size_t fileSize = InsecureRandRange(256); + size_t fileSize = m_rng.randrange(256); for (uint8_t i = 0; i < fileSize; ++i) { file << i; } - std::rewind(file.Get()); + file.seek(0, SEEK_SET); - size_t bufSize = InsecureRandRange(300) + 1; - size_t rewindSize = InsecureRandRange(bufSize); + size_t bufSize = m_rng.randrange(300) + 1; + size_t rewindSize = m_rng.randrange(bufSize); BufferedFile bf{file, bufSize, rewindSize}; size_t currentPos = 0; size_t maxPos = 0; @@ -464,7 +463,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) // sizes; the boundaries of the objects can interact arbitrarily // with the CBufferFile's internal buffer. These first three // cases simulate objects of various sizes (1, 2, 5 bytes). - switch (InsecureRandRange(6)) { + switch (m_rng.randrange(6)) { case 0: { uint8_t a[1]; if (currentPos + 1 > fileSize) @@ -504,7 +503,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) case 3: { // SkipTo is similar to the "read" cases above, except // we don't receive the data. - size_t skip_length{static_cast<size_t>(InsecureRandRange(5))}; + size_t skip_length{static_cast<size_t>(m_rng.randrange(5))}; if (currentPos + skip_length > fileSize) continue; bf.SetLimit(currentPos + skip_length); bf.SkipTo(currentPos + skip_length); @@ -513,7 +512,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) } case 4: { // Find a byte value (that is at or ahead of the current position). - size_t find = currentPos + InsecureRandRange(8); + size_t find = currentPos + m_rng.randrange(8); if (find >= fileSize) find = fileSize - 1; bf.FindByte(std::byte(find)); @@ -529,7 +528,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) break; } case 5: { - size_t requestPos = InsecureRandRange(maxPos + 4); + size_t requestPos = m_rng.randrange(maxPos + 4); bool okay = bf.SetPos(requestPos); // The new position may differ from the requested position // because we may not be able to rewind beyond the rewind diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index baa759e42c..a5d9be07d5 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. // -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <test/util/setup_common.h> #include <common/run_command.h> #include <univalue.h> @@ -16,13 +16,6 @@ BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup) -// At least one test is required (in case ENABLE_EXTERNAL_SIGNER is not defined). -// Workaround for https://github.com/bitcoin/bitcoin/issues/19128 -BOOST_AUTO_TEST_CASE(dummy) -{ - BOOST_CHECK(true); -} - #ifdef ENABLE_EXTERNAL_SIGNER BOOST_AUTO_TEST_CASE(run_command) @@ -54,8 +47,8 @@ BOOST_AUTO_TEST_CASE(run_command) } { // Return non-zero exit code, with error message for stderr - const std::string command{"ls nosuchfile"}; - const std::string expected{"No such file or directory"}; + const std::string command{"sh -c 'echo err 1>&2 && false'"}; + const std::string expected{"err"}; BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) { const std::string what(e.what()); BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned", command)) != std::string::npos); diff --git a/src/test/timeoffsets_tests.cpp b/src/test/timeoffsets_tests.cpp index 008f1a9db9..5f85a5feeb 100644 --- a/src/test/timeoffsets_tests.cpp +++ b/src/test/timeoffsets_tests.cpp @@ -4,6 +4,7 @@ // #include <node/timeoffsets.h> +#include <node/warnings.h> #include <test/util/setup_common.h> #include <boost/test/unit_test.hpp> @@ -24,7 +25,8 @@ BOOST_FIXTURE_TEST_SUITE(timeoffsets_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(timeoffsets) { - TimeOffsets offsets{}; + node::Warnings warnings{}; + TimeOffsets offsets{warnings}; BOOST_CHECK(offsets.Median() == 0s); AddMulti(offsets, {{0s, -1s, -2s, -3s}}); @@ -50,7 +52,8 @@ BOOST_AUTO_TEST_CASE(timeoffsets) static bool IsWarningRaised(const std::vector<std::chrono::seconds>& check_offsets) { - TimeOffsets offsets{}; + node::Warnings warnings{}; + TimeOffsets offsets{warnings}; AddMulti(offsets, check_offsets); return offsets.WarnIfOutOfSync(); } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index e6cf64611e..3430a5bbfa 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> @@ -38,6 +39,10 @@ #include <univalue.h> +using namespace util::hex_literals; +using util::SplitString; +using util::ToString; + typedef std::vector<unsigned char> valtype; static CFeeRate g_dust{DUST_RELAY_TX_FEE}; @@ -69,17 +74,16 @@ static std::map<std::string, unsigned int> mapFlagNames = { unsigned int ParseScriptFlags(std::string strFlags) { - if (strFlags.empty() || strFlags == "NONE") return 0; - unsigned int flags = 0; - std::vector<std::string> words = SplitString(strFlags, ','); + unsigned int flags = SCRIPT_VERIFY_NONE; + if (strFlags.empty() || strFlags == "NONE") return flags; + std::vector<std::string> words = SplitString(strFlags, ','); for (const std::string& word : words) { if (!mapFlagNames.count(word)) BOOST_ERROR("Bad test: unknown verification flag '" << word << "'"); flags |= mapFlagNames[word]; } - return flags; } @@ -95,7 +99,7 @@ bool CheckMapFlagNames() std::string FormatScriptFlags(unsigned int flags) { - if (flags == 0) { + if (flags == SCRIPT_VERIFY_NONE) { return ""; } std::string ret; @@ -220,7 +224,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) { @@ -260,7 +264,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest); } // Removing random combinations of flags - flags = TrimFlags(~(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size()))); + flags = TrimFlags(~(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size()))); if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) { BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags) << ": " << strTest); } @@ -308,7 +312,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) { @@ -351,7 +355,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest); } // Adding random combinations of flags - flags = FillFlags(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size())); + flags = FillFlags(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size())); if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) { BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest); } @@ -367,6 +371,41 @@ BOOST_AUTO_TEST_CASE(tx_invalid) } } +BOOST_AUTO_TEST_CASE(tx_no_inputs) +{ + CMutableTransaction empty; + + TxValidationState state; + BOOST_CHECK_MESSAGE(!CheckTransaction(CTransaction(empty), state), "Transaction with no inputs should be invalid."); + BOOST_CHECK(state.GetRejectReason() == "bad-txns-vin-empty"); +} + +BOOST_AUTO_TEST_CASE(tx_oversized) +{ + auto createTransaction =[](size_t payloadSize) { + CMutableTransaction tx; + tx.vin.resize(1); + tx.vout.emplace_back(1, CScript() << OP_RETURN << std::vector<unsigned char>(payloadSize)); + return CTransaction(tx); + }; + const auto maxTransactionSize = MAX_BLOCK_WEIGHT / WITNESS_SCALE_FACTOR; + const auto oversizedTransactionBaseSize = ::GetSerializeSize(TX_NO_WITNESS(createTransaction(maxTransactionSize))) - maxTransactionSize; + + auto maxPayloadSize = maxTransactionSize - oversizedTransactionBaseSize; + { + TxValidationState state; + CheckTransaction(createTransaction(maxPayloadSize), state); + BOOST_CHECK(state.GetRejectReason() != "bad-txns-oversize"); + } + + maxPayloadSize += 1; + { + TxValidationState state; + BOOST_CHECK_MESSAGE(!CheckTransaction(createTransaction(maxPayloadSize), state), "Oversized transaction should be invalid"); + BOOST_CHECK(state.GetRejectReason() == "bad-txns-oversize"); + } +} + BOOST_AUTO_TEST_CASE(basic_transaction_tests) { // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) @@ -412,7 +451,7 @@ BOOST_AUTO_TEST_CASE(test_Get) static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true) { CMutableTransaction outputm; - outputm.nVersion = 1; + outputm.version = 1; outputm.vin.resize(1); outputm.vin[0].prevout.SetNull(); outputm.vin[0].scriptSig = CScript(); @@ -428,7 +467,7 @@ static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const assert(output->vout[0] == outputm.vout[0]); CMutableTransaction inputm; - inputm.nVersion = 1; + inputm.version = 1; inputm.vin.resize(1); inputm.vin[0].prevout.hash = output->GetHash(); inputm.vin[0].prevout.n = 0; @@ -485,7 +524,7 @@ static void ReplaceRedeemScript(CScript& script, const CScript& redeemScript) BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { CMutableTransaction mtx; - mtx.nVersion = 1; + mtx.version = 1; CKey key = GenerateRandomKey(); // Need to use compressed keys in segwit or the signing will fail FillableSigningProvider keystore; @@ -504,7 +543,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; @@ -541,9 +580,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)); } @@ -612,11 +653,11 @@ BOOST_AUTO_TEST_CASE(test_witness) // Normal pay-to-compressed-pubkey. CreateCreditAndSpend(keystore, scriptPubkey1, output1, input1); CreateCreditAndSpend(keystore, scriptPubkey2, output2, input2); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); - CheckWithFlag(output1, input2, 0, false); + CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, false); CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); @@ -625,11 +666,11 @@ BOOST_AUTO_TEST_CASE(test_witness) CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1)), output1, input1); CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2)), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); - CheckWithFlag(output1, input2, 0, true); + CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); @@ -637,11 +678,11 @@ BOOST_AUTO_TEST_CASE(test_witness) // Witness pay-to-compressed-pubkey (v0). CreateCreditAndSpend(keystore, destination_script_1, output1, input1); CreateCreditAndSpend(keystore, destination_script_2, output2, input2); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); - CheckWithFlag(output1, input2, 0, true); + CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); @@ -650,11 +691,11 @@ BOOST_AUTO_TEST_CASE(test_witness) CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(destination_script_1)), output1, input1); CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(destination_script_2)), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, destination_script_1); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); - CheckWithFlag(output1, input2, 0, true); + CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); @@ -662,11 +703,11 @@ BOOST_AUTO_TEST_CASE(test_witness) // Normal pay-to-uncompressed-pubkey. CreateCreditAndSpend(keystore, scriptPubkey1L, output1, input1); CreateCreditAndSpend(keystore, scriptPubkey2L, output2, input2); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); - CheckWithFlag(output1, input2, 0, false); + CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, false); CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); @@ -675,11 +716,11 @@ BOOST_AUTO_TEST_CASE(test_witness) CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1L)), output1, input1); CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2L)), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1L); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); - CheckWithFlag(output1, input2, 0, true); + CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); @@ -694,19 +735,19 @@ BOOST_AUTO_TEST_CASE(test_witness) // Normal 2-of-2 multisig CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false); - CheckWithFlag(output1, input1, 0, false); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, false); CreateCreditAndSpend(keystore2, scriptMulti, output2, input2, false); - CheckWithFlag(output2, input2, 0, false); + CheckWithFlag(output2, input2, SCRIPT_VERIFY_NONE, false); BOOST_CHECK(*output1 == *output2); UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1)); CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); // P2SH 2-of-2 multisig CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptMulti)), output1, input1, false); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, false); CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(scriptMulti)), output2, input2, false); - CheckWithFlag(output2, input2, 0, true); + CheckWithFlag(output2, input2, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false); BOOST_CHECK(*output1 == *output2); UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1)); @@ -715,10 +756,10 @@ BOOST_AUTO_TEST_CASE(test_witness) // Witness 2-of-2 multisig CreateCreditAndSpend(keystore, destination_script_multi, output1, input1, false); - CheckWithFlag(output1, input1, 0, true); + CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); CreateCreditAndSpend(keystore2, destination_script_multi, output2, input2, false); - CheckWithFlag(output2, input2, 0, true); + CheckWithFlag(output2, input2, SCRIPT_VERIFY_NONE, true); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); BOOST_CHECK(*output1 == *output2); UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1)); @@ -779,21 +820,21 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].nValue = nDustThreshold; CheckIsStandard(t); - // Disallowed nVersion - t.nVersion = -1; + // Disallowed version + t.version = std::numeric_limits<uint32_t>::max(); CheckIsNotStandard(t, "version"); - t.nVersion = 0; + t.version = 0; CheckIsNotStandard(t, "version"); - t.nVersion = TX_MAX_STANDARD_VERSION + 1; + t.version = TX_MAX_STANDARD_VERSION + 1; CheckIsNotStandard(t, "version"); - // Allowed nVersion - t.nVersion = 1; + // Allowed version + t.version = 1; CheckIsStandard(t); - t.nVersion = 2; + t.version = 2; CheckIsStandard(t); // Check dust with odd relay fee to verify rounding: @@ -811,24 +852,24 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) CheckIsNotStandard(t, "scriptpubkey"); // MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard) - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size()); CheckIsStandard(t); // MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard) - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"_hex; BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size()); CheckIsNotStandard(t, "scriptpubkey"); // Data payload can be encoded in any way... - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex(""); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << ""_hex; CheckIsStandard(t); - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01"); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << "00"_hex << "01"_hex; CheckIsStandard(t); // OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()! - t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << ParseHex("01") << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16; + t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << "01"_hex << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16; CheckIsStandard(t); - t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex("01") << 2 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << "01"_hex << 2 << "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"_hex; CheckIsStandard(t); // ...so long as it only contains PUSHDATA's @@ -842,13 +883,13 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) // Only one TxoutType::NULL_DATA permitted in all cases t.vout.resize(2); - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; t.vout[0].nValue = 0; - t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; t.vout[1].nValue = 0; CheckIsNotStandard(t, "multi-op-return"); - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; t.vout[1].scriptPubKey = CScript() << OP_RETURN; CheckIsNotStandard(t, "multi-op-return"); @@ -904,15 +945,15 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vin.clear(); t.vin.resize(2438); // size per input (empty scriptSig): 41 bytes t.vout[0].scriptPubKey = CScript() << OP_RETURN << std::vector<unsigned char>(19, 0); // output size: 30 bytes - // tx header: 12 bytes => 48 vbytes - // 2438 inputs: 2438*41 = 99958 bytes => 399832 vbytes - // 1 output: 30 bytes => 120 vbytes - // =============================== - // total: 400000 vbytes + // tx header: 12 bytes => 48 weight units + // 2438 inputs: 2438*41 = 99958 bytes => 399832 weight units + // 1 output: 30 bytes => 120 weight units + // ====================================== + // total: 400000 weight units BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(t)), 400000); CheckIsStandard(t); - // increase output size by one byte, so we end up with 400004 vbytes + // increase output size by one byte, so we end up with 400004 weight units t.vout[0].scriptPubKey = CScript() << OP_RETURN << std::vector<unsigned char>(20, 0); // output size: 31 bytes BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(t)), 400004); CheckIsNotStandard(t, "tx-size"); @@ -986,6 +1027,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/txindex_tests.cpp b/src/test/txindex_tests.cpp index 5a32b02ad9..9ee5387830 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -33,7 +33,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) BOOST_REQUIRE(txindex.StartBackgroundSync()); // Allow tx index to catch up with the block index. - IndexWaitSynced(txindex, *Assert(m_node.shutdown)); + IndexWaitSynced(txindex, *Assert(m_node.shutdown_signal)); // Check that txindex excludes genesis block transactions. const CBlock& genesis_block = Params().GenesisBlock(); diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp index 55e0c5f285..ea211aedf3 100644 --- a/src/test/txpackage_tests.cpp +++ b/src/test/txpackage_tests.cpp @@ -6,6 +6,7 @@ #include <key_io.h> #include <policy/packages.h> #include <policy/policy.h> +#include <policy/rbf.h> #include <primitives/transaction.h> #include <script/script.h> #include <serialize.h> @@ -19,20 +20,22 @@ #include <boost/test/unit_test.hpp> -BOOST_AUTO_TEST_SUITE(txpackage_tests) +using namespace util::hex_literals; + // A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these // unit tests. static const CAmount low_fee_amt{200}; +struct TxPackageTest : TestChain100Setup { // Create placeholder transactions that have no meaning. inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs) { CMutableTransaction mtx = CMutableTransaction(); mtx.vin.resize(num_inputs); mtx.vout.resize(num_outputs); - auto random_script = CScript() << ToByteVector(InsecureRand256()) << ToByteVector(InsecureRand256()); + auto random_script = CScript() << ToByteVector(m_rng.rand256()) << ToByteVector(m_rng.rand256()); for (size_t i{0}; i < num_inputs; ++i) { - mtx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256()); + mtx.vin[i].prevout.hash = Txid::FromUint256(m_rng.rand256()); mtx.vin[i].prevout.n = 0; mtx.vin[i].scriptSig = random_script; } @@ -42,40 +45,37 @@ inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outpu } return MakeTransactionRef(mtx); } +}; // struct TxPackageTest -// Create a Wtxid from a hex string -inline Wtxid WtxidFromString(std::string_view str) -{ - return Wtxid::FromUint256(uint256S(str.data())); -} +BOOST_FIXTURE_TEST_SUITE(txpackage_tests, TxPackageTest) -BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_hash_tests) { // Random real segwit transaction DataStream stream_1{ - ParseHex("02000000000101964b8aa63509579ca6086e6012eeaa4c2f4dd1e283da29b67c8eea38b3c6fd220000000000fdffffff0294c618000000000017a9145afbbb42f4e83312666d0697f9e66259912ecde38768fa2c0000000000160014897388a0889390fd0e153a22bb2cf9d8f019faf50247304402200547406380719f84d68cf4e96cc3e4a1688309ef475b150be2b471c70ea562aa02206d255f5acc40fd95981874d77201d2eb07883657ce1c796513f32b6079545cdf0121023ae77335cefcb5ab4c1dc1fb0d2acfece184e593727d7d5906c78e564c7c11d125cf0c00"), + "02000000000101964b8aa63509579ca6086e6012eeaa4c2f4dd1e283da29b67c8eea38b3c6fd220000000000fdffffff0294c618000000000017a9145afbbb42f4e83312666d0697f9e66259912ecde38768fa2c0000000000160014897388a0889390fd0e153a22bb2cf9d8f019faf50247304402200547406380719f84d68cf4e96cc3e4a1688309ef475b150be2b471c70ea562aa02206d255f5acc40fd95981874d77201d2eb07883657ce1c796513f32b6079545cdf0121023ae77335cefcb5ab4c1dc1fb0d2acfece184e593727d7d5906c78e564c7c11d125cf0c00"_hex, }; CTransaction tx_1(deserialize, TX_WITH_WITNESS, stream_1); CTransactionRef ptx_1{MakeTransactionRef(tx_1)}; // Random real nonsegwit transaction DataStream stream_2{ - ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"), + "01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"_hex, }; CTransaction tx_2(deserialize, TX_WITH_WITNESS, stream_2); CTransactionRef ptx_2{MakeTransactionRef(tx_2)}; // Random real segwit transaction DataStream stream_3{ - ParseHex("0200000000010177862801f77c2c068a70372b4c435ef8dd621291c36a64eb4dd491f02218f5324600000000fdffffff014a0100000000000022512035ea312034cfac01e956a269f3bf147f569c2fbb00180677421262da042290d803402be713325ff285e66b0380f53f2fae0d0fb4e16f378a440fed51ce835061437566729d4883bc917632f3cff474d6384bc8b989961a1d730d4a87ed38ad28bd337b20f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7fac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800357b2270223a226272632d3230222c226f70223a226d696e74222c227469636b223a224342414c222c22616d74223a2236393639227d6821c1f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7f00000000"), + "0200000000010177862801f77c2c068a70372b4c435ef8dd621291c36a64eb4dd491f02218f5324600000000fdffffff014a0100000000000022512035ea312034cfac01e956a269f3bf147f569c2fbb00180677421262da042290d803402be713325ff285e66b0380f53f2fae0d0fb4e16f378a440fed51ce835061437566729d4883bc917632f3cff474d6384bc8b989961a1d730d4a87ed38ad28bd337b20f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7fac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800357b2270223a226272632d3230222c226f70223a226d696e74222c227469636b223a224342414c222c22616d74223a2236393639227d6821c1f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7f00000000"_hex, }; CTransaction tx_3(deserialize, TX_WITH_WITNESS, stream_3); 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); @@ -84,9 +84,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); @@ -130,7 +130,7 @@ BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup) BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_321)); } -BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_sanitization_tests) { // Packages can't have more than 25 transactions. Package package_too_many; @@ -173,7 +173,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) // Packages can't have transactions spending the same prevout CMutableTransaction tx_zero_1; CMutableTransaction tx_zero_2; - COutPoint same_prevout{Txid::FromUint256(InsecureRand256()), 0}; + COutPoint same_prevout{Txid::FromUint256(m_rng.rand256()), 0}; tx_zero_1.vin.emplace_back(same_prevout); tx_zero_2.vin.emplace_back(same_prevout); // Different vouts (not the same tx) @@ -191,7 +191,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) // IsConsistentPackage only cares about conflicts between transactions, not about a transaction // conflicting with itself (i.e. duplicate prevouts in vin). CMutableTransaction dup_tx; - const COutPoint rand_prevout{Txid::FromUint256(InsecureRand256()), 0}; + const COutPoint rand_prevout{Txid::FromUint256(m_rng.rand256()), 0}; dup_tx.vin.emplace_back(rand_prevout); dup_tx.vin.emplace_back(rand_prevout); Package package_with_dup_tx{MakeTransactionRef(dup_tx)}; @@ -200,7 +200,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) BOOST_CHECK(IsConsistentPackage(package_with_dup_tx)); } -BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_validation_tests) { LOCK(cs_main); unsigned int initialPoolSize = m_node.mempool->size(); @@ -255,7 +255,7 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize); } -BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(noncontextual_package_tests) { // The signatures won't be verified so we can just use a placeholder CKey placeholder_key = GenerateRandomKey(); @@ -302,7 +302,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; @@ -351,7 +351,7 @@ BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup) } } -BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_submission_tests) { LOCK(cs_main); unsigned int expected_pool_size = m_node.mempool->size(); @@ -494,7 +494,7 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) // Tests for packages containing transactions that have same-txid-different-witness equivalents in // the mempool. -BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_witness_swap_tests) { // Mine blocks to mature coinbases. mineBlocks(5); @@ -523,7 +523,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) CKey child_key = GenerateRandomKey(); CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey())); CMutableTransaction mtx_child1; - mtx_child1.nVersion = 1; + mtx_child1.version = 1; mtx_child1.vin.resize(1); mtx_child1.vin[0].prevout.hash = ptx_parent->GetHash(); mtx_child1.vin[0].prevout.n = 0; @@ -651,7 +651,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) CTransactionRef ptx_grandparent2 = MakeTransactionRef(mtx_grandparent2); CMutableTransaction mtx_parent2_v1; - mtx_parent2_v1.nVersion = 1; + mtx_parent2_v1.version = 1; mtx_parent2_v1.vin.resize(1); mtx_parent2_v1.vin[0].prevout.hash = ptx_grandparent2->GetHash(); mtx_parent2_v1.vin[0].prevout.n = 0; @@ -728,7 +728,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) } } -BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_cpfp_tests) { mineBlocks(5); MockMempoolMinFee(CFeeRate(5000)); @@ -938,4 +938,147 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); } } + +BOOST_AUTO_TEST_CASE(package_rbf_tests) +{ + mineBlocks(5); + LOCK(::cs_main); + size_t expected_pool_size = m_node.mempool->size(); + CKey child_key{GenerateRandomKey()}; + CScript parent_spk = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey())); + CKey grandchild_key{GenerateRandomKey()}; + CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey())); + + const CAmount coinbase_value{50 * COIN}; + // Test that de-duplication works. This is not actually package rbf. + { + // 1 parent paying 200sat, 1 child paying 300sat + Package package1; + // 1 parent paying 200sat, 1 child paying 500sat + Package package2; + // Package1 and package2 have the same parent. The children conflict. + auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0, + /*input_height=*/0, /*input_signing_key=*/coinbaseKey, + /*output_destination=*/parent_spk, + /*output_amount=*/coinbase_value - low_fee_amt, /*submit=*/false); + CTransactionRef tx_parent = MakeTransactionRef(mtx_parent); + package1.push_back(tx_parent); + package2.push_back(tx_parent); + + CTransactionRef tx_child_1 = MakeTransactionRef(CreateValidMempoolTransaction(tx_parent, 0, 101, child_key, child_spk, coinbase_value - low_fee_amt - 300, false)); + package1.push_back(tx_child_1); + CTransactionRef tx_child_2 = MakeTransactionRef(CreateValidMempoolTransaction(tx_parent, 0, 101, child_key, child_spk, coinbase_value - low_fee_amt - 500, false)); + package2.push_back(tx_child_2); + + LOCK(m_node.mempool->cs); + const auto submit1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, /*test_accept=*/false, std::nullopt); + if (auto err_1{CheckPackageMempoolAcceptResult(package1, submit1, /*expect_valid=*/true, m_node.mempool.get())}) { + BOOST_ERROR(err_1.value()); + } + + // Check precise ResultTypes and mempool size. We know it_parent_1 and it_child_1 exist from above call + auto it_parent_1 = submit1.m_tx_results.find(tx_parent->GetWitnessHash()); + auto it_child_1 = submit1.m_tx_results.find(tx_child_1->GetWitnessHash()); + BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + expected_pool_size += 2; + BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); + + const auto submit2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package2, /*test_accept=*/false, std::nullopt); + if (auto err_2{CheckPackageMempoolAcceptResult(package2, submit2, /*expect_valid=*/true, m_node.mempool.get())}) { + BOOST_ERROR(err_2.value()); + } + + // Check precise ResultTypes and mempool size. We know it_parent_2 and it_child_2 exist from above call + auto it_parent_2 = submit2.m_tx_results.find(tx_parent->GetWitnessHash()); + auto it_child_2 = submit2.m_tx_results.find(tx_child_2->GetWitnessHash()); + BOOST_CHECK_EQUAL(it_parent_2->second.m_result_type, MempoolAcceptResult::ResultType::MEMPOOL_ENTRY); + BOOST_CHECK_EQUAL(it_child_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); + + // child1 has been replaced + BOOST_CHECK(!m_node.mempool->exists(GenTxid::Txid(tx_child_1->GetHash()))); + } + + // Test package rbf. + { + CTransactionRef tx_parent_1 = MakeTransactionRef(CreateValidMempoolTransaction( + m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0, + coinbaseKey, parent_spk, coinbase_value - 200, /*submit=*/false)); + CTransactionRef tx_child_1 = MakeTransactionRef(CreateValidMempoolTransaction( + tx_parent_1, /*input_vout=*/0, /*input_height=*/101, + child_key, child_spk, coinbase_value - 400, /*submit=*/false)); + + CTransactionRef tx_parent_2 = MakeTransactionRef(CreateValidMempoolTransaction( + m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0, + coinbaseKey, parent_spk, coinbase_value - 800, /*submit=*/false)); + CTransactionRef tx_child_2 = MakeTransactionRef(CreateValidMempoolTransaction( + tx_parent_2, /*input_vout=*/0, /*input_height=*/101, + child_key, child_spk, coinbase_value - 800 - 200, /*submit=*/false)); + + CTransactionRef tx_parent_3 = MakeTransactionRef(CreateValidMempoolTransaction( + m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0, + coinbaseKey, parent_spk, coinbase_value - 199, /*submit=*/false)); + CTransactionRef tx_child_3 = MakeTransactionRef(CreateValidMempoolTransaction( + tx_parent_3, /*input_vout=*/0, /*input_height=*/101, + child_key, child_spk, coinbase_value - 199 - 1300, /*submit=*/false)); + + // In all packages, the parents conflict with each other + BOOST_CHECK(tx_parent_1->GetHash() != tx_parent_2->GetHash() && tx_parent_2->GetHash() != tx_parent_3->GetHash()); + + // 1 parent paying 200sat, 1 child paying 200sat. + Package package1{tx_parent_1, tx_child_1}; + // 1 parent paying 800sat, 1 child paying 200sat. + Package package2{tx_parent_2, tx_child_2}; + // 1 parent paying 199sat, 1 child paying 1300sat. + Package package3{tx_parent_3, tx_child_3}; + + const auto submit1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, false, std::nullopt); + if (auto err_1{CheckPackageMempoolAcceptResult(package1, submit1, /*expect_valid=*/true, m_node.mempool.get())}) { + BOOST_ERROR(err_1.value()); + } + auto it_parent_1 = submit1.m_tx_results.find(tx_parent_1->GetWitnessHash()); + auto it_child_1 = submit1.m_tx_results.find(tx_child_1->GetWitnessHash()); + BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + expected_pool_size += 2; + BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); + + // This replacement is actually not package rbf; the parent carries enough fees + // to replace the entire package on its own. + const auto submit2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package2, false, std::nullopt); + if (auto err_2{CheckPackageMempoolAcceptResult(package2, submit2, /*expect_valid=*/true, m_node.mempool.get())}) { + BOOST_ERROR(err_2.value()); + } + auto it_parent_2 = submit2.m_tx_results.find(tx_parent_2->GetWitnessHash()); + auto it_child_2 = submit2.m_tx_results.find(tx_child_2->GetWitnessHash()); + BOOST_CHECK_EQUAL(it_parent_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK_EQUAL(it_child_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); + + // Package RBF, in which the replacement transaction's child sponsors the fees to meet RBF feerate rules + const auto submit3 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package3, false, std::nullopt); + if (auto err_3{CheckPackageMempoolAcceptResult(package3, submit3, /*expect_valid=*/true, m_node.mempool.get())}) { + BOOST_ERROR(err_3.value()); + } + auto it_parent_3 = submit3.m_tx_results.find(tx_parent_3->GetWitnessHash()); + auto it_child_3 = submit3.m_tx_results.find(tx_child_3->GetWitnessHash()); + BOOST_CHECK_EQUAL(it_parent_3->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK_EQUAL(it_child_3->second.m_result_type, MempoolAcceptResult::ResultType::VALID); + + // package3 was considered as a package to replace both package2 transactions + BOOST_CHECK(it_parent_3->second.m_replaced_transactions.size() == 2); + BOOST_CHECK(it_child_3->second.m_replaced_transactions.empty()); + + std::vector<Wtxid> expected_package3_wtxids({tx_parent_3->GetWitnessHash(), tx_child_3->GetWitnessHash()}); + const auto package3_total_vsize{GetVirtualTransactionSize(*tx_parent_3) + GetVirtualTransactionSize(*tx_child_3)}; + BOOST_CHECK(it_parent_3->second.m_wtxids_fee_calculations.value() == expected_package3_wtxids); + BOOST_CHECK(it_child_3->second.m_wtxids_fee_calculations.value() == expected_package3_wtxids); + BOOST_CHECK_EQUAL(it_parent_3->second.m_effective_feerate.value().GetFee(package3_total_vsize), 199 + 1300); + BOOST_CHECK_EQUAL(it_child_3->second.m_effective_feerate.value().GetFee(package3_total_vsize), 199 + 1300); + + BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); + } + +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp index dc257a0d51..6bb732ba69 100644 --- a/src/test/txrequest_tests.cpp +++ b/src/test/txrequest_tests.cpp @@ -15,10 +15,23 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(txrequest_tests, BasicTestingSetup) - namespace { +class Scenario; + +struct TxRequestTest : BasicTestingSetup { + std::chrono::microseconds RandomTime8s(); + std::chrono::microseconds RandomTime1y(); + void BuildSingleTest(Scenario& scenario, int config); + void BuildPriorityTest(Scenario& scenario, int config); + void BuildBigPriorityTest(Scenario& scenario, int peers); + void BuildRequestOrderTest(Scenario& scenario, int config); + void BuildWtxidTest(Scenario& scenario, int config); + void BuildTimeBackwardsTest(Scenario& scenario); + void BuildWeirdRequestsTest(Scenario& scenario); + void TestInterleavedScenarios(); +}; + constexpr std::chrono::microseconds MIN_TIME = std::chrono::microseconds::min(); constexpr std::chrono::microseconds MAX_TIME = std::chrono::microseconds::max(); constexpr std::chrono::microseconds MICROSECOND = std::chrono::microseconds{1}; @@ -51,8 +64,8 @@ struct Runner std::multiset<std::pair<NodeId, GenTxid>> expired; }; -std::chrono::microseconds RandomTime8s() { return std::chrono::microseconds{1 + InsecureRandBits(23)}; } -std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 + InsecureRandBits(45)}; } +std::chrono::microseconds TxRequestTest::RandomTime8s() { return std::chrono::microseconds{1 + m_rng.randbits(23)}; } +std::chrono::microseconds TxRequestTest::RandomTime1y() { return std::chrono::microseconds{1 + m_rng.randbits(45)}; } /** A proxy for a Runner that helps build a sequence of consecutive test actions on a TxRequestTracker. * @@ -65,12 +78,13 @@ std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 + */ class Scenario { + FastRandomContext& m_rng; Runner& m_runner; std::chrono::microseconds m_now; std::string m_testname; public: - Scenario(Runner& runner, std::chrono::microseconds starttime) : m_runner(runner), m_now(starttime) {} + Scenario(FastRandomContext& rng, Runner& runner, std::chrono::microseconds starttime) : m_rng(rng), m_runner(runner), m_now(starttime) {} /** Set a name for the current test, to give more clear error messages. */ void SetTestName(std::string testname) @@ -199,7 +213,7 @@ public: uint256 ret; bool ok; do { - ret = InsecureRand256(); + ret = m_rng.rand256(); ok = true; for (const auto& order : orders) { for (size_t pos = 1; pos < order.size(); ++pos) { @@ -222,7 +236,7 @@ public: /** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */ GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {}) { - return InsecureRandBool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders)); + return m_rng.randbool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders)); } /** Generate a new random NodeId to use as peer. The same NodeId is never returned twice @@ -232,7 +246,7 @@ public: bool ok; NodeId ret; do { - ret = InsecureRandBits(63); + ret = m_rng.randbits(63); ok = m_runner.peerset.insert(ret).second; } while(!ok); return ret; @@ -245,7 +259,7 @@ public: * * config is an integer in [0, 32), which controls which variant of the test is used. */ -void BuildSingleTest(Scenario& scenario, int config) +void TxRequestTest::BuildSingleTest(Scenario& scenario, int config) { auto peer = scenario.NewPeer(); auto gtxid = scenario.NewGTxid(); @@ -282,7 +296,7 @@ void BuildSingleTest(Scenario& scenario, int config) scenario.CheckExpired(peer, gtxid); return; } else { - scenario.AdvanceTime(std::chrono::microseconds{InsecureRandRange(expiry.count())}); + scenario.AdvanceTime(std::chrono::microseconds{m_rng.randrange(expiry.count())}); scenario.Check(peer, {}, 0, 1, 0, "s9"); if ((config >> 3) == 3) { // A response will arrive for the transaction scenario.ReceivedResponse(peer, gtxid.GetHash()); @@ -305,7 +319,7 @@ void BuildSingleTest(Scenario& scenario, int config) * * config is an integer in [0, 32), which controls which variant of the test is used. */ -void BuildPriorityTest(Scenario& scenario, int config) +void TxRequestTest::BuildPriorityTest(Scenario& scenario, int config) { scenario.SetTestName(strprintf("Priority(config=%i)", config)); @@ -319,7 +333,7 @@ void BuildPriorityTest(Scenario& scenario, int config) scenario.ReceivedInv(peer1, gtxid, pref1, MIN_TIME); scenario.Check(peer1, {gtxid}, 1, 0, 0, "p1"); - if (InsecureRandBool()) { + if (m_rng.randbool()) { scenario.AdvanceTime(RandomTime8s()); scenario.Check(peer1, {gtxid}, 1, 0, 0, "p2"); } @@ -335,7 +349,7 @@ void BuildPriorityTest(Scenario& scenario, int config) NodeId priopeer = stage2_prio ? peer2 : peer1, otherpeer = stage2_prio ? peer1 : peer2; scenario.Check(otherpeer, {}, 1, 0, 0, "p3"); scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p4"); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.Check(otherpeer, {}, 1, 0, 0, "p5"); scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p6"); @@ -344,7 +358,7 @@ void BuildPriorityTest(Scenario& scenario, int config) scenario.RequestedTx(priopeer, gtxid.GetHash(), MAX_TIME); scenario.Check(priopeer, {}, 0, 1, 0, "p7"); scenario.Check(otherpeer, {}, 1, 0, 0, "p8"); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); } // The peer which was selected (or requested from) now goes offline, or a NOTFOUND is received from them. @@ -353,28 +367,28 @@ void BuildPriorityTest(Scenario& scenario, int config) } else { scenario.ReceivedResponse(priopeer, gtxid.GetHash()); } - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.Check(priopeer, {}, 0, 0, !(config & 16), "p8"); scenario.Check(otherpeer, {gtxid}, 1, 0, 0, "p9"); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); // Now the other peer goes offline. scenario.DisconnectedPeer(otherpeer); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.Check(peer1, {}, 0, 0, 0, "p10"); scenario.Check(peer2, {}, 0, 0, 0, "p11"); } /** Add to scenario a randomized test in which N peers announce the same transaction, to verify * the order in which they are requested. */ -void BuildBigPriorityTest(Scenario& scenario, int peers) +void TxRequestTest::BuildBigPriorityTest(Scenario& scenario, int peers) { scenario.SetTestName(strprintf("BigPriority(peers=%i)", peers)); // We will have N peers announce the same transaction. std::map<NodeId, bool> preferred; std::vector<NodeId> pref_peers, npref_peers; - int num_pref = InsecureRandRange(peers + 1) ; // Some preferred, ... + int num_pref = m_rng.randrange(peers + 1) ; // Some preferred, ... int num_npref = peers - num_pref; // some not preferred. for (int i = 0; i < num_pref; ++i) { pref_peers.push_back(scenario.NewPeer()); @@ -392,7 +406,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(), m_rng); // Find a gtxid whose txhash prioritization is consistent with the required ordering within pref_peers and // within npref_peers. @@ -427,11 +441,11 @@ void BuildBigPriorityTest(Scenario& scenario, int peers) // Peers now in random order go offline, or send NOTFOUNDs. At every point in time the new to-be-requested-from // peer should be the best remaining one, so verify this after every response. for (int i = 0; i < peers; ++i) { - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); - const int pos = InsecureRandRange(request_order.size()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); + const int pos = m_rng.randrange(request_order.size()); const auto peer = request_order[pos]; request_order.erase(request_order.begin() + pos); - if (InsecureRandBool()) { + if (m_rng.randbool()) { scenario.DisconnectedPeer(peer); scenario.Check(peer, {}, 0, 0, 0, "b4"); } else { @@ -454,7 +468,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers) * * config is an integer in [0, 4) inclusive, and selects the variant of the test. */ -void BuildRequestOrderTest(Scenario& scenario, int config) +void TxRequestTest::BuildRequestOrderTest(Scenario& scenario, int config) { scenario.SetTestName(strprintf("RequestOrder(config=%i)", config)); @@ -489,7 +503,7 @@ void BuildRequestOrderTest(Scenario& scenario, int config) * * config is an integer in [0, 4) inclusive, and selects the variant of the test used. */ -void BuildWtxidTest(Scenario& scenario, int config) +void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config) { scenario.SetTestName(strprintf("Wtxid(config=%i)", config)); @@ -499,17 +513,17 @@ void BuildWtxidTest(Scenario& scenario, int config) auto txid{GenTxid::Txid(txhash)}; auto wtxid{GenTxid::Wtxid(txhash)}; - auto reqtimeT = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); - auto reqtimeW = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); + auto reqtimeT = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s(); + auto reqtimeW = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s(); // Announce txid first or wtxid first. if (config & 1) { scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW); } else { scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT); } @@ -552,14 +566,14 @@ void BuildWtxidTest(Scenario& scenario, int config) // If a good transaction with either that hash as wtxid or txid arrives, both // announcements are gone. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ForgetTxHash(txhash); scenario.Check(peerT, {}, 0, 0, 0, "w13"); scenario.Check(peerW, {}, 0, 0, 0, "w14"); } /** Add to scenario a test that exercises clocks that go backwards. */ -void BuildTimeBackwardsTest(Scenario& scenario) +void TxRequestTest::BuildTimeBackwardsTest(Scenario& scenario) { auto peer1 = scenario.NewPeer(); auto peer2 = scenario.NewPeer(); @@ -577,13 +591,13 @@ void BuildTimeBackwardsTest(Scenario& scenario) scenario.Check(peer2, {gtxid}, 1, 0, 0, "r4"); // Announce from peer1. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peer1, gtxid, true, MAX_TIME); scenario.Check(peer2, {gtxid}, 1, 0, 0, "r5"); scenario.Check(peer1, {}, 1, 0, 0, "r6"); // Request from peer1. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); auto expiry = scenario.Now() + RandomTime8s(); scenario.RequestedTx(peer1, gtxid.GetHash(), expiry); scenario.Check(peer1, {}, 0, 1, 0, "r7"); @@ -598,14 +612,14 @@ void BuildTimeBackwardsTest(Scenario& scenario) scenario.Check(peer2, {gtxid}, 1, 0, 0, "r12", -MICROSECOND); // Peer2 goes offline, meaning no viable announcements remain. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.DisconnectedPeer(peer2); scenario.Check(peer1, {}, 0, 0, 0, "r13"); scenario.Check(peer2, {}, 0, 0, 0, "r14"); } /** Add to scenario a test that involves RequestedTx() calls for txhashes not returned by GetRequestable. */ -void BuildWeirdRequestsTest(Scenario& scenario) +void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario) { auto peer1 = scenario.NewPeer(); auto peer2 = scenario.NewPeer(); @@ -617,19 +631,19 @@ void BuildWeirdRequestsTest(Scenario& scenario) scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q1"); // Announce gtxid2 by peer2. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peer2, gtxid2, true, MIN_TIME); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q2"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q3"); // We request gtxid2 from *peer1* - no effect. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5"); // Now request gtxid1 from peer1 - marks it as REQUESTED. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); auto expiryA = scenario.Now() + RandomTime8s(); scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA); scenario.Check(peer1, {}, 0, 1, 0, "q6"); @@ -653,25 +667,25 @@ void BuildWeirdRequestsTest(Scenario& scenario) scenario.CheckExpired(peer1, gtxid1); // Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer1, gtxid1.GetHash(), MAX_TIME); scenario.Check(peer1, {}, 0, 0, 1, "q14"); scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15"); // Now announce gtxid2 from peer1. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peer1, gtxid2, true, MIN_TIME); scenario.Check(peer1, {}, 1, 0, 1, "q16"); scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q17"); // And request it from peer1 (weird as peer2 has the preference). - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); scenario.Check(peer1, {}, 0, 1, 1, "q18"); scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19"); // If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer2, gtxid2.GetHash(), MAX_TIME); scenario.Check(peer1, {}, 0, 0, 2, "q20"); scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21"); @@ -682,22 +696,22 @@ void BuildWeirdRequestsTest(Scenario& scenario) scenario.Check(peer2, {}, 0, 0, 0, "q23"); } -void TestInterleavedScenarios() +void TxRequestTest::TestInterleavedScenarios() { // Create a list of functions which add tests to scenarios. std::vector<std::function<void(Scenario&)>> builders; // Add instances of every test, for every configuration. for (int n = 0; n < 64; ++n) { - builders.emplace_back([n](Scenario& scenario){ BuildWtxidTest(scenario, n); }); - builders.emplace_back([n](Scenario& scenario){ BuildRequestOrderTest(scenario, n & 3); }); - builders.emplace_back([n](Scenario& scenario){ BuildSingleTest(scenario, n & 31); }); - builders.emplace_back([n](Scenario& scenario){ BuildPriorityTest(scenario, n & 31); }); - builders.emplace_back([n](Scenario& scenario){ BuildBigPriorityTest(scenario, (n & 7) + 1); }); - builders.emplace_back([](Scenario& scenario){ BuildTimeBackwardsTest(scenario); }); - builders.emplace_back([](Scenario& scenario){ BuildWeirdRequestsTest(scenario); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildWtxidTest(scenario, n); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildRequestOrderTest(scenario, n & 3); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildSingleTest(scenario, n & 31); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildPriorityTest(scenario, n & 31); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildBigPriorityTest(scenario, (n & 7) + 1); }); + builders.emplace_back([this](Scenario& scenario) { BuildTimeBackwardsTest(scenario); }); + builders.emplace_back([this](Scenario& scenario) { BuildWeirdRequestsTest(scenario); }); } // Randomly shuffle all those functions. - Shuffle(builders.begin(), builders.end(), g_insecure_rand_ctx); + std::shuffle(builders.begin(), builders.end(), m_rng); Runner runner; auto starttime = RandomTime1y(); @@ -706,7 +720,7 @@ void TestInterleavedScenarios() // Introduce some variation in the start time of each scenario, so they don't all start off // concurrently, but get a more random interleaving. auto scenario_start = starttime + RandomTime8s() + RandomTime8s() + RandomTime8s(); - Scenario scenario(runner, scenario_start); + Scenario scenario(m_rng, runner, scenario_start); for (int j = 0; builders.size() && j < 10; ++j) { builders.back()(scenario); builders.pop_back(); @@ -730,6 +744,8 @@ void TestInterleavedScenarios() } // namespace +BOOST_FIXTURE_TEST_SUITE(txrequest_tests, TxRequestTest) + BOOST_AUTO_TEST_CASE(TxRequestTest) { for (int i = 0; i < 5; ++i) { diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp index 95583b53bf..97b27ef370 100644 --- a/src/test/txvalidation_tests.cpp +++ b/src/test/txvalidation_tests.cpp @@ -4,9 +4,9 @@ #include <consensus/validation.h> #include <key_io.h> -#include <policy/v3_policy.h> #include <policy/packages.h> #include <policy/policy.h> +#include <policy/truc_policy.h> #include <primitives/transaction.h> #include <random.h> #include <script/script.h> @@ -27,7 +27,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup) CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; CMutableTransaction coinbaseTx; - coinbaseTx.nVersion = 1; + coinbaseTx.version = 1; coinbaseTx.vin.resize(1); coinbaseTx.vout.resize(1); coinbaseTx.vin[0].scriptSig = CScript() << OP_11 << OP_EQUAL; @@ -72,11 +72,11 @@ static inline std::vector<CPubKey> random_keys(size_t num_keys) { return keys; } -// Creates a placeholder tx (not valid) with 25 outputs. Specify the nVersion and the inputs. +// Creates a placeholder tx (not valid) with 25 outputs. Specify the version and the inputs. static inline CTransactionRef make_tx(const std::vector<COutPoint>& inputs, int32_t version) { CMutableTransaction mtx = CMutableTransaction{}; - mtx.nVersion = version; + mtx.version = version; mtx.vin.resize(inputs.size()); mtx.vout.resize(25); for (size_t i{0}; i < inputs.size(); ++i) { @@ -91,7 +91,7 @@ static inline CTransactionRef make_tx(const std::vector<COutPoint>& inputs, int3 BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) { - // Test V3 policy helper functions + // Test TRUC policy helper functions CTxMemPool& pool = *Assert(m_node.mempool); LOCK2(cs_main, pool.cs); TestMemPoolEntryHelper entry; @@ -105,77 +105,77 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) // Default values. CTxMemPool::Limits m_limits{}; - // Cannot spend from an unconfirmed v3 transaction unless this tx is also v3. + // Cannot spend from an unconfirmed TRUC transaction unless this tx is also TRUC. { // mempool_tx_v3 // ^ // tx_v2_from_v3 auto tx_v2_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/2); auto ancestors_v2_from_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v3), m_limits)}; - const auto expected_error_str{strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)", + const auto expected_error_str{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)", tx_v2_from_v3->GetHash().ToString(), tx_v2_from_v3->GetWitnessHash().ToString(), mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())}; - auto result_v2_from_v3{SingleV3Checks(tx_v2_from_v3, *ancestors_v2_from_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v3))}; + auto result_v2_from_v3{SingleTRUCChecks(tx_v2_from_v3, *ancestors_v2_from_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v3))}; BOOST_CHECK_EQUAL(result_v2_from_v3->first, expected_error_str); BOOST_CHECK_EQUAL(result_v2_from_v3->second, nullptr); Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str); + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str); CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value()}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str); + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str); // mempool_tx_v3 mempool_tx_v2 // ^ ^ // tx_v2_from_v2_and_v3 auto tx_v2_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2); auto ancestors_v2_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2_and_v3), m_limits)}; - const auto expected_error_str_2{strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)", + const auto expected_error_str_2{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)", tx_v2_from_v2_and_v3->GetHash().ToString(), tx_v2_from_v2_and_v3->GetWitnessHash().ToString(), mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())}; - auto result_v2_from_both{SingleV3Checks(tx_v2_from_v2_and_v3, *ancestors_v2_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3))}; + auto result_v2_from_both{SingleTRUCChecks(tx_v2_from_v2_and_v3, *ancestors_v2_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3))}; BOOST_CHECK_EQUAL(result_v2_from_both->first, expected_error_str_2); BOOST_CHECK_EQUAL(result_v2_from_both->second, nullptr); Package package_v3_v2_v2{mempool_tx_v3, mempool_tx_v2, tx_v2_from_v2_and_v3}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v2_from_v2_and_v3, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3), package_v3_v2_v2, empty_ancestors), expected_error_str_2); + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v2_and_v3, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3), package_v3_v2_v2, empty_ancestors), expected_error_str_2); } - // V3 cannot spend from an unconfirmed non-v3 transaction. + // TRUC cannot spend from an unconfirmed non-TRUC transaction. { // mempool_tx_v2 // ^ // tx_v3_from_v2 auto tx_v3_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3); auto ancestors_v3_from_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2), m_limits)}; - const auto expected_error_str{strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)", + const auto expected_error_str{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)", tx_v3_from_v2->GetHash().ToString(), tx_v3_from_v2->GetWitnessHash().ToString(), mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())}; - auto result_v3_from_v2{SingleV3Checks(tx_v3_from_v2, *ancestors_v3_from_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2))}; + auto result_v3_from_v2{SingleTRUCChecks(tx_v3_from_v2, *ancestors_v3_from_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2))}; BOOST_CHECK_EQUAL(result_v3_from_v2->first, expected_error_str); BOOST_CHECK_EQUAL(result_v3_from_v2->second, nullptr); Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str); + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str); CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash().ToUint256()).value()}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str); + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str); // mempool_tx_v3 mempool_tx_v2 // ^ ^ // tx_v3_from_v2_and_v3 auto tx_v3_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3); auto ancestors_v3_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2_and_v3), m_limits)}; - const auto expected_error_str_2{strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)", + const auto expected_error_str_2{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)", tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString(), mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())}; - auto result_v3_from_both{SingleV3Checks(tx_v3_from_v2_and_v3, *ancestors_v3_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3))}; + auto result_v3_from_both{SingleTRUCChecks(tx_v3_from_v2_and_v3, *ancestors_v3_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3))}; BOOST_CHECK_EQUAL(result_v3_from_both->first, expected_error_str_2); BOOST_CHECK_EQUAL(result_v3_from_both->second, nullptr); - // tx_v3_from_v2_and_v3 also violates V3_ANCESTOR_LIMIT. + // tx_v3_from_v2_and_v3 also violates TRUC_ANCESTOR_LIMIT. const auto expected_error_str_3{strprintf("tx %s (wtxid=%s) would have too many ancestors", tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString())}; Package package_v3_v2_v3{mempool_tx_v3, mempool_tx_v2, tx_v3_from_v2_and_v3}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v3_from_v2_and_v3, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3), package_v3_v2_v3, empty_ancestors), expected_error_str_3); + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2_and_v3, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3), package_v3_v2_v3, empty_ancestors), expected_error_str_3); } // V3 from V3 is ok, and non-V3 from non-V3 is ok. { @@ -184,25 +184,25 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) // tx_v3_from_v3 auto tx_v3_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3); auto ancestors_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v3), m_limits)}; - BOOST_CHECK(SingleV3Checks(tx_v3_from_v3, *ancestors_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v3)) + BOOST_CHECK(SingleTRUCChecks(tx_v3_from_v3, *ancestors_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v3)) == std::nullopt); Package package_v3_v3{mempool_tx_v3, tx_v3_from_v3}; - BOOST_CHECK(PackageV3Checks(tx_v3_from_v3, GetVirtualTransactionSize(*tx_v3_from_v3), package_v3_v3, empty_ancestors) == std::nullopt); + BOOST_CHECK(PackageTRUCChecks(tx_v3_from_v3, GetVirtualTransactionSize(*tx_v3_from_v3), package_v3_v3, empty_ancestors) == std::nullopt); // mempool_tx_v2 // ^ // tx_v2_from_v2 auto tx_v2_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2); auto ancestors_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2), m_limits)}; - BOOST_CHECK(SingleV3Checks(tx_v2_from_v2, *ancestors_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2)) + BOOST_CHECK(SingleTRUCChecks(tx_v2_from_v2, *ancestors_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2)) == std::nullopt); Package package_v2_v2{mempool_tx_v2, tx_v2_from_v2}; - BOOST_CHECK(PackageV3Checks(tx_v2_from_v2, GetVirtualTransactionSize(*tx_v2_from_v2), package_v2_v2, empty_ancestors) == std::nullopt); + BOOST_CHECK(PackageTRUCChecks(tx_v2_from_v2, GetVirtualTransactionSize(*tx_v2_from_v2), package_v2_v2, empty_ancestors) == std::nullopt); } - // Tx spending v3 cannot have too many mempool ancestors + // Tx spending TRUC cannot have too many mempool ancestors // Configuration where the tx has multiple direct parents. { Package package_multi_parents; @@ -221,11 +221,11 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) BOOST_CHECK_EQUAL(ancestors->size(), 3); const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors", tx_v3_multi_parent->GetHash().ToString(), tx_v3_multi_parent->GetWitnessHash().ToString())}; - auto result{SingleV3Checks(tx_v3_multi_parent, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_parent))}; + auto result{SingleTRUCChecks(tx_v3_multi_parent, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_parent))}; BOOST_CHECK_EQUAL(result->first, expected_error_str); BOOST_CHECK_EQUAL(result->second, nullptr); - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v3_multi_parent, GetVirtualTransactionSize(*tx_v3_multi_parent), package_multi_parents, empty_ancestors), + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_multi_parent, GetVirtualTransactionSize(*tx_v3_multi_parent), package_multi_parents, empty_ancestors), expected_error_str); } @@ -246,34 +246,34 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_gen), m_limits)}; const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors", tx_v3_multi_gen->GetHash().ToString(), tx_v3_multi_gen->GetWitnessHash().ToString())}; - auto result{SingleV3Checks(tx_v3_multi_gen, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_gen))}; + auto result{SingleTRUCChecks(tx_v3_multi_gen, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_gen))}; BOOST_CHECK_EQUAL(result->first, expected_error_str); BOOST_CHECK_EQUAL(result->second, nullptr); // Middle tx is what triggers a failure for the grandchild: - BOOST_CHECK_EQUAL(*PackageV3Checks(middle_tx, GetVirtualTransactionSize(*middle_tx), package_multi_gen, empty_ancestors), expected_error_str); - BOOST_CHECK(PackageV3Checks(tx_v3_multi_gen, GetVirtualTransactionSize(*tx_v3_multi_gen), package_multi_gen, empty_ancestors) == std::nullopt); + BOOST_CHECK_EQUAL(*PackageTRUCChecks(middle_tx, GetVirtualTransactionSize(*middle_tx), package_multi_gen, empty_ancestors), expected_error_str); + BOOST_CHECK(PackageTRUCChecks(tx_v3_multi_gen, GetVirtualTransactionSize(*tx_v3_multi_gen), package_multi_gen, empty_ancestors) == std::nullopt); } - // Tx spending v3 cannot be too large in virtual size. + // Tx spending TRUC cannot be too large in virtual size. auto many_inputs{random_outpoints(100)}; many_inputs.emplace_back(mempool_tx_v3->GetHash(), 0); { auto tx_v3_child_big = make_tx(many_inputs, /*version=*/3); const auto vsize{GetVirtualTransactionSize(*tx_v3_child_big)}; auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child_big), m_limits)}; - const auto expected_error_str{strprintf("v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", - tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize, V3_CHILD_MAX_VSIZE)}; - auto result{SingleV3Checks(tx_v3_child_big, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child_big))}; + const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", + tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE)}; + auto result{SingleTRUCChecks(tx_v3_child_big, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child_big))}; BOOST_CHECK_EQUAL(result->first, expected_error_str); BOOST_CHECK_EQUAL(result->second, nullptr); Package package_child_big{mempool_tx_v3, tx_v3_child_big}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v3_child_big, GetVirtualTransactionSize(*tx_v3_child_big), package_child_big, empty_ancestors), + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child_big, GetVirtualTransactionSize(*tx_v3_child_big), package_child_big, empty_ancestors), expected_error_str); } - // Tx spending v3 cannot have too many sigops. + // Tx spending TRUC cannot have too many sigops. // This child has 10 P2WSH multisig inputs. auto multisig_outpoints{random_outpoints(10)}; multisig_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0); @@ -286,7 +286,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) script_multisig << OP_2 << OP_CHECKMULTISIG; { CMutableTransaction mtx_many_sigops = CMutableTransaction{}; - mtx_many_sigops.nVersion = 3; + mtx_many_sigops.version = TRUC_VERSION; for (const auto& outpoint : multisig_outpoints) { mtx_many_sigops.vin.emplace_back(outpoint); mtx_many_sigops.vin.back().scriptWitness.stack.emplace_back(script_multisig.begin(), script_multisig.end()); @@ -302,34 +302,34 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) BOOST_CHECK_EQUAL(total_sigops, tx_many_sigops->vin.size() * MAX_PUBKEYS_PER_MULTISIG); const int64_t bip141_vsize{GetVirtualTransactionSize(*tx_many_sigops)}; // Weight limit is not reached... - BOOST_CHECK(SingleV3Checks(tx_many_sigops, *ancestors, empty_conflicts_set, bip141_vsize) == std::nullopt); + BOOST_CHECK(SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set, bip141_vsize) == std::nullopt); // ...but sigop limit is. - const auto expected_error_str{strprintf("v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", + const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes", tx_many_sigops->GetHash().ToString(), tx_many_sigops->GetWitnessHash().ToString(), - total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, V3_CHILD_MAX_VSIZE)}; - auto result{SingleV3Checks(tx_many_sigops, *ancestors, empty_conflicts_set, + total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, TRUC_CHILD_MAX_VSIZE)}; + auto result{SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_many_sigops, /*nSigOpCost=*/total_sigops, /*bytes_per_sigop=*/ DEFAULT_BYTES_PER_SIGOP))}; BOOST_CHECK_EQUAL(result->first, expected_error_str); BOOST_CHECK_EQUAL(result->second, nullptr); Package package_child_sigops{mempool_tx_v3, tx_many_sigops}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_many_sigops, total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, package_child_sigops, empty_ancestors), + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_many_sigops, total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, package_child_sigops, empty_ancestors), expected_error_str); } - // Parent + child with v3 in the mempool. Child is allowed as long as it is under V3_CHILD_MAX_VSIZE. + // Parent + child with TRUC in the mempool. Child is allowed as long as it is under TRUC_CHILD_MAX_VSIZE. auto tx_mempool_v3_child = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3); { - BOOST_CHECK(GetTransactionWeight(*tx_mempool_v3_child) <= V3_CHILD_MAX_VSIZE * WITNESS_SCALE_FACTOR); + BOOST_CHECK(GetTransactionWeight(*tx_mempool_v3_child) <= TRUC_CHILD_MAX_VSIZE * WITNESS_SCALE_FACTOR); auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_mempool_v3_child), m_limits)}; - BOOST_CHECK(SingleV3Checks(tx_mempool_v3_child, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_mempool_v3_child)) == std::nullopt); + BOOST_CHECK(SingleTRUCChecks(tx_mempool_v3_child, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_mempool_v3_child)) == std::nullopt); pool.addUnchecked(entry.FromTx(tx_mempool_v3_child)); Package package_v3_1p1c{mempool_tx_v3, tx_mempool_v3_child}; - BOOST_CHECK(PackageV3Checks(tx_mempool_v3_child, GetVirtualTransactionSize(*tx_mempool_v3_child), package_v3_1p1c, empty_ancestors) == std::nullopt); + BOOST_CHECK(PackageTRUCChecks(tx_mempool_v3_child, GetVirtualTransactionSize(*tx_mempool_v3_child), package_v3_1p1c, empty_ancestors) == std::nullopt); } - // A v3 transaction cannot have more than 1 descendant. Sibling is returned when exactly 1 exists. + // A TRUC transaction cannot have more than 1 descendant. Sibling is returned when exactly 1 exists. { auto tx_v3_child2 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 1}}, /*version=*/3); @@ -337,17 +337,17 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) auto ancestors_1sibling{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child2), m_limits)}; const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit", mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())}; - auto result_with_sibling_eviction{SingleV3Checks(tx_v3_child2, *ancestors_1sibling, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child2))}; + auto result_with_sibling_eviction{SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child2))}; BOOST_CHECK_EQUAL(result_with_sibling_eviction->first, expected_error_str); // The other mempool child is returned to allow for sibling eviction. BOOST_CHECK_EQUAL(result_with_sibling_eviction->second, tx_mempool_v3_child); // If directly replacing the child, make sure there is no double-counting. - BOOST_CHECK(SingleV3Checks(tx_v3_child2, *ancestors_1sibling, {tx_mempool_v3_child->GetHash()}, GetVirtualTransactionSize(*tx_v3_child2)) + BOOST_CHECK(SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, {tx_mempool_v3_child->GetHash()}, GetVirtualTransactionSize(*tx_v3_child2)) == std::nullopt); Package package_v3_1p2c{mempool_tx_v3, tx_mempool_v3_child, tx_v3_child2}; - BOOST_CHECK_EQUAL(*PackageV3Checks(tx_v3_child2, GetVirtualTransactionSize(*tx_v3_child2), package_v3_1p2c, empty_ancestors), + BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child2, GetVirtualTransactionSize(*tx_v3_child2), package_v3_1p2c, empty_ancestors), expected_error_str); // Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg. @@ -357,7 +357,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) BOOST_CHECK_EQUAL(entry_mempool_parent->GetCountWithDescendants(), 3); auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3), m_limits)}; - auto result_2children{SingleV3Checks(tx_v3_child3, *ancestors_2siblings, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child3))}; + auto result_2children{SingleTRUCChecks(tx_v3_child3, *ancestors_2siblings, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child3))}; BOOST_CHECK_EQUAL(result_2children->first, expected_error_str); // The other mempool child is not returned because sibling eviction is not allowed. BOOST_CHECK_EQUAL(result_2children->second, nullptr); @@ -377,7 +377,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup) auto ancestors_3gen{pool.CalculateMemPoolAncestors(entry.FromTx(tx_to_submit), m_limits)}; const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit", tx_mempool_grandparent->GetHash().ToString(), tx_mempool_grandparent->GetWitnessHash().ToString())}; - auto result_3gen{SingleV3Checks(tx_to_submit, *ancestors_3gen, empty_conflicts_set, GetVirtualTransactionSize(*tx_to_submit))}; + auto result_3gen{SingleTRUCChecks(tx_to_submit, *ancestors_3gen, empty_conflicts_set, GetVirtualTransactionSize(*tx_to_submit))}; BOOST_CHECK_EQUAL(result_3gen->first, expected_error_str); // The other mempool child is not returned because sibling eviction is not allowed. BOOST_CHECK_EQUAL(result_3gen->second, nullptr); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 790eabc7c1..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) @@ -46,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup) spends.resize(2); for (int i = 0; i < 2; i++) { - spends[i].nVersion = 1; + spends[i].version = 1; spends[i].vin.resize(1); spends[i].vin[0].prevout.hash = m_coinbase_txns[0]->GetHash(); spends[i].vin[0].prevout.n = 0; @@ -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()); } } @@ -181,7 +183,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) // coinbase tx. CMutableTransaction spend_tx; - spend_tx.nVersion = 1; + spend_tx.version = 1; spend_tx.vin.resize(1); spend_tx.vin[0].prevout.hash = m_coinbase_txns[0]->GetHash(); spend_tx.vin[0].prevout.n = 0; @@ -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 @@ -243,7 +245,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) // then test validity with P2SH. { CMutableTransaction invalid_under_p2sh_tx; - invalid_under_p2sh_tx.nVersion = 1; + invalid_under_p2sh_tx.version = 1; invalid_under_p2sh_tx.vin.resize(1); invalid_under_p2sh_tx.vin[0].prevout.hash = spend_tx.GetHash(); invalid_under_p2sh_tx.vin[0].prevout.n = 0; @@ -253,13 +255,13 @@ 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 { CMutableTransaction invalid_with_cltv_tx; - invalid_with_cltv_tx.nVersion = 1; + invalid_with_cltv_tx.version = 1; invalid_with_cltv_tx.nLockTime = 100; invalid_with_cltv_tx.vin.resize(1); invalid_with_cltv_tx.vin[0].prevout.hash = spend_tx.GetHash(); @@ -276,19 +278,19 @@ 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 { CMutableTransaction invalid_with_csv_tx; - invalid_with_csv_tx.nVersion = 2; + invalid_with_csv_tx.version = 2; invalid_with_csv_tx.vin.resize(1); invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetHash(); invalid_with_csv_tx.vin[0].prevout.n = 3; @@ -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 @@ -319,7 +321,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) // for the same tx with a different witness. { CMutableTransaction valid_with_witness_tx; - valid_with_witness_tx.nVersion = 1; + valid_with_witness_tx.version = 1; valid_with_witness_tx.vin.resize(1); valid_with_witness_tx.vin[0].prevout.hash = spend_tx.GetHash(); valid_with_witness_tx.vin[0].prevout.n = 1; @@ -333,18 +335,18 @@ 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); } { // Test a transaction with multiple inputs. CMutableTransaction tx; - tx.nVersion = 1; + tx.version = 1; tx.vin.resize(2); tx.vin[0].prevout.hash = spend_tx.GetHash(); tx.vin[0].prevout.n = 0; @@ -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 5746961550..142d7a6fde 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -2,16 +2,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <arith_uint256.h> #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 +60,49 @@ static std::string ArrayToString(const unsigned char A[], unsigned int width) return Stream.str(); } -inline uint160 uint160S(const char *str) -{ - uint160 rv; - rv.SetHex(str); - return rv; -} -inline uint160 uint160S(const std::string& str) -{ - uint160 rv; - rv.SetHex(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(uint256::FromHex(R1L.ToString()).value(), R1L); + BOOST_CHECK_EQUAL(uint256::FromHex(R2L.ToString()).value(), R2L); + BOOST_CHECK_EQUAL(uint256::FromHex(ZeroL.ToString()).value(), ZeroL); + BOOST_CHECK_EQUAL(uint256::FromHex(OneL.ToString()).value(), OneL); + BOOST_CHECK_EQUAL(uint256::FromHex(MaxL.ToString()).value(), MaxL); + BOOST_CHECK_EQUAL(uint256::FromHex(R1ArrayHex).value(), R1L); + BOOST_CHECK_EQUAL(uint256(R1L), R1L); + BOOST_CHECK_EQUAL(uint256(ZeroL), ZeroL); + BOOST_CHECK_EQUAL(uint256(OneL), OneL); + + BOOST_CHECK_EQUAL(uint160::FromHex(R1S.ToString()).value(), R1S); + BOOST_CHECK_EQUAL(uint160::FromHex(R2S.ToString()).value(), R2S); + BOOST_CHECK_EQUAL(uint160::FromHex(ZeroS.ToString()).value(), ZeroS); + BOOST_CHECK_EQUAL(uint160::FromHex(OneS.ToString()).value(), OneS); + BOOST_CHECK_EQUAL(uint160::FromHex(MaxS.ToString()).value(), MaxS); + BOOST_CHECK_EQUAL(uint160::FromHex(std::string_view{R1ArrayHex + 24, 40}).value(), R1S); + + BOOST_CHECK_EQUAL(uint160(R1S), R1S); + BOOST_CHECK_EQUAL(uint160(ZeroS), ZeroS); + BOOST_CHECK_EQUAL(uint160(OneS), OneS); } BOOST_AUTO_TEST_CASE( comparison ) // <= >= < > @@ -129,187 +111,232 @@ 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_AUTO_TEST_CASE( operator_with_self ) -{ - arith_uint256 v = UintToArith256(uint256S("02")); - v *= v; - BOOST_CHECK(v == UintToArith256(uint256S("04"))); - v /= v; - BOOST_CHECK(v == UintToArith256(uint256S("01"))); - v += v; - BOOST_CHECK(v == UintToArith256(uint256S("02"))); - v -= v; - BOOST_CHECK(v == UintToArith256(uint256S("0"))); -} - -BOOST_AUTO_TEST_CASE(parse) +/** + * 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)); + } { - 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("0x12").GetHex(), s_12); - BOOST_CHECK_EQUAL(uint256S(" 0x12").GetHex(), s_12); - BOOST_CHECK_EQUAL(uint256S(" 12").GetHex(), s_12); + // 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")); } { - 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("0x1").GetHex(), s_1); - BOOST_CHECK_EQUAL(uint256S(" 0x1").GetHex(), s_1); - BOOST_CHECK_EQUAL(uint256S(" 1").GetHex(), s_1); + // 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)); } { - 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("0x").GetHex(), s_0); - BOOST_CHECK_EQUAL(uint256S(" 0x").GetHex(), s_0); - BOOST_CHECK_EQUAL(uint256S(" ").GetHex(), s_0); + // 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(from_user_hex) +{ + BOOST_CHECK_EQUAL(uint256::FromUserHex(""), uint256::ZERO); + BOOST_CHECK_EQUAL(uint256::FromUserHex("0x"), uint256::ZERO); + BOOST_CHECK_EQUAL(uint256::FromUserHex("0"), uint256::ZERO); + BOOST_CHECK_EQUAL(uint256::FromUserHex("00"), uint256::ZERO); + BOOST_CHECK_EQUAL(uint256::FromUserHex("1"), uint256::ONE); + BOOST_CHECK_EQUAL(uint256::FromUserHex("0x10"), uint256{0x10}); + BOOST_CHECK_EQUAL(uint256::FromUserHex("10"), uint256{0x10}); + BOOST_CHECK_EQUAL(uint256::FromUserHex("0xFf"), uint256{0xff}); + BOOST_CHECK_EQUAL(uint256::FromUserHex("Ff"), uint256{0xff}); + const std::string valid_hex_64{"0x0123456789abcdef0123456789abcdef0123456789ABDCEF0123456789ABCDEF"}; + BOOST_REQUIRE_EQUAL(valid_hex_64.size(), 2 + 64); // 0x prefix and 64 hex digits + BOOST_CHECK_EQUAL(uint256::FromUserHex(valid_hex_64.substr(2)).value().ToString(), ToLower(valid_hex_64.substr(2))); + BOOST_CHECK_EQUAL(uint256::FromUserHex(valid_hex_64.substr(0)).value().ToString(), ToLower(valid_hex_64.substr(2))); + + BOOST_CHECK(!uint256::FromUserHex("0x0 ")); // no spaces at end, + BOOST_CHECK(!uint256::FromUserHex(" 0x0")); // or beginning, + BOOST_CHECK(!uint256::FromUserHex("0x 0")); // or middle, + BOOST_CHECK(!uint256::FromUserHex(" ")); // etc. + BOOST_CHECK(!uint256::FromUserHex("0x0ga")); // invalid character + BOOST_CHECK(!uint256::FromUserHex("x0")); // broken prefix + BOOST_CHECK(!uint256::FromUserHex("0x0x00")); // two prefixes not allowed + BOOST_CHECK(!uint256::FromUserHex(valid_hex_64.substr(2) + "0")); // 1 hex digit too many + BOOST_CHECK(!uint256::FromUserHex(valid_hex_64 + "a")); // 1 hex digit too many + BOOST_CHECK(!uint256::FromUserHex(valid_hex_64 + " ")); // whitespace after max length + BOOST_CHECK(!uint256::FromUserHex(valid_hex_64 + "z")); // invalid character after max length +} + 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")}; + constexpr uint256 consteval_uint{ "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"}; + BOOST_CHECK_EQUAL(consteval_uint, runtime_uint); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util/CMakeLists.txt b/src/test/util/CMakeLists.txt new file mode 100644 index 0000000000..5d88d1da3e --- /dev/null +++ b/src/test/util/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_library(test_util STATIC EXCLUDE_FROM_ALL + blockfilter.cpp + coins.cpp + index.cpp + json.cpp + logging.cpp + mining.cpp + net.cpp + random.cpp + script.cpp + setup_common.cpp + str.cpp + transaction_utils.cpp + txmempool.cpp + validation.cpp + $<$<BOOL:${ENABLE_WALLET}>:${PROJECT_SOURCE_DIR}/src/wallet/test/util.cpp> +) + +target_link_libraries(test_util + PRIVATE + core_interface + Boost::headers + PUBLIC + univalue +) diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h index 03b44fc894..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; } @@ -124,11 +124,11 @@ CreateAndActivateUTXOSnapshot( new_active.m_chain.SetTip(*(tip->pprev)); } - bool res = node.chainman->ActivateSnapshot(auto_infile, metadata, in_memory_chainstate); + auto res = node.chainman->ActivateSnapshot(auto_infile, metadata, in_memory_chainstate); // Restore the old tip. new_active.m_chain.SetTip(*tip); - return res; + return !!res; } diff --git a/src/test/util/cluster_linearize.h b/src/test/util/cluster_linearize.h new file mode 100644 index 0000000000..871aa9d74e --- /dev/null +++ b/src/test/util/cluster_linearize.h @@ -0,0 +1,411 @@ +// 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 : depgraph.Positions()) { + 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. + * - The appending of 1, 2, 3, ... holes at the end of the cluster, followed by appending the new + * transaction. + * + * Let's say you have a 7-transaction cluster, consisting of transactions F,A,C,B,_,G,E,_,D + * (where _ represent holes; unused positions within the DepGraph) 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 + * - [ ] put G before the hole before D + * - [X] put G before E + * - [ ] put G before the hole before E + * - [ ] put G before B + * - [ ] put G before C + * - [ ] put G before A + * - [ ] put G before F + * - [ ] add 1 hole at the end of the cluster, followed by G + * - [ ] add 2 holes at the end of the cluster, followed by G + * - [ ] add ... + * + * The skip values in this case are 1 (G->F), 1 (G->D), 4 (G->A, G at end, G before D, G before + * hole). No skip after 4 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). */ + [[maybe_unused]] 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). */ + [[maybe_unused]] 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; + topo_order.reserve(depgraph.TxCount()); + for (auto i : depgraph.Positions()) topo_order.push_back(i); + 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 positions (incl. holes) the deserializer already knows when it has deserialized + * what has been serialized here so far. */ + SetType done; + + // 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 encountered, 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. + auto add_holes = SetType::Fill(idx) - done - depgraph.Positions(); + if (add_holes.None()) { + // The new transaction is to be inserted N positions back from the end of the + // cluster. Emit N to indicate that that many insertion choices are skipped. + auto skips = (done - SetType::Fill(idx)).Count(); + s << VARINT(diff + skips); + } else { + // The new transaction is to be appended at the end of the cluster, after N holes. + // Emit current_cluster_size + N, to indicate all insertion choices are skipped, + // plus N possibilities for the number of holes. + s << VARINT(diff + done.Count() + add_holes.Count()); + done |= add_holes; + } + done.Set(idx); + } + + // 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 serialization order to cluster order, used later to reconstruct the + * cluster order. */ + std::vector<ClusterIndex> reordering; + /** How big the entries vector in the reconstructed depgraph will be (including holes). */ + ClusterIndex total_size{0}; + + // Read transactions in topological order. + while (true) { + FeeFrac new_feerate; //!< The new transaction's fee and size. + SetType new_ancestors; //!< The new transaction's ancestors (excluding itself). + uint64_t diff{0}; //!< How many potential parents/insertions we have to skip. + bool read_error{false}; + try { + // 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); + new_feerate = {UnsignedToSigned(coded_fee), size}; + // Read dependency information. + auto topo_idx = reordering.size(); + 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 (new_ancestors[dep_topo_idx]) continue; + if (diff == 0) { + // When the skip counter has reached 0, add an actual dependency. + new_ancestors |= topo_depgraph.Ancestors(dep_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; + } + } + } catch (const std::ios_base::failure&) { + // Continue even if a read error was encountered. + read_error = true; + } + // Construct a new transaction whenever we made it past the new_feerate construction. + if (new_feerate.IsEmpty()) break; + assert(reordering.size() < SetType::Size()); + auto topo_idx = topo_depgraph.AddTransaction(new_feerate); + topo_depgraph.AddDependencies(new_ancestors, topo_idx); + if (total_size < SetType::Size()) { + // Normal case. + diff %= SetType::Size(); + if (diff <= total_size) { + // Insert the new transaction at distance diff back from the end. + for (auto& pos : reordering) { + pos += (pos >= total_size - diff); + } + reordering.push_back(total_size++ - diff); + } else { + // Append diff - total_size holes at the end, plus the new transaction. + total_size = diff; + reordering.push_back(total_size++); + } + } else { + // In case total_size == SetType::Size, it is not possible to insert the new + // transaction without exceeding SetType's size. Instead, interpret diff as an + // index into the holes, and overwrite a position there. This branch is never used + // when deserializing the output of the serializer, but gives meaning to otherwise + // invalid input. + diff %= (SetType::Size() - reordering.size()); + SetType holes = SetType::Fill(SetType::Size()); + for (auto pos : reordering) holes.Reset(pos); + for (auto pos : holes) { + if (diff == 0) { + reordering.push_back(pos); + break; + } + --diff; + } + } + // Stop if a read error was encountered during deserialization. + if (read_error) break; + } + + // Construct the original cluster order depgraph. + depgraph = DepGraph(topo_depgraph, reordering, total_size); + } +}; + +/** Perform a sanity/consistency check on a DepGraph. */ +template<typename SetType> +void SanityCheck(const DepGraph<SetType>& depgraph) +{ + // Verify Positions and PositionRange consistency. + ClusterIndex num_positions{0}; + ClusterIndex position_range{0}; + for (ClusterIndex i : depgraph.Positions()) { + ++num_positions; + position_range = i + 1; + } + assert(num_positions == depgraph.TxCount()); + assert(position_range == depgraph.PositionRange()); + assert(position_range >= num_positions); + assert(position_range <= SetType::Size()); + // Consistency check between ancestors internally. + for (ClusterIndex i : depgraph.Positions()) { + // 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 : depgraph.Positions()) { + for (ClusterIndex j : depgraph.Positions()) { + assert(depgraph.Ancestors(i)[j] == depgraph.Descendants(j)[i]); + } + // No transaction is a parent or child of itself. + auto parents = depgraph.GetReducedParents(i); + auto children = depgraph.GetReducedChildren(i); + assert(!parents[i]); + assert(!children[i]); + // Parents of a transaction do not have ancestors inside those parents (except itself). + // Note that even the transaction itself may be missing (if it is part of a cycle). + for (auto parent : parents) { + assert((depgraph.Ancestors(parent) & parents).IsSubsetOf(SetType::Singleton(parent))); + } + // Similar for children and descendants. + for (auto child : children) { + assert((depgraph.Descendants(child) & children).IsSubsetOf(SetType::Singleton(child))); + } + } + if (IsAcyclic(depgraph)) { + // If DepGraph is acyclic, serialize + deserialize must roundtrip. + 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()); + + // In acyclic graphs, the union of parents with parents of parents etc. yields the + // full ancestor set (and similar for children and descendants). + std::vector<SetType> parents(depgraph.PositionRange()), children(depgraph.PositionRange()); + for (ClusterIndex i : depgraph.Positions()) { + parents[i] = depgraph.GetReducedParents(i); + children[i] = depgraph.GetReducedChildren(i); + } + for (auto i : depgraph.Positions()) { + // Initialize the set of ancestors with just the current transaction itself. + SetType ancestors = SetType::Singleton(i); + // Iteratively add parents of all transactions in the ancestor set to itself. + while (true) { + const auto old_ancestors = ancestors; + for (auto j : ancestors) ancestors |= parents[j]; + // Stop when no more changes are being made. + if (old_ancestors == ancestors) break; + } + assert(ancestors == depgraph.Ancestors(i)); + + // Initialize the set of descendants with just the current transaction itself. + SetType descendants = SetType::Singleton(i); + // Iteratively add children of all transactions in the descendant set to itself. + while (true) { + const auto old_descendants = descendants; + for (auto j : descendants) descendants |= children[j]; + // Stop when no more changes are being made. + if (old_descendants == descendants) break; + } + assert(descendants == depgraph.Descendants(i)); + } + } +} + +/** 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(depgraph.Positions()[i]); + // 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/coins.cpp b/src/test/util/coins.cpp index 742dbc04d1..7e10c7c58d 100644 --- a/src/test/util/coins.cpp +++ b/src/test/util/coins.cpp @@ -13,12 +13,12 @@ #include <stdint.h> #include <utility> -COutPoint AddTestCoin(CCoinsViewCache& coins_view) +COutPoint AddTestCoin(FastRandomContext& rng, CCoinsViewCache& coins_view) { Coin new_coin; - COutPoint outpoint{Txid::FromUint256(InsecureRand256()), /*nIn=*/0}; + COutPoint outpoint{Txid::FromUint256(rng.rand256()), /*nIn=*/0}; new_coin.nHeight = 1; - new_coin.out.nValue = InsecureRandMoneyAmount(); + new_coin.out.nValue = RandMoney(rng); new_coin.out.scriptPubKey.assign(uint32_t{56}, 1); coins_view.AddCoin(outpoint, std::move(new_coin), /*possible_overwrite=*/false); diff --git a/src/test/util/coins.h b/src/test/util/coins.h index 5e6f4293ae..89a9e7b329 100644 --- a/src/test/util/coins.h +++ b/src/test/util/coins.h @@ -8,12 +8,13 @@ #include <primitives/transaction.h> class CCoinsViewCache; +class FastRandomContext; /** * Create a Coin with DynamicMemoryUsage of 80 bytes and add it to the given view. * @param[in,out] coins_view The coins view cache to add the new coin to. * @returns the COutPoint of the created coin. */ -COutPoint AddTestCoin(CCoinsViewCache& coins_view); +COutPoint AddTestCoin(FastRandomContext& rng, CCoinsViewCache& coins_view); #endif // BITCOIN_TEST_UTIL_COINS_H diff --git a/src/test/util/json.cpp b/src/test/util/json.cpp index ad3c346c84..46a4a9f9a1 100644 --- a/src/test/util/json.cpp +++ b/src/test/util/json.cpp @@ -1,15 +1,15 @@ -// Copyright (c) 2023 The Bitcoin Core developers +// Copyright (c) 2023-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 <test/util/json.h> -#include <string> +#include <univalue.h> #include <util/check.h> -#include <univalue.h> +#include <string_view> -UniValue read_json(const std::string& jsondata) +UniValue read_json(std::string_view jsondata) { UniValue v; Assert(v.read(jsondata) && v.isArray()); diff --git a/src/test/util/json.h b/src/test/util/json.h index 5b1026762e..f6f4e6ab71 100644 --- a/src/test/util/json.h +++ b/src/test/util/json.h @@ -1,14 +1,14 @@ -// Copyright (c) 2023 The Bitcoin Core developers +// Copyright (c) 2023-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. #ifndef BITCOIN_TEST_UTIL_JSON_H #define BITCOIN_TEST_UTIL_JSON_H -#include <string> - #include <univalue.h> -UniValue read_json(const std::string& jsondata); +#include <string_view> + +UniValue read_json(std::string_view jsondata); #endif // BITCOIN_TEST_UTIL_JSON_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..32d785e45d 100644 --- a/src/test/util/random.cpp +++ b/src/test/util/random.cpp @@ -7,27 +7,36 @@ #include <logging.h> #include <random.h> #include <uint256.h> +#include <util/check.h> #include <cstdlib> -#include <string> +#include <iostream> -FastRandomContext g_insecure_rand_ctx; +extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; -/** Return the unsigned from the environment var if available, otherwise 0 */ -static uint256 GetUintFromEnv(const std::string& env_name) +void SeedRandomStateForTest(SeedRand seedtype) { - const char* num = std::getenv(env_name.c_str()); - if (!num) return {}; - return uint256S(num); -} + constexpr auto RANDOM_CTX_SEED{"RANDOM_CTX_SEED"}; -void Seed(FastRandomContext& ctx) -{ - // 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(); - LogPrintf("%s: Setting random seed for current tests to %s=%s\n", __func__, RANDOM_CTX_SEED, seed.GetHex()); - ctx = FastRandomContext(seed); + // 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. + if (const char* num{std::getenv(RANDOM_CTX_SEED)}) { + if (auto num_parsed{uint256::FromUserHex(num)}) { + return *num_parsed; + } else { + std::cerr << RANDOM_CTX_SEED << " must consist of up to " << uint256::size() * 2 << " hex digits (\"0x\" prefix allowed), it was set to: '" << num << "'.\n"; + std::abort(); + } + } + // Otherwise use a (truly) random value. + return GetRandHash(); + }(); + + const uint256& seed{seedtype == SeedRand::FIXED_SEED ? ctx_seed : uint256::ZERO}; + LogInfo("Setting random seed for current tests to %s=%s\n", RANDOM_CTX_SEED, seed.GetHex()); + MakeRandDeterministicDANGEROUS(seed); } diff --git a/src/test/util/random.h b/src/test/util/random.h index 18ab425e48..441150e666 100644 --- a/src/test/util/random.h +++ b/src/test/util/random.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 The Bitcoin Core developers +// Copyright (c) 2023-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. @@ -11,64 +11,26 @@ #include <cstdint> -/** - * This global and the helpers that use it are not thread-safe. - * - * If thread-safety is needed, a per-thread instance could be - * used in the multi-threaded test. - */ -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 with a compile time constant of zeros. + */ + ZEROS, + /** + * Seed with a fixed value that never changes over the lifetime of this + * process. The seed is read from the RANDOM_CTX_SEED environment variable + * if set, otherwise generated randomly once, saved, and reused. + */ + FIXED_SEED, }; -/** 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); - } -} - -static inline uint32_t InsecureRand32() -{ - return g_insecure_rand_ctx.rand32(); -} - -static inline uint256 InsecureRand256() -{ - return g_insecure_rand_ctx.rand256(); -} - -static inline uint64_t InsecureRandBits(int bits) -{ - return g_insecure_rand_ctx.randbits(bits); -} - -static inline uint64_t InsecureRandRange(uint64_t range) -{ - return g_insecure_rand_ctx.randrange(range); -} - -static inline bool InsecureRandBool() -{ - return g_insecure_rand_ctx.randbool(); -} +/** Seed the global RNG state for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */ +void SeedRandomStateForTest(SeedRand seed); -static inline CAmount InsecureRandMoneyAmount() +template <RandomNumberGenerator Rng> +inline CAmount RandMoney(Rng&& rng) { - return static_cast<CAmount>(InsecureRandRange(MAX_MONEY + 1)); + return CAmount{rng.randrange(MAX_MONEY + 1)}; } #endif // BITCOIN_TEST_UTIL_RANDOM_H diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index fd07931716..7465846356 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -1,13 +1,9 @@ -// 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. -#include <config/bitcoin-config.h> // IWYU pragma: keep - #include <test/util/setup_common.h> -#include <kernel/validation_cache_sizes.h> - #include <addrman.h> #include <banman.h> #include <chainparams.h> @@ -30,10 +26,9 @@ #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> -#include <policy/fees_args.h> #include <pow.h> #include <random.h> #include <rpc/blockchain.h> @@ -66,8 +61,8 @@ #include <functional> #include <stdexcept> +using namespace util::hex_literals; using kernel::BlockTreeDB; -using kernel::ValidationCacheSizes; using node::ApplyArgsManOptions; using node::BlockAssembler; using node::BlockManager; @@ -79,14 +74,9 @@ using node::VerifyLoadedChainstate; 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 uint256& num) -{ - os << num.ToString(); - return os; -} +constexpr inline auto TEST_DIR_PATH_ELEMENT{"test_common bitcoin"}; // Includes a space to catch possible path escape issues. +/** Random context to get unique temp data dirs. Separate from m_rng, which can be seeded from a const env var */ +static FastRandomContext g_rng_temp_path; struct NetworkSetup { @@ -100,7 +90,7 @@ static NetworkSetup g_networksetup_instance; /** Register test-only arguments */ static void SetupUnitTestArgs(ArgsManager& argsman) { - argsman.AddArg("-testdatadir", strprintf("Custom data directory (default: %s<random_string>)", fs::PathToString(fs::temp_directory_path() / "test_common_" PACKAGE_NAME / "")), + argsman.AddArg("-testdatadir", strprintf("Custom data directory (default: %s<random_string>)", fs::PathToString(fs::temp_directory_path() / TEST_DIR_PATH_ELEMENT / "")), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); } @@ -111,10 +101,11 @@ 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; + m_node.shutdown_signal = &m_interrupt; + m_node.shutdown_request = [this]{ return m_interrupt(); }; m_node.args = &gArgs; std::vector<const char*> arguments = Cat( { @@ -128,7 +119,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()); } @@ -144,10 +135,14 @@ 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::FIXED_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()}; - m_path_root = fs::temp_directory_path() / "test_common_" PACKAGE_NAME / rand_str; + const auto rand_str{g_rng_temp_path.rand256().ToString()}; + m_path_root = fs::temp_directory_path() / TEST_DIR_PATH_ELEMENT / rand_str; TryCreateDirectories(m_path_root); } else { // Custom data directory @@ -157,7 +152,7 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto root_dir = fs::absolute(root_dir); const std::string test_path{G_TEST_GET_FULL_NAME ? G_TEST_GET_FULL_NAME() : ""}; - m_path_lock = root_dir / "test_common_" PACKAGE_NAME / fs::PathFromString(test_path); + m_path_lock = root_dir / TEST_DIR_PATH_ELEMENT / fs::PathFromString(test_path); m_path_root = m_path_lock / "datadir"; // Try to obtain the lock; if unsuccessful don't disturb the existing test. @@ -177,20 +172,15 @@ 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); LogInstance().StartLogging(); + m_node.warnings = std::make_unique<node::Warnings>(); m_node.kernel = std::make_unique<kernel::Context>(); 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) { @@ -215,55 +205,69 @@ 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); - m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node)); + bilingual_str error{}; + m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node), error); + Assert(error.empty()); + m_node.warnings = std::make_unique<node::Warnings>(); m_cache_sizes = CalculateCacheSizes(m_args); - m_node.notifications = std::make_unique<KernelNotifications>(*Assert(m_node.shutdown), m_node.exit_status); - - const ChainstateManager::Options chainman_opts{ - .chainparams = chainparams, - .datadir = m_args.GetDataDirNet(), - .check_block_index = true, - .notifications = *m_node.notifications, - .signals = m_node.validation_signals.get(), - .worker_threads_num = 2, - }; - const BlockManager::Options blockman_opts{ - .chainparams = chainman_opts.chainparams, - .blocks_dir = m_args.GetBlocksDirPath(), - .notifications = chainman_opts.notifications, + m_node.notifications = std::make_unique<KernelNotifications>(Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)); + + m_make_chainman = [this, &chainparams, opts] { + Assert(!m_node.chainman); + ChainstateManager::Options chainman_opts{ + .chainparams = chainparams, + .datadir = m_args.GetDataDirNet(), + .check_block_index = 1, + .notifications = *m_node.notifications, + .signals = m_node.validation_signals.get(), + .worker_threads_num = 2, + }; + if (opts.min_validation_cache) { + chainman_opts.script_execution_cache_bytes = 0; + chainman_opts.signature_cache_bytes = 0; + } + const BlockManager::Options blockman_opts{ + .chainparams = chainman_opts.chainparams, + .blocks_dir = m_args.GetBlocksDirPath(), + .notifications = chainman_opts.notifications, + }; + m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown_signal), chainman_opts, blockman_opts); + LOCK(m_node.chainman->GetMutex()); + m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{ + .path = m_args.GetDataDirNet() / "blocks" / "index", + .cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db), + .memory_only = true, + }); }; - m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts); - m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{ - .path = m_args.GetDataDirNet() / "blocks" / "index", - .cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db), - .memory_only = true}); + m_make_chainman(); } 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(); m_node.netgroupman.reset(); m_node.args = nullptr; m_node.mempool.reset(); - m_node.fee_estimator.reset(); + Assert(!m_node.fee_estimator); // Each test must create a local object, if they wish to use the fee_estimator m_node.chainman.reset(); m_node.validation_signals.reset(); m_node.scheduler.reset(); @@ -276,8 +280,8 @@ void ChainTestingSetup::LoadVerifyActivateChainstate() options.mempool = Assert(m_node.mempool.get()); options.block_tree_db_in_memory = m_block_tree_db_in_memory; options.coins_db_in_memory = m_coins_db_in_memory; - options.reindex = chainman.m_blockman.m_reindexing; - options.reindex_chainstate = m_args.GetBoolArg("-reindex-chainstate", false); + options.wipe_block_tree_db = m_args.GetBoolArg("-reindex", false); + options.wipe_chainstate_db = m_args.GetBoolArg("-reindex", false) || m_args.GetBoolArg("-reindex-chainstate", false); options.prune = chainman.m_blockman.IsPruneMode(); options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL); @@ -296,19 +300,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, @@ -320,7 +324,8 @@ TestingSetup::TestingSetup( peerman_opts.deterministic_rng = true; m_node.peerman = PeerManager::make(*m_node.connman, *m_node.addrman, m_node.banman.get(), *m_node.chainman, - *m_node.mempool, peerman_opts); + *m_node.mempool, *m_node.warnings, + peerman_opts); { CConnman::Options options; @@ -330,11 +335,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 = { @@ -368,7 +371,8 @@ CBlock TestChain100Setup::CreateBlock( const CScript& scriptPubKey, Chainstate& chainstate) { - CBlock block = BlockAssembler{chainstate, nullptr}.CreateNewBlock(scriptPubKey)->block; + BlockAssembler::Options options; + CBlock block = BlockAssembler{chainstate, nullptr, options}.CreateNewBlock(scriptPubKey)->block; Assert(block.vtx.size() == 1); for (const CMutableTransaction& tx : txns) { @@ -559,7 +563,7 @@ void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate) // Manually create an invalid transaction. Manually set the fee in the CTxMemPoolEntry to // achieve the exact target feerate. CMutableTransaction mtx = CMutableTransaction(); - mtx.vin.emplace_back(COutPoint{Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0}); + mtx.vin.emplace_back(COutPoint{Txid::FromUint256(m_rng.rand256()), 0}); mtx.vout.emplace_back(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE))); const auto tx{MakeTransactionRef(mtx)}; LockPoints lp; @@ -580,8 +584,23 @@ CBlock getBlock13b8a() { CBlock block; DataStream stream{ - ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), + "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"_hex, }; stream >> TX_WITH_WITNESS(block); return block; } + +std::ostream& operator<<(std::ostream& os, const arith_uint256& num) +{ + return os << num.ToString(); +} + +std::ostream& operator<<(std::ostream& os, const uint160& num) +{ + return os << num.ToString(); +} + +std::ostream& operator<<(std::ostream& os, const uint256& num) +{ + return os << num.ToString(); +} diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index dbd66e3585..f9cf5d9157 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2022 The Bitcoin Core developers +// Copyright (c) 2015-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. @@ -10,9 +10,12 @@ #include <key.h> #include <node/caches.h> #include <node/context.h> // IWYU pragma: export +#include <optional> +#include <ostream> #include <primitives/transaction.h> #include <pubkey.h> #include <stdexcept> +#include <test/util/random.h> #include <util/chaintype.h> // IWYU pragma: export #include <util/check.h> #include <util/fs.h> @@ -24,9 +27,12 @@ #include <type_traits> #include <vector> +class arith_uint256; class CFeeRate; class Chainstate; class FastRandomContext; +class uint160; +class uint256; /** This is connected to the logger. Can be used to redirect logs to any other log */ extern const std::function<void(const std::string&)> G_TEST_LOG_FUN; @@ -37,17 +43,17 @@ extern const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUM /** Retrieve the unit test name. */ extern const std::function<std::string()> G_TEST_GET_FULL_NAME; -// Enable BOOST_CHECK_EQUAL for enum class types -namespace std { -template <typename T> -std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e) -{ - return stream << static_cast<typename std::underlying_type<T>::type>(e); -} -} // namespace std - 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}; + bool min_validation_cache{false}; // Equivalent of -maxsigcachebytes=0 +}; + /** Basic testing setup. * This just configures logging, data dir and chain parameters. */ @@ -55,12 +61,37 @@ 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 = {}); + FastRandomContext m_rng; + /** Seed the global RNG state and m_rng for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */ + void SeedRandomForTest(SeedRand seed) + { + SeedRandomStateForTest(seed); + m_rng.Reseed(GetRandHash()); + } + + explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {}); ~BasicTestingSetup(); fs::path m_path_root; fs::path m_path_lock; bool m_has_custom_datadir{false}; + /** @brief Test-specific arguments and settings. + * + * This member is intended to be the primary source of settings for code + * being tested by unit tests. It exists to make tests more self-contained + * and reduce reliance on global state. + * + * Usage guidelines: + * 1. Prefer using m_args where possible in test code. + * 2. If m_args is not accessible, use m_node.args as a fallback. + * 3. Avoid direct references to gArgs in test code. + * + * Note: Currently, m_node.args points to gArgs for backwards + * compatibility. In the future, it will point to m_args to further isolate + * test environments. + * + * @see https://github.com/bitcoin/bitcoin/issues/25055 for additional context. + */ ArgsManager m_args; }; @@ -72,8 +103,9 @@ struct ChainTestingSetup : public BasicTestingSetup { node::CacheSizes m_cache_sizes{}; bool m_coins_db_in_memory{true}; bool m_block_tree_db_in_memory{true}; + std::function<void()> m_make_chainman{}; - 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 +117,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 +136,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,22 +248,40 @@ 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_* @{ +namespace std { +template <typename T> requires std::is_enum_v<T> +inline std::ostream& operator<<(std::ostream& os, const T& e) +{ + return os << static_cast<std::underlying_type_t<T>>(e); +} + +template <typename T> +inline std::ostream& operator<<(std::ostream& os, const std::optional<T>& v) +{ + return v ? os << *v + : os << "std::nullopt"; +} +} // namespace std + +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); +// @} /** * BOOST_CHECK_EXCEPTION predicates to check the specific validation error. @@ -245,11 +291,9 @@ std::ostream& operator<<(std::ostream& os, const uint256& num); class HasReason { public: - explicit HasReason(const std::string& reason) : m_reason(reason) {} - bool operator()(const std::exception& e) const - { - return std::string(e.what()).find(m_reason) != std::string::npos; - }; + explicit HasReason(std::string_view reason) : m_reason(reason) {} + bool operator()(std::string_view s) const { return s.find(m_reason) != std::string_view::npos; } + bool operator()(const std::exception& e) const { return (*this)(e.what()); } private: const std::string m_reason; diff --git a/src/test/util/transaction_utils.cpp b/src/test/util/transaction_utils.cpp index 7e5bb30a2c..a588e61944 100644 --- a/src/test/util/transaction_utils.cpp +++ b/src/test/util/transaction_utils.cpp @@ -3,13 +3,14 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <coins.h> +#include <consensus/validation.h> #include <script/signingprovider.h> #include <test/util/transaction_utils.h> CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int nValue) { CMutableTransaction txCredit; - txCredit.nVersion = 1; + txCredit.version = 1; txCredit.nLockTime = 0; txCredit.vin.resize(1); txCredit.vout.resize(1); @@ -25,7 +26,7 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int n CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScriptWitness& scriptWitness, const CTransaction& txCredit) { CMutableTransaction txSpend; - txSpend.nVersion = 1; + txSpend.version = 1; txSpend.nLockTime = 0; txSpend.vin.resize(1); txSpend.vout.resize(1); @@ -69,3 +70,44 @@ std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keyst return dummyTransactions; } + +void BulkTransaction(CMutableTransaction& tx, int32_t target_weight) +{ + tx.vout.emplace_back(0, CScript() << OP_RETURN); + auto unpadded_weight{GetTransactionWeight(CTransaction(tx))}; + assert(target_weight >= unpadded_weight); + + // determine number of needed padding bytes by converting weight difference to vbytes + auto dummy_vbytes = (target_weight - unpadded_weight + (WITNESS_SCALE_FACTOR - 1)) / WITNESS_SCALE_FACTOR; + // compensate for the increase of the compact-size encoded script length + // (note that the length encoding of the unpadded output script needs one byte) + dummy_vbytes -= GetSizeOfCompactSize(dummy_vbytes) - 1; + + // pad transaction by repeatedly appending a dummy opcode to the output script + tx.vout[0].scriptPubKey.insert(tx.vout[0].scriptPubKey.end(), dummy_vbytes, OP_1); + + // actual weight should be at most 3 higher than target weight + assert(GetTransactionWeight(CTransaction(tx)) >= target_weight); + assert(GetTransactionWeight(CTransaction(tx)) <= target_weight + 3); +} + +bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data) +{ + assert(nIn < txTo.vin.size()); + + MutableTransactionSignatureCreator creator(txTo, nIn, amount, nHashType); + + bool ret = ProduceSignature(provider, creator, fromPubKey, sig_data); + UpdateInput(txTo.vin.at(nIn), sig_data); + return ret; +} + +bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, SignatureData& sig_data) +{ + assert(nIn < txTo.vin.size()); + const CTxIn& txin = txTo.vin[nIn]; + assert(txin.prevout.n < txFrom.vout.size()); + const CTxOut& txout = txFrom.vout[txin.prevout.n]; + + return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, sig_data); +} diff --git a/src/test/util/transaction_utils.h b/src/test/util/transaction_utils.h index 6f2faeec6c..4a18ab6ab4 100644 --- a/src/test/util/transaction_utils.h +++ b/src/test/util/transaction_utils.h @@ -6,6 +6,7 @@ #define BITCOIN_TEST_UTIL_TRANSACTION_UTILS_H #include <primitives/transaction.h> +#include <script/sign.h> #include <array> @@ -26,4 +27,27 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CSc // the second nValues[2] and nValues[3] outputs paid to a TxoutType::PUBKEYHASH. std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet, const std::array<CAmount,4>& nValues); +// bulk transaction to reach a certain target weight, +// by appending a single output with padded output script +void BulkTransaction(CMutableTransaction& tx, int32_t target_weight); + +/** + * Produce a satisfying script (scriptSig or witness). + * + * @param provider Utility containing the information necessary to solve a script. + * @param fromPubKey The script to produce a satisfaction for. + * @param txTo The spending transaction. + * @param nIn The index of the input in `txTo` referring the output being spent. + * @param amount The value of the output being spent. + * @param nHashType Signature hash type. + * @param sig_data Additional data provided to solve a script. Filled with the resulting satisfying + * script and whether the satisfaction is complete. + * + * @return True if the produced script is entirely satisfying `fromPubKey`. + **/ +bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, + unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data); +bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, + unsigned int nIn, int nHashType, SignatureData& sig_data); + #endif // BITCOIN_TEST_UTIL_TRANSACTION_UTILS_H diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp index 2657104e7d..9d6b4810d0 100644 --- a/src/test/util/txmempool.cpp +++ b/src/test/util/txmempool.cpp @@ -7,7 +7,8 @@ #include <chainparams.h> #include <node/context.h> #include <node/mempool_args.h> -#include <policy/v3_policy.h> +#include <policy/rbf.h> +#include <policy/truc_policy.h> #include <txmempool.h> #include <util/check.h> #include <util/time.h> @@ -68,6 +69,28 @@ std::optional<std::string> CheckPackageMempoolAcceptResult(const Package& txns, return strprintf("tx %s unexpectedly failed: %s", wtxid.ToString(), atmp_result.m_state.ToString()); } + // Each subpackage is allowed MAX_REPLACEMENT_CANDIDATES replacements (only checking individually here) + if (atmp_result.m_replaced_transactions.size() > MAX_REPLACEMENT_CANDIDATES) { + return strprintf("tx %s result replaced too many transactions", + wtxid.ToString()); + } + + // Replacements can't happen for subpackages larger than 2 + if (!atmp_result.m_replaced_transactions.empty() && + atmp_result.m_wtxids_fee_calculations.has_value() && atmp_result.m_wtxids_fee_calculations.value().size() > 2) { + return strprintf("tx %s was part of a too-large package RBF subpackage", + wtxid.ToString()); + } + + if (!atmp_result.m_replaced_transactions.empty() && mempool) { + LOCK(mempool->cs); + // If replacements occurred and it used 2 transactions, this is a package RBF and should result in a cluster of size 2 + if (atmp_result.m_wtxids_fee_calculations.has_value() && atmp_result.m_wtxids_fee_calculations.value().size() == 2) { + const auto cluster = mempool->GatherClusters({tx->GetHash()}); + if (cluster.size() != 2) return strprintf("tx %s has too many ancestors or descendants for a package rbf", wtxid.ToString()); + } + } + // m_vsize and m_base_fees should exist iff the result was VALID or MEMPOOL_ENTRY const bool mempool_entry{atmp_result.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY}; if (atmp_result.m_base_fees.has_value() != (valid || mempool_entry)) { @@ -108,37 +131,42 @@ std::optional<std::string> CheckPackageMempoolAcceptResult(const Package& txns, return strprintf("wtxid %s should not be in mempool", wtxid.ToString()); } } + for (const auto& tx_ref : atmp_result.m_replaced_transactions) { + if (mempool->exists(GenTxid::Txid(tx_ref->GetHash()))) { + return strprintf("tx %s should not be in mempool as it was replaced", tx_ref->GetWitnessHash().ToString()); + } + } } } return std::nullopt; } -void CheckMempoolV3Invariants(const CTxMemPool& tx_pool) +void CheckMempoolTRUCInvariants(const CTxMemPool& tx_pool) { LOCK(tx_pool.cs); for (const auto& tx_info : tx_pool.infoAll()) { const auto& entry = *Assert(tx_pool.GetEntry(tx_info.tx->GetHash())); - if (tx_info.tx->nVersion == 3) { + if (tx_info.tx->version == TRUC_VERSION) { // Check that special maximum virtual size is respected - Assert(entry.GetTxSize() <= V3_MAX_VSIZE); + Assert(entry.GetTxSize() <= TRUC_MAX_VSIZE); - // Check that special v3 ancestor/descendant limits and rules are always respected - Assert(entry.GetCountWithDescendants() <= V3_DESCENDANT_LIMIT); - Assert(entry.GetCountWithAncestors() <= V3_ANCESTOR_LIMIT); - Assert(entry.GetSizeWithDescendants() <= V3_MAX_VSIZE + V3_CHILD_MAX_VSIZE); - Assert(entry.GetSizeWithAncestors() <= V3_MAX_VSIZE + V3_CHILD_MAX_VSIZE); + // Check that special TRUC ancestor/descendant limits and rules are always respected + Assert(entry.GetCountWithDescendants() <= TRUC_DESCENDANT_LIMIT); + Assert(entry.GetCountWithAncestors() <= TRUC_ANCESTOR_LIMIT); + Assert(entry.GetSizeWithDescendants() <= TRUC_MAX_VSIZE + TRUC_CHILD_MAX_VSIZE); + Assert(entry.GetSizeWithAncestors() <= TRUC_MAX_VSIZE + TRUC_CHILD_MAX_VSIZE); // If this transaction has at least 1 ancestor, it's a "child" and has restricted weight. if (entry.GetCountWithAncestors() > 1) { - Assert(entry.GetTxSize() <= V3_CHILD_MAX_VSIZE); - // All v3 transactions must only have v3 unconfirmed parents. + Assert(entry.GetTxSize() <= TRUC_CHILD_MAX_VSIZE); + // All TRUC transactions must only have TRUC unconfirmed parents. const auto& parents = entry.GetMemPoolParentsConst(); - Assert(parents.begin()->get().GetSharedTx()->nVersion == 3); + Assert(parents.begin()->get().GetSharedTx()->version == TRUC_VERSION); } } else if (entry.GetCountWithAncestors() > 1) { - // All non-v3 transactions must only have non-v3 unconfirmed parents. + // All non-TRUC transactions must only have non-TRUC unconfirmed parents. for (const auto& parent : entry.GetMemPoolParentsConst()) { - Assert(parent.get().GetSharedTx()->nVersion != 3); + Assert(parent.get().GetSharedTx()->version != TRUC_VERSION); } } } diff --git a/src/test/util/txmempool.h b/src/test/util/txmempool.h index b3022af7df..6d41fdf87f 100644 --- a/src/test/util/txmempool.h +++ b/src/test/util/txmempool.h @@ -47,13 +47,13 @@ std::optional<std::string> CheckPackageMempoolAcceptResult(const Package& txns, bool expect_valid, const CTxMemPool* mempool); -/** For every transaction in tx_pool, check v3 invariants: - * - a v3 tx's ancestor count must be within V3_ANCESTOR_LIMIT - * - a v3 tx's descendant count must be within V3_DESCENDANT_LIMIT - * - if a v3 tx has ancestors, its sigop-adjusted vsize must be within V3_CHILD_MAX_VSIZE - * - any non-v3 tx must only have non-v3 parents - * - any v3 tx must only have v3 parents +/** For every transaction in tx_pool, check TRUC invariants: + * - a TRUC tx's ancestor count must be within TRUC_ANCESTOR_LIMIT + * - a TRUC tx's descendant count must be within TRUC_DESCENDANT_LIMIT + * - if a TRUC tx has ancestors, its sigop-adjusted vsize must be within TRUC_CHILD_MAX_VSIZE + * - any non-TRUC tx must only have non-TRUC parents + * - any TRUC tx must only have TRUC parents * */ -void CheckMempoolV3Invariants(const CTxMemPool& tx_pool); +void CheckMempoolTRUCInvariants(const CTxMemPool& tx_pool); #endif // BITCOIN_TEST_UTIL_TXMEMPOOL_H 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_string_tests.cpp b/src/test/util_string_tests.cpp new file mode 100644 index 0000000000..1574fe2358 --- /dev/null +++ b/src/test/util_string_tests.cpp @@ -0,0 +1,85 @@ +// 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 <util/string.h> + +#include <boost/test/unit_test.hpp> +#include <test/util/setup_common.h> + +using namespace util; + +BOOST_AUTO_TEST_SUITE(util_string_tests) + +// Helper to allow compile-time sanity checks while providing the number of +// args directly. Normally PassFmt<sizeof...(Args)> would be used. +template <unsigned NumArgs> +inline void PassFmt(util::ConstevalFormatString<NumArgs> fmt) +{ + // This was already executed at compile-time, but is executed again at run-time to avoid -Wunused. + decltype(fmt)::Detail_CheckNumFormatSpecifiers(fmt.fmt); +} +template <unsigned WrongNumArgs> +inline void FailFmtWithError(std::string_view wrong_fmt, std::string_view error) +{ + BOOST_CHECK_EXCEPTION(util::ConstevalFormatString<WrongNumArgs>::Detail_CheckNumFormatSpecifiers(wrong_fmt), const char*, HasReason(error)); +} + +BOOST_AUTO_TEST_CASE(ConstevalFormatString_NumSpec) +{ + PassFmt<0>(""); + PassFmt<0>("%%"); + PassFmt<1>("%s"); + PassFmt<0>("%%s"); + PassFmt<0>("s%%"); + PassFmt<1>("%%%s"); + PassFmt<1>("%s%%"); + PassFmt<0>(" 1$s"); + PassFmt<1>("%1$s"); + PassFmt<1>("%1$s%1$s"); + PassFmt<2>("%2$s"); + PassFmt<2>("%2$s 4$s %2$s"); + PassFmt<129>("%129$s 999$s %2$s"); + PassFmt<1>("%02d"); + PassFmt<1>("%+2s"); + PassFmt<1>("%.6i"); + PassFmt<1>("%5.2f"); + PassFmt<1>("%#x"); + PassFmt<1>("%1$5i"); + PassFmt<1>("%1$-5i"); + PassFmt<1>("%1$.5i"); + // tinyformat accepts almost any "type" spec, even '%', or '_', or '\n'. + PassFmt<1>("%123%"); + PassFmt<1>("%123%s"); + PassFmt<1>("%_"); + PassFmt<1>("%\n"); + + // The `*` specifier behavior is unsupported and can lead to runtime + // errors when used in a ConstevalFormatString. Please refer to the + // note in the ConstevalFormatString docs. + PassFmt<1>("%*c"); + PassFmt<2>("%2$*3$d"); + PassFmt<1>("%.*f"); + + auto err_mix{"Format specifiers must be all positional or all non-positional!"}; + FailFmtWithError<1>("%s%1$s", err_mix); + + auto err_num{"Format specifier count must match the argument count!"}; + FailFmtWithError<1>("", err_num); + FailFmtWithError<0>("%s", err_num); + FailFmtWithError<2>("%s", err_num); + FailFmtWithError<0>("%1$s", err_num); + FailFmtWithError<2>("%1$s", err_num); + + auto err_0_pos{"Positional format specifier must have position of at least 1"}; + FailFmtWithError<1>("%$s", err_0_pos); + FailFmtWithError<1>("%$", err_0_pos); + FailFmtWithError<0>("%0$", err_0_pos); + FailFmtWithError<0>("%0$s", err_0_pos); + + auto err_term{"Format specifier incorrectly terminated by end of string"}; + FailFmtWithError<1>("%", err_term); + FailFmtWithError<1>("%1$", err_term); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 9a2add748e..1624fb8b5b 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -3,8 +3,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <clientversion.h> +#include <common/signmessage.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC #include <hash.h> // For Hash() #include <key.h> // For CKey +#include <script/parsing.h> +#include <span.h> #include <sync.h> #include <test/util/random.h> #include <test/util/setup_common.h> @@ -12,11 +15,9 @@ #include <util/bitdeque.h> #include <util/fs.h> #include <util/fs_helpers.h> -#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC #include <util/moneystr.h> #include <util/overflow.h> #include <util/readwritefile.h> -#include <util/spanparsing.h> #include <util/strencodings.h> #include <util/string.h> #include <util/time.h> @@ -45,11 +46,22 @@ #include <boost/test/unit_test.hpp> using namespace std::literals; +using namespace util::hex_literals; +using util::ConstevalHexDigit; +using util::Join; +using util::RemovePrefix; +using util::RemovePrefixView; +using util::ReplaceAll; +using util::Split; +using util::SplitString; +using util::TrimString; +using util::TrimStringView; + 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) @@ -127,46 +139,69 @@ BOOST_AUTO_TEST_CASE(util_criticalsection) } while(0); } -static const unsigned char ParseHex_expected[65] = { +constexpr char HEX_PARSE_INPUT[] = "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"; +constexpr uint8_t HEX_PARSE_OUTPUT[] = { 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f }; +static_assert((sizeof(HEX_PARSE_INPUT) - 1) == 2 * sizeof(HEX_PARSE_OUTPUT)); BOOST_AUTO_TEST_CASE(parse_hex) { std::vector<unsigned char> result; - std::vector<unsigned char> expected(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)); + // Basic test vector - result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); + std::vector<unsigned char> expected(std::begin(HEX_PARSE_OUTPUT), std::end(HEX_PARSE_OUTPUT)); + constexpr std::array<std::byte, 65> hex_literal_array{operator""_hex<util::detail::Hex(HEX_PARSE_INPUT)>()}; + auto hex_literal_span{MakeUCharSpan(hex_literal_array)}; + BOOST_CHECK_EQUAL_COLLECTIONS(hex_literal_span.begin(), hex_literal_span.end(), expected.begin(), expected.end()); + + const std::vector<std::byte> hex_literal_vector{operator""_hex_v<util::detail::Hex(HEX_PARSE_INPUT)>()}; + hex_literal_span = MakeUCharSpan(hex_literal_vector); + BOOST_CHECK_EQUAL_COLLECTIONS(hex_literal_span.begin(), hex_literal_span.end(), expected.begin(), expected.end()); + + constexpr std::array<uint8_t, 65> hex_literal_array_uint8{operator""_hex_u8<util::detail::Hex(HEX_PARSE_INPUT)>()}; + BOOST_CHECK_EQUAL_COLLECTIONS(hex_literal_array_uint8.begin(), hex_literal_array_uint8.end(), expected.begin(), expected.end()); + + result = operator""_hex_v_u8<util::detail::Hex(HEX_PARSE_INPUT)>(); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); + + result = ParseHex(HEX_PARSE_INPUT); BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); - result = TryParseHex<uint8_t>("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").value(); + + result = TryParseHex<uint8_t>(HEX_PARSE_INPUT).value(); BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); // Spaces between bytes must be supported + expected = {0x12, 0x34, 0x56, 0x78}; result = ParseHex("12 34 56 78"); - BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); result = TryParseHex<uint8_t>("12 34 56 78").value(); - BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); // Leading space must be supported (used in BerkeleyEnvironment::Salvage) + expected = {0x89, 0x34, 0x56, 0x78}; result = ParseHex(" 89 34 56 78"); - BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); result = TryParseHex<uint8_t>(" 89 34 56 78").value(); - BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); // Mixed case and spaces are supported + expected = {0xff, 0xaa}; result = ParseHex(" Ff aA "); - BOOST_CHECK(result.size() == 2 && result[0] == 0xff && result[1] == 0xaa); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); result = TryParseHex<uint8_t>(" Ff aA ").value(); - BOOST_CHECK(result.size() == 2 && result[0] == 0xff && result[1] == 0xaa); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); // Empty string is supported - result = ParseHex(""); - BOOST_CHECK(result.size() == 0); - result = TryParseHex<uint8_t>("").value(); - BOOST_CHECK(result.size() == 0); + static_assert(""_hex.empty()); + static_assert(""_hex_u8.empty()); + BOOST_CHECK_EQUAL(""_hex_v.size(), 0); + BOOST_CHECK_EQUAL(""_hex_v_u8.size(), 0); + BOOST_CHECK_EQUAL(ParseHex("").size(), 0); + BOOST_CHECK_EQUAL(TryParseHex<uint8_t>("").value().size(), 0); // Spaces between nibbles is treated as invalid BOOST_CHECK_EQUAL(ParseHex("AAF F").size(), 0); @@ -189,25 +224,25 @@ BOOST_AUTO_TEST_CASE(parse_hex) BOOST_CHECK(!TryParseHex("12 3").has_value()); } -BOOST_AUTO_TEST_CASE(util_HexStr) +BOOST_AUTO_TEST_CASE(consteval_hex_digit) { - BOOST_CHECK_EQUAL( - HexStr(ParseHex_expected), - "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); - - BOOST_CHECK_EQUAL( - HexStr(Span{ParseHex_expected}.last(0)), - ""); + BOOST_CHECK_EQUAL(ConstevalHexDigit('0'), 0); + BOOST_CHECK_EQUAL(ConstevalHexDigit('9'), 9); + BOOST_CHECK_EQUAL(ConstevalHexDigit('a'), 0xa); + BOOST_CHECK_EQUAL(ConstevalHexDigit('f'), 0xf); +} - BOOST_CHECK_EQUAL( - HexStr(Span{ParseHex_expected}.first(0)), - ""); +BOOST_AUTO_TEST_CASE(util_HexStr) +{ + BOOST_CHECK_EQUAL(HexStr(HEX_PARSE_OUTPUT), HEX_PARSE_INPUT); + BOOST_CHECK_EQUAL(HexStr(Span{HEX_PARSE_OUTPUT}.last(0)), ""); + BOOST_CHECK_EQUAL(HexStr(Span{HEX_PARSE_OUTPUT}.first(0)), ""); { - const std::vector<char> in_s{ParseHex_expected, ParseHex_expected + 5}; + constexpr std::string_view out_exp{"04678afdb0"}; + constexpr std::span in_s{HEX_PARSE_OUTPUT, out_exp.size() / 2}; const Span<const uint8_t> in_u{MakeUCharSpan(in_s)}; const Span<const std::byte> in_b{MakeByteSpan(in_s)}; - const std::string out_exp{"04678afdb0"}; BOOST_CHECK_EQUAL(HexStr(in_u), out_exp); BOOST_CHECK_EQUAL(HexStr(in_s), out_exp); @@ -423,34 +458,9 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_CHECK(!IsHex("0x0000")); } -BOOST_AUTO_TEST_CASE(util_IsHexNumber) -{ - BOOST_CHECK(IsHexNumber("0x0")); - BOOST_CHECK(IsHexNumber("0")); - BOOST_CHECK(IsHexNumber("0x10")); - BOOST_CHECK(IsHexNumber("10")); - BOOST_CHECK(IsHexNumber("0xff")); - BOOST_CHECK(IsHexNumber("ff")); - BOOST_CHECK(IsHexNumber("0xFfa")); - BOOST_CHECK(IsHexNumber("Ffa")); - BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF")); - BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF")); - - BOOST_CHECK(!IsHexNumber("")); // empty string not allowed - BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed - BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end, - BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning, - BOOST_CHECK(!IsHexNumber("0x 0")); // or middle, - BOOST_CHECK(!IsHexNumber(" ")); // etc. - BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character - BOOST_CHECK(!IsHexNumber("x0")); // broken prefix - BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed - -} - BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); for (int mod=2;mod<11;mod++) { int mask = 1; @@ -464,7 +474,7 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) for (int i = 0; i < 10000; i++) { uint32_t rval; do{ - rval=InsecureRand32()&mask; + rval=m_rng.rand32()&mask; }while(rval>=(uint32_t)mod); count += rval==0; } @@ -1292,9 +1302,9 @@ static std::string SpanToStr(const Span<const char>& span) return std::string(span.begin(), span.end()); } -BOOST_AUTO_TEST_CASE(test_spanparsing) +BOOST_AUTO_TEST_CASE(test_script_parsing) { - using namespace spanparsing; + using namespace script; std::string input; Span<const char> sp; bool success; @@ -1499,8 +1509,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/util_threadnames_tests.cpp b/src/test/util_threadnames_tests.cpp index 174052d5fa..efa0b2736b 100644 --- a/src/test/util_threadnames_tests.cpp +++ b/src/test/util_threadnames_tests.cpp @@ -13,6 +13,8 @@ #include <boost/test/unit_test.hpp> +using util::ToString; + BOOST_AUTO_TEST_SUITE(util_threadnames_tests) const std::string TEST_THREAD_NAME_BASE = "test_thread."; diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 69f4e305ab..f5c4204c55 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -1,4 +1,4 @@ -// 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. @@ -65,7 +65,8 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash) static int i = 0; static uint64_t time = Params().GenesisBlock().nTime; - auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get()}.CreateNewBlock(CScript{} << i++ << OP_TRUE); + BlockAssembler::Options options; + auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(CScript{} << i++ << OP_TRUE); auto pblock = std::make_shared<CBlock>(ptemplate->block); pblock->hashPrevBlock = prev_hash; pblock->nTime = ++time; @@ -100,7 +101,7 @@ std::shared_ptr<CBlock> MinerTestingSetup::FinalizeBlock(std::shared_ptr<CBlock> // submit block header, so that miner can get the block height from the // global state and the node has the topology of the chain BlockValidationState ignored; - BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders({pblock->GetBlockHeader()}, true, ignored)); + BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders({{pblock->GetBlockHeader()}}, true, ignored)); return pblock; } @@ -132,8 +133,8 @@ void MinerTestingSetup::BuildChain(const uint256& root, int height, const unsign { if (height <= 0 || blocks.size() >= max_size) return; - bool gen_invalid = InsecureRandRange(100) < invalid_rate; - bool gen_fork = InsecureRandRange(100) < branch_rate; + bool gen_invalid = m_rng.randrange(100U) < invalid_rate; + bool gen_fork = m_rng.randrange(100U) < branch_rate; const std::shared_ptr<const CBlock> pblock = gen_invalid ? BadBlock(root) : GoodBlock(root); blocks.push_back(pblock); @@ -329,7 +330,8 @@ BOOST_AUTO_TEST_CASE(witness_commitment_index) LOCK(Assert(m_node.chainman)->GetMutex()); CScript pubKey; pubKey << 1 << OP_TRUE; - auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get()}.CreateNewBlock(pubKey); + BlockAssembler::Options options; + auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(pubKey); CBlock pblock = ptemplate->block; CTxOut witness; diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index 1c02066047..c9cca8af04 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -4,6 +4,7 @@ // #include <chainparams.h> #include <consensus/validation.h> +#include <node/kernel_notifications.h> #include <random.h> #include <rpc/blockchain.h> #include <sync.h> @@ -36,11 +37,11 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) // Add a coin to the in-memory cache, upsize once, then downsize. { LOCK(::cs_main); - const auto outpoint = AddTestCoin(c1.CoinsTip()); + const auto outpoint = AddTestCoin(m_rng, c1.CoinsTip()); // Set a meaningless bestblock value in the coinsview cache - otherwise we won't // flush during ResizecoinsCaches() and will subsequently hit an assertion. - c1.CoinsTip().SetBestBlock(InsecureRand256()); + c1.CoinsTip().SetBestBlock(m_rng.rand256()); BOOST_CHECK(c1.CoinsTip().HaveCoinInCache(outpoint)); @@ -69,14 +70,18 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup) { ChainstateManager& chainman = *Assert(m_node.chainman); - uint256 curr_tip = ::g_best_block; + const auto get_notify_tip{[&]() { + LOCK(m_node.notifications->m_tip_block_mutex); + return m_node.notifications->m_tip_block; + }}; + uint256 curr_tip = get_notify_tip(); // Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can // be found. mineBlocks(10); // After adding some blocks to the tip, best block should have changed. - BOOST_CHECK(::g_best_block != curr_tip); + BOOST_CHECK(get_notify_tip() != curr_tip); // Grab block 1 from disk; we'll add it to the background chain later. std::shared_ptr<CBlock> pblockone = std::make_shared<CBlock>(); @@ -91,15 +96,15 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup) // Ensure our active chain is the snapshot chainstate. BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.IsSnapshotActive())); - curr_tip = ::g_best_block; + curr_tip = get_notify_tip(); // Mine a new block on top of the activated snapshot chainstate. mineBlocks(1); // Defined in TestChain100Setup. // After adding some blocks to the snapshot tip, best block should have changed. - BOOST_CHECK(::g_best_block != curr_tip); + BOOST_CHECK(get_notify_tip() != curr_tip); - curr_tip = ::g_best_block; + curr_tip = get_notify_tip(); BOOST_CHECK_EQUAL(chainman.GetAll().size(), 2); @@ -135,10 +140,10 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup) // Ensure tip is as expected BOOST_CHECK_EQUAL(background_cs.m_chain.Tip()->GetBlockHash(), pblockone->GetHash()); - // g_best_block should be unchanged after adding a block to the background + // get_notify_tip() should be unchanged after adding a block to the background // validation chain. BOOST_CHECK(block_added); - BOOST_CHECK_EQUAL(curr_tip, ::g_best_block); + BOOST_CHECK_EQUAL(curr_tip, get_notify_tip()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 1f6b7368a2..6c2a825e64 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -5,6 +5,7 @@ #include <chainparams.h> #include <consensus/validation.h> #include <kernel/disconnected_transactions.h> +#include <node/chainstatemanager_args.h> #include <node/kernel_notifications.h> #include <node/utxo_snapshot.h> #include <random.h> @@ -16,6 +17,8 @@ #include <test/util/setup_common.h> #include <test/util/validation.h> #include <uint256.h> +#include <util/result.h> +#include <util/vector.h> #include <validation.h> #include <validationinterface.h> @@ -152,10 +155,10 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_rebalance_caches, TestChain100Setup) manager.MaybeRebalanceCaches(); } - BOOST_CHECK_CLOSE(c1.m_coinstip_cache_size_bytes, max_cache * 0.05, 1); - BOOST_CHECK_CLOSE(c1.m_coinsdb_cache_size_bytes, max_cache * 0.05, 1); - BOOST_CHECK_CLOSE(c2.m_coinstip_cache_size_bytes, max_cache * 0.95, 1); - BOOST_CHECK_CLOSE(c2.m_coinsdb_cache_size_bytes, max_cache * 0.95, 1); + BOOST_CHECK_CLOSE(double(c1.m_coinstip_cache_size_bytes), max_cache * 0.05, 1); + BOOST_CHECK_CLOSE(double(c1.m_coinsdb_cache_size_bytes), max_cache * 0.05, 1); + BOOST_CHECK_CLOSE(double(c2.m_coinstip_cache_size_bytes), max_cache * 0.95, 1); + BOOST_CHECK_CLOSE(double(c2.m_coinsdb_cache_size_bytes), max_cache * 0.95, 1); } struct SnapshotTestSetup : TestChain100Setup { @@ -167,9 +170,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 +288,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()}; @@ -378,7 +382,7 @@ struct SnapshotTestSetup : TestChain100Setup { LOCK(::cs_main); chainman.ResetChainstates(); BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0); - m_node.notifications = std::make_unique<KernelNotifications>(*Assert(m_node.shutdown), m_node.exit_status); + m_node.notifications = std::make_unique<KernelNotifications>(Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)); const ChainstateManager::Options chainman_opts{ .chainparams = ::Params(), .datadir = chainman.m_options.datadir, @@ -393,7 +397,7 @@ struct SnapshotTestSetup : TestChain100Setup { // For robustness, ensure the old manager is destroyed before creating a // new one. m_node.chainman.reset(); - m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts); + m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown_signal), chainman_opts, blockman_opts); } return *Assert(m_node.chainman); } @@ -464,7 +468,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; @@ -714,10 +718,10 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, Sna CCoinsViewCache& ibd_coins = WITH_LOCK(::cs_main, return validation_chainstate.CoinsTip()); Coin badcoin; - badcoin.out.nValue = InsecureRand32(); + badcoin.out.nValue = m_rng.rand32(); badcoin.nHeight = 1; - badcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); - Txid txid = Txid::FromUint256(InsecureRand256()); + badcoin.out.scriptPubKey.assign(m_rng.randbits(6), 0); + Txid txid = Txid::FromUint256(m_rng.rand256()); ibd_coins.AddCoin(COutPoint(txid, 0), std::move(badcoin), false); fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot"; @@ -768,4 +772,63 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, Sna } } +/** Helper function to parse args into args_man and return the result of applying them to opts */ +template <typename Options> +util::Result<Options> SetOptsFromArgs(ArgsManager& args_man, Options opts, + const std::vector<const char*>& args) +{ + const auto argv{Cat({"ignore"}, args)}; + std::string error{}; + if (!args_man.ParseParameters(argv.size(), argv.data(), error)) { + return util::Error{Untranslated("ParseParameters failed with error: " + error)}; + } + const auto result{node::ApplyArgsManOptions(args_man, opts)}; + if (!result) return util::Error{util::ErrorString(result)}; + return opts; +} + +BOOST_FIXTURE_TEST_CASE(chainstatemanager_args, BasicTestingSetup) +{ + //! Try to apply the provided args to a ChainstateManager::Options + auto get_opts = [&](const std::vector<const char*>& args) { + static kernel::Notifications notifications{}; + static const ChainstateManager::Options options{ + .chainparams = ::Params(), + .datadir = {}, + .notifications = notifications}; + return SetOptsFromArgs(*this->m_node.args, options, args); + }; + //! Like get_opts, but requires the provided args to be valid and unwraps the result + auto get_valid_opts = [&](const std::vector<const char*>& args) { + const auto result{get_opts(args)}; + BOOST_REQUIRE_MESSAGE(result, util::ErrorString(result).original); + return *result; + }; + + // test -assumevalid + BOOST_CHECK(!get_valid_opts({}).assumed_valid_block); + BOOST_CHECK_EQUAL(get_valid_opts({"-assumevalid="}).assumed_valid_block, uint256::ZERO); + BOOST_CHECK_EQUAL(get_valid_opts({"-assumevalid=0"}).assumed_valid_block, uint256::ZERO); + BOOST_CHECK_EQUAL(get_valid_opts({"-noassumevalid"}).assumed_valid_block, uint256::ZERO); + BOOST_CHECK_EQUAL(get_valid_opts({"-assumevalid=0x12"}).assumed_valid_block, uint256{0x12}); + + std::string assume_valid{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}; + BOOST_CHECK_EQUAL(get_valid_opts({("-assumevalid=" + assume_valid).c_str()}).assumed_valid_block, uint256::FromHex(assume_valid)); + + BOOST_CHECK(!get_opts({"-assumevalid=xyz"})); // invalid hex characters + BOOST_CHECK(!get_opts({"-assumevalid=01234567890123456789012345678901234567890123456789012345678901234"})); // > 64 hex chars + + // test -minimumchainwork + BOOST_CHECK(!get_valid_opts({}).minimum_chain_work); + BOOST_CHECK_EQUAL(get_valid_opts({"-minimumchainwork=0"}).minimum_chain_work, arith_uint256()); + BOOST_CHECK_EQUAL(get_valid_opts({"-nominimumchainwork"}).minimum_chain_work, arith_uint256()); + BOOST_CHECK_EQUAL(get_valid_opts({"-minimumchainwork=0x1234"}).minimum_chain_work, arith_uint256{0x1234}); + + std::string minimum_chainwork{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}; + BOOST_CHECK_EQUAL(get_valid_opts({("-minimumchainwork=" + minimum_chainwork).c_str()}).minimum_chain_work, UintToArith256(uint256::FromHex(minimum_chainwork).value())); + + BOOST_CHECK(!get_opts({"-minimumchainwork=xyz"})); // invalid hex characters + BOOST_CHECK(!get_opts({"-minimumchainwork=01234567890123456789012345678901234567890123456789012345678901234"})); // > 64 hex chars +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp index 7398091215..c325f7deb2 100644 --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Add a bunch of coins to see that we at least flip over to CRITICAL. for (int i{0}; i < 1000; ++i) { - const COutPoint res = AddTestCoin(view); + const COutPoint res = AddTestCoin(m_rng, view); BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); } @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) CoinsCacheSizeState::OK); for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) { - const COutPoint res = AddTestCoin(view); + const COutPoint res = AddTestCoin(m_rng, view); print_view_mem_usage(view); BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Adding some additional coins will push us over the edge to CRITICAL. for (int i{0}; i < 4; ++i) { - AddTestCoin(view); + AddTestCoin(m_rng, view); print_view_mem_usage(view); if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0) == CoinsCacheSizeState::CRITICAL) { @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) CoinsCacheSizeState::OK); for (int i{0}; i < 3; ++i) { - AddTestCoin(view); + AddTestCoin(m_rng, view); print_view_mem_usage(view); BOOST_CHECK_EQUAL( chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/ 1 << 19), @@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Adding another coin with the additional mempool room will put us >90% // but not yet critical. - AddTestCoin(view); + AddTestCoin(m_rng, view); print_view_mem_usage(view); // Only perform these checks on 64 bit hosts; I haven't done the math for 32. @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Using the default max_* values permits way more coins to be added. for (int i{0}; i < 1000; ++i) { - AddTestCoin(view); + AddTestCoin(m_rng, view); BOOST_CHECK_EQUAL( chainstate.GetCoinsCacheSizeState(), CoinsCacheSizeState::OK); @@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0), CoinsCacheSizeState::CRITICAL); - view.SetBestBlock(InsecureRand256()); + view.SetBestBlock(m_rng.rand256()); BOOST_CHECK(view.Flush()); print_view_mem_usage(view); 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..29240a45f0 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -67,6 +67,7 @@ public: class VersionBitsTester { + FastRandomContext& m_rng; // A fake blockchain std::vector<CBlockIndex*> vpblock; @@ -85,6 +86,8 @@ class VersionBitsTester int num{1000}; public: + VersionBitsTester(FastRandomContext& rng) : m_rng{rng} {} + VersionBitsTester& Reset() { // Have each group of tests be counted by the 1000s part, starting at 1000 num = num - (num % 1000) + 1000; @@ -128,7 +131,7 @@ public: { const CBlockIndex* tip = Tip(); for (int i = 0; i < CHECKERS; i++) { - if (InsecureRandBits(i) == 0) { + if (m_rng.randbits(i) == 0) { BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(tip) == height, strprintf("Test %i for StateSinceHeight", num)); BOOST_CHECK_MESSAGE(checker_delayed[i].GetStateSinceHeightFor(tip) == height_delayed, strprintf("Test %i for StateSinceHeight (delayed)", num)); BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (always active)", num)); @@ -154,7 +157,7 @@ public: const CBlockIndex* pindex = Tip(); for (int i = 0; i < CHECKERS; i++) { - if (InsecureRandBits(i) == 0) { + if (m_rng.randbits(i) == 0) { ThresholdState got = checker[i].GetStateFor(pindex); ThresholdState got_delayed = checker_delayed[i].GetStateFor(pindex); ThresholdState got_always = checker_always[i].GetStateFor(pindex); @@ -190,7 +193,7 @@ BOOST_AUTO_TEST_CASE(versionbits_test) { for (int i = 0; i < 64; i++) { // DEFINED -> STARTED after timeout reached -> FAILED - VersionBitsTester().TestDefined().TestStateSinceHeight(0) + VersionBitsTester(m_rng).TestDefined().TestStateSinceHeight(0) .Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0) .Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0) .Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0) @@ -256,8 +259,9 @@ BOOST_AUTO_TEST_CASE(versionbits_test) } } +struct BlockVersionTest : BasicTestingSetup { /** Check that ComputeBlockVersion will set the appropriate bit correctly */ -static void check_computeblockversion(VersionBitsCache& versionbitscache, const Consensus::Params& params, Consensus::DeploymentPos dep) +void check_computeblockversion(VersionBitsCache& versionbitscache, const Consensus::Params& params, Consensus::DeploymentPos dep) { // Clear the cache every time versionbitscache.Clear(); @@ -295,7 +299,7 @@ static void check_computeblockversion(VersionBitsCache& versionbitscache, const // In the first chain, test that the bit is set by CBV until it has failed. // In the second chain, test the bit is set by CBV while STARTED and // LOCKED-IN, and then no longer set while ACTIVE. - VersionBitsTester firstChain, secondChain; + VersionBitsTester firstChain{m_rng}, secondChain{m_rng}; int64_t nTime = nStartTime; @@ -412,14 +416,15 @@ static void check_computeblockversion(VersionBitsCache& versionbitscache, const // Check that we don't signal after activation BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); } +}; // struct BlockVersionTest -BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) +BOOST_FIXTURE_TEST_CASE(versionbits_computeblockversion, BlockVersionTest) { VersionBitsCache vbcache; // 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/torcontrol.cpp b/src/torcontrol.cpp index 442c1c4d42..58fc1bdf2a 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -42,6 +42,10 @@ #include <event2/thread.h> #include <event2/util.h> +using util::ReplaceAll; +using util::SplitString; +using util::ToString; + /** Default control ip and port */ const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:" + ToString(DEFAULT_TOR_CONTROL_PORT); /** Tor cookie size (from control-spec.txt) */ @@ -106,7 +110,7 @@ void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) self->reply_handlers.front()(*self, self->message); self->reply_handlers.pop_front(); } else { - LogPrint(BCLog::TOR, "Received unexpected sync reply %i\n", self->message.code); + LogDebug(BCLog::TOR, "Received unexpected sync reply %i\n", self->message.code); } } self->message.Clear(); @@ -125,13 +129,13 @@ void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ct { TorControlConnection *self = static_cast<TorControlConnection*>(ctx); if (what & BEV_EVENT_CONNECTED) { - LogPrint(BCLog::TOR, "Successfully connected!\n"); + LogDebug(BCLog::TOR, "Successfully connected!\n"); self->connected(*self); } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { if (what & BEV_EVENT_ERROR) { - LogPrint(BCLog::TOR, "Error connecting to Tor control socket\n"); + LogDebug(BCLog::TOR, "Error connecting to Tor control socket\n"); } else { - LogPrint(BCLog::TOR, "End of stream\n"); + LogDebug(BCLog::TOR, "End of stream\n"); } self->Disconnect(); self->disconnected(*self); @@ -330,7 +334,7 @@ TorController::TorController(struct event_base* _base, const std::string& tor_co // Read service private key if cached std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile()); if (pkf.first) { - LogPrint(BCLog::TOR, "Reading cached private key from %s\n", fs::PathToString(GetPrivateKeyFile())); + LogDebug(BCLog::TOR, "Reading cached private key from %s\n", fs::PathToString(GetPrivateKeyFile())); private_key = pkf.second; } } @@ -371,7 +375,7 @@ void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlRe } } if (!socks_location.empty()) { - LogPrint(BCLog::TOR, "Get SOCKS port command yielded %s\n", socks_location); + LogDebug(BCLog::TOR, "Get SOCKS port command yielded %s\n", socks_location); } else { LogPrintf("tor: Get SOCKS port command returned nothing\n"); } @@ -392,7 +396,7 @@ void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlRe } Assume(resolved.IsValid()); - LogPrint(BCLog::TOR, "Configuring onion proxy for %s\n", resolved.ToStringAddrPort()); + LogDebug(BCLog::TOR, "Configuring onion proxy for %s\n", resolved.ToStringAddrPort()); Proxy addrOnion = Proxy(resolved, true); SetProxy(NET_ONION, addrOnion); @@ -416,7 +420,7 @@ void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlRe void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrint(BCLog::TOR, "ADD_ONION successful\n"); + LogDebug(BCLog::TOR, "ADD_ONION successful\n"); for (const std::string &s : reply.lines) { std::map<std::string,std::string> m = ParseTorReplyMapping(s); std::map<std::string,std::string>::iterator i; @@ -435,7 +439,7 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe service = LookupNumeric(std::string(service_id+".onion"), Params().GetDefaultPort()); LogInfo("Got tor service ID %s, advertising service %s\n", service_id, service.ToStringAddrPort()); if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { - LogPrint(BCLog::TOR, "Cached service private key to %s\n", fs::PathToString(GetPrivateKeyFile())); + LogDebug(BCLog::TOR, "Cached service private key to %s\n", fs::PathToString(GetPrivateKeyFile())); } else { LogPrintf("tor: Error writing service private key to %s\n", fs::PathToString(GetPrivateKeyFile())); } @@ -451,7 +455,7 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrint(BCLog::TOR, "Authentication successful\n"); + LogDebug(BCLog::TOR, "Authentication successful\n"); // Now that we know Tor is running setup the proxy for onion addresses // if -onion isn't set to something else. @@ -502,7 +506,7 @@ static std::vector<uint8_t> ComputeResponse(const std::string &key, const std::v void TorController::authchallenge_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrint(BCLog::TOR, "SAFECOOKIE authentication challenge successful\n"); + LogDebug(BCLog::TOR, "SAFECOOKIE authentication challenge successful\n"); std::pair<std::string,std::string> l = SplitTorReplyLine(reply.lines[0]); if (l.first == "AUTHCHALLENGE") { std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); @@ -512,7 +516,7 @@ void TorController::authchallenge_cb(TorControlConnection& _conn, const TorContr } std::vector<uint8_t> serverHash = ParseHex(m["SERVERHASH"]); std::vector<uint8_t> serverNonce = ParseHex(m["SERVERNONCE"]); - LogPrint(BCLog::TOR, "AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce)); + LogDebug(BCLog::TOR, "AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce)); if (serverNonce.size() != 32) { LogPrintf("tor: ServerNonce is not 32 bytes, as required by spec\n"); return; @@ -559,12 +563,12 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); std::map<std::string,std::string>::iterator i; if ((i = m.find("Tor")) != m.end()) { - LogPrint(BCLog::TOR, "Connected to Tor version %s\n", i->second); + LogDebug(BCLog::TOR, "Connected to Tor version %s\n", i->second); } } } for (const std::string &s : methods) { - LogPrint(BCLog::TOR, "Supported authentication method: %s\n", s); + LogDebug(BCLog::TOR, "Supported authentication method: %s\n", s); } // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD /* Authentication: @@ -574,18 +578,18 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro std::string torpassword = gArgs.GetArg("-torpassword", ""); if (!torpassword.empty()) { if (methods.count("HASHEDPASSWORD")) { - LogPrint(BCLog::TOR, "Using HASHEDPASSWORD authentication\n"); + LogDebug(BCLog::TOR, "Using HASHEDPASSWORD authentication\n"); ReplaceAll(torpassword, "\"", "\\\""); _conn.Command("AUTHENTICATE \"" + torpassword + "\"", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); } else { LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); } } else if (methods.count("NULL")) { - LogPrint(BCLog::TOR, "Using NULL authentication\n"); + LogDebug(BCLog::TOR, "Using NULL authentication\n"); _conn.Command("AUTHENTICATE", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); } else if (methods.count("SAFECOOKIE")) { // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie - LogPrint(BCLog::TOR, "Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); + LogDebug(BCLog::TOR, "Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); std::pair<bool,std::string> status_cookie = ReadBinaryFile(fs::PathFromString(cookiefile), TOR_COOKIE_SIZE); if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); @@ -627,7 +631,7 @@ void TorController::disconnected_cb(TorControlConnection& _conn) if (!reconnect) return; - LogPrint(BCLog::TOR, "Not connected to Tor control port %s, trying to reconnect\n", m_tor_control_center); + LogDebug(BCLog::TOR, "Not connected to Tor control port %s, trying to reconnect\n", m_tor_control_center); // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); diff --git a/src/txdb.cpp b/src/txdb.cpp index e4a4b3bf72..9b43a2b03e 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,9 +124,9 @@ 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)); + LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); m_db->WriteBatch(batch); batch.Clear(); if (m_options.simulate_crash_ratio) { @@ -143,9 +143,9 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo batch.Erase(DB_HEAD_BLOCKS); batch.Write(DB_BEST_BLOCK, hashBlock); - LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); + LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); bool ret = m_db->WriteBatch(batch); - LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); + LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); return ret; } diff --git a/src/txdb.h b/src/txdb.h index c9af0a091e..412d6c6009 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -25,8 +25,6 @@ class uint256; static const int64_t nDefaultDbCache = 450; //! -dbbatchsize default (bytes) static const int64_t nDefaultDbBatchSize = 16 << 20; -//! max. -dbcache (MiB) -static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; //! min. -dbcache (MiB) static const int64_t nMinDbCache = 4; //! Max memory allocated to block tree DB specific cache, if no -txindex (MiB) @@ -63,7 +61,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 c845944d32..f8f5ec0360 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -15,7 +15,7 @@ #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> #include <util/moneystr.h> @@ -26,9 +26,11 @@ #include <util/translation.h> #include <validationinterface.h> +#include <algorithm> #include <cmath> #include <numeric> #include <optional> +#include <ranges> #include <string_view> #include <utility> @@ -119,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()) { @@ -395,8 +397,19 @@ void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee, assert(int(nSigOpCostWithAncestors) >= 0); } -CTxMemPool::CTxMemPool(const Options& opts) - : m_opts{opts} +//! Clamp option values and populate the error if options are not valid. +static CTxMemPool::Options&& Flatten(CTxMemPool::Options&& opts, bilingual_str& error) +{ + opts.check_ratio = std::clamp<int>(opts.check_ratio, 0, 1'000'000); + int64_t descendant_limit_bytes = opts.limits.descendant_size_vbytes * 40; + if (opts.max_size_bytes < 0 || opts.max_size_bytes < descendant_limit_bytes) { + error = strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0)); + } + return std::move(opts); +} + +CTxMemPool::CTxMemPool(Options opts, bilingual_str& error) + : m_opts{Flatten(std::move(opts), error)} { } @@ -644,11 +657,11 @@ 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); - LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); + LogDebug(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); uint64_t checkTotal = 0; CAmount check_total_fee{0}; @@ -1023,7 +1036,7 @@ void CTxMemPool::RemoveUnbroadcastTx(const uint256& txid, const bool unchecked) if (m_unbroadcast_txids.erase(txid)) { - LogPrint(BCLog::MEMPOOL, "Removed %i from set of unbroadcast txns%s\n", txid.GetHex(), (unchecked ? " before confirmation that txn was sent out" : "")); + LogDebug(BCLog::MEMPOOL, "Removed %i from set of unbroadcast txns%s\n", txid.GetHex(), (unchecked ? " before confirmation that txn was sent out" : "")); } } @@ -1151,7 +1164,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends } if (maxFeeRateRemoved > CFeeRate(0)) { - LogPrint(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); + LogDebug(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); } } diff --git a/src/txmempool.h b/src/txmempool.h index c9f6cdbfac..d0cb41a078 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -43,6 +43,8 @@ class CChain; class ValidationSignals; +struct bilingual_str; + /** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */ static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF; @@ -327,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 @@ -357,6 +357,10 @@ public: CompareTxMemPoolEntryByAncestorFee > > + {}; + typedef boost::multi_index_container< + CTxMemPoolEntry, + CTxMemPoolEntry_Indices > indexed_transaction_set; /** @@ -364,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 @@ -374,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 @@ -442,7 +443,7 @@ public: * accepting transactions becomes O(N^2) where N is the number of transactions * in the pool. */ - explicit CTxMemPool(const Options& opts); + explicit CTxMemPool(Options opts, bilingual_str& error); /** * If sanity-checking is turned on, check makes sure the pool is diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp index 3eaf53939d..ba4ba6c3b6 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)) @@ -37,31 +29,24 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) unsigned int sz = GetTransactionWeight(*tx); if (sz > MAX_STANDARD_TX_WEIGHT) { - LogPrint(BCLog::TXPACKAGES, "ignoring large orphan tx (size: %u, txid: %s, wtxid: %s)\n", sz, hash.ToString(), wtxid.ToString()); + LogDebug(BCLog::TXPACKAGES, "ignoring large orphan tx (size: %u, txid: %s, wtxid: %s)\n", sz, hash.ToString(), wtxid.ToString()); return false; } - auto ret = m_orphans.emplace(wtxid, OrphanTx{tx, peer, Now<NodeSeconds>() + ORPHAN_TX_EXPIRE_TIME, m_orphan_list.size()}); + auto ret = m_orphans.emplace(wtxid, OrphanTx{{tx, peer, Now<NodeSeconds>() + ORPHAN_TX_EXPIRE_TIME}, m_orphan_list.size()}); assert(ret.second); m_orphan_list.push_back(ret.first); for (const CTxIn& txin : tx->vin) { m_outpoint_to_orphan_it[txin.prevout].insert(ret.first); } - LogPrint(BCLog::TXPACKAGES, "stored orphan tx %s (wtxid=%s), weight: %u (mapsz %u outsz %u)\n", hash.ToString(), wtxid.ToString(), sz, + LogDebug(BCLog::TXPACKAGES, "stored orphan tx %s (wtxid=%s), weight: %u (mapsz %u outsz %u)\n", hash.ToString(), wtxid.ToString(), sz, m_orphans.size(), m_outpoint_to_orphan_it.size()); return true; } 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; @@ -87,7 +72,7 @@ int TxOrphanage::EraseTxNoLock(const Wtxid& wtxid) const auto& txid = it->second.tx->GetHash(); // Time spent in orphanage = difference between current and entry time. // Entry time is equal to ORPHAN_TX_EXPIRE_TIME earlier than entry's expiry. - LogPrint(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s) after %ds\n", txid.ToString(), wtxid.ToString(), + LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s) after %ds\n", txid.ToString(), wtxid.ToString(), Ticks<std::chrono::seconds>(NodeClock::now() + ORPHAN_TX_EXPIRE_TIME - it->second.nTimeExpire)); m_orphan_list.pop_back(); @@ -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,16 +91,14 @@ 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); + if (nErased > 0) LogDebug(BCLog::TXPACKAGES, "Erased %d orphan transaction(s) from peer=%d\n", nErased, 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,30 +110,27 @@ 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); } } // Sweep again 5 minutes after the next entry that expires in order to batch the linear scan. m_next_sweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL; - if (nErased > 0) LogPrint(BCLog::TXPACKAGES, "Erased %d orphan tx due to expiration\n", nErased); + if (nErased > 0) LogDebug(BCLog::TXPACKAGES, "Erased %d orphan tx due to expiration\n", nErased); } while (m_orphans.size() > max_orphans) { // 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); + if (nEvicted > 0) LogDebug(BCLog::TXPACKAGES, "orphanage overflow, removed %u tx\n", nEvicted); } 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()) { @@ -162,7 +140,7 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx) std::set<Wtxid>& orphan_work_set = m_peer_work_set.try_emplace(elem->second.fromPeer).first->second; // Add this tx to the work set orphan_work_set.insert(elem->first); - LogPrint(BCLog::TXPACKAGES, "added %s (wtxid=%s) to peer %d workset\n", + LogDebug(BCLog::TXPACKAGES, "added %s (wtxid=%s) to peer %d workset\n", tx.GetHash().ToString(), tx.GetWitnessHash().ToString(), elem->second.fromPeer); } } @@ -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,16 +202,14 @@ 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); + LogDebug(BCLog::TXPACKAGES, "Erased %d orphan transaction(s) included or conflicted by block\n", nErased); } } 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; @@ -310,3 +277,13 @@ std::vector<std::pair<CTransactionRef, NodeId>> TxOrphanage::GetChildrenFromDiff } return children_found; } + +std::vector<TxOrphanage::OrphanTxBase> TxOrphanage::GetOrphanTransactions() const +{ + std::vector<OrphanTxBase> ret; + ret.reserve(m_orphans.size()); + for (auto const& o : m_orphans) { + ret.push_back({o.second.tx, o.second.fromPeer, o.second.nTimeExpire}); + } + return ret; +} diff --git a/src/txorphanage.h b/src/txorphanage.h index 3054396b2d..5501d10922 100644 --- a/src/txorphanage.h +++ b/src/txorphanage.h @@ -14,76 +14,84 @@ #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 { + /** Allows providing orphan information externally */ + struct OrphanTxBase { CTransactionRef tx; NodeId fromPeer; NodeSeconds nTimeExpire; + }; + + std::vector<OrphanTxBase> GetOrphanTransactions() const; + +protected: + struct OrphanTx : public OrphanTxBase { size_t list_pos; }; /** 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); @@ -92,22 +100,19 @@ protected: template<typename I> bool operator()(const I& a, const I& b) const { - return &(*a) < &(*b); + return a->first < b->first; } }; /** 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..8223787041 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,13 +8,17 @@ #include <crypto/common.h> #include <span.h> +#include <util/strencodings.h> +#include <util/string.h> #include <algorithm> #include <array> #include <cassert> +#include <cstdint> #include <cstring> -#include <stdint.h> +#include <optional> #include <string> +#include <string_view> /** Template base class for fixed-sized opaque blobs. */ template<unsigned int BITS> @@ -39,6 +43,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 +57,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 +124,60 @@ public: } }; +template <unsigned int BITS> +consteval base_blob<BITS>::base_blob(std::string_view hex_str) +{ + if (hex_str.length() != m_data.size() * 2) throw "Hex string must fit exactly"; + auto str_it = hex_str.rbegin(); + for (auto& elem : m_data) { + auto lo = util::ConstevalHexDigit(*(str_it++)); + elem = (util::ConstevalHexDigit(*(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; +} +/** + * @brief Like FromHex(std::string_view str), but allows an "0x" prefix + * and pads the input with leading zeroes if it is shorter than + * the expected length of uintN_t::size()*2. + * + * Designed to be used when dealing with user input. + */ +template <class uintN_t> +std::optional<uintN_t> FromUserHex(std::string_view input) +{ + input = util::RemovePrefixView(input, "0x"); + constexpr auto expected_size{uintN_t::size() * 2}; + if (input.size() < expected_size) { + auto padded = std::string(expected_size, '0'); + std::copy(input.begin(), input.end(), padded.begin() + expected_size - input.size()); + return FromHex<uintN_t>(padded); + } + return FromHex<uintN_t>(input); +} +} // 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,32 +189,14 @@ public: */ class uint256 : public base_blob<256> { public: + static std::optional<uint256> FromHex(std::string_view str) { return detail::FromHex<uint256>(str); } + static std::optional<uint256> FromUserHex(std::string_view str) { return detail::FromUserHex<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*). - */ -inline uint256 uint256S(const std::string& str) -{ - uint256 rv; - rv.SetHex(str); - return rv; -} - #endif // BITCOIN_UINT256_H diff --git a/src/univalue/.gitignore b/src/univalue/.gitignore deleted file mode 100644 index 19e42f814a..0000000000 --- a/src/univalue/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -.deps/ -INSTALL -Makefile -Makefile.in -aclocal.m4 -autom4te.cache/ -compile -config.log -config.status -config.guess -config.sub -configure -depcomp -install-sh -missing -stamp-h1 -univalue-config.h* -test-driver -libtool -ltmain.sh -test-suite.log - -*.a -*.la -*.lo -*.logs -*.o -*.pc -*.trs - -.dirstamp -.libs diff --git a/src/univalue/CMakeLists.txt b/src/univalue/CMakeLists.txt new file mode 100644 index 0000000000..96733fe077 --- /dev/null +++ b/src/univalue/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_library(univalue STATIC EXCLUDE_FROM_ALL + lib/univalue.cpp + lib/univalue_get.cpp + lib/univalue_read.cpp + lib/univalue_write.cpp +) +target_include_directories(univalue + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> +) +target_link_libraries(univalue PRIVATE core_interface) + +if(BUILD_TESTS) + add_executable(unitester test/unitester.cpp) + target_compile_definitions(unitester + PRIVATE + JSON_TEST_SRC=\"${CMAKE_CURRENT_SOURCE_DIR}/test\" + ) + target_link_libraries(unitester + PRIVATE + core_interface + univalue + ) + add_test(NAME univalue_test + COMMAND unitester + ) + + add_executable(object test/object.cpp) + target_link_libraries(object + PRIVATE + core_interface + univalue + ) + add_test(NAME univalue_object_test + COMMAND object + ) +endif() diff --git a/src/univalue/lib/.gitignore b/src/univalue/lib/.gitignore deleted file mode 100644 index ee7fc2851c..0000000000 --- a/src/univalue/lib/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gen -.libs diff --git a/src/univalue/sources.mk b/src/univalue/sources.mk deleted file mode 100644 index 5e4d9c3831..0000000000 --- a/src/univalue/sources.mk +++ /dev/null @@ -1,86 +0,0 @@ -# - All Variables ending in _HEADERS or _SOURCES confuse automake, so the -# _INT postfix is applied. -# - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used -# as they interfere with automatic dependency generation -# - The %reldir% is the relative path from the Makefile.am. - -UNIVALUE_INCLUDE_DIR_INT = %reldir%/include - -UNIVALUE_DIST_HEADERS_INT = -UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue.h -UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue_utffilter.h -UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue_escapes.h - -UNIVALUE_LIB_SOURCES_INT = -UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue.cpp -UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_get.cpp -UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_read.cpp -UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_write.cpp - -UNIVALUE_TEST_DATA_DIR_INT = %reldir%/test - -UNIVALUE_TEST_UNITESTER_INT = -UNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp - -UNIVALUE_TEST_JSON_INT = -UNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp - -UNIVALUE_TEST_OBJECT_INT = -UNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp - -UNIVALUE_TEST_FILES_INT = -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail1.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail2.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail3.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail4.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail5.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail6.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail7.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail8.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail9.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail10.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail11.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail12.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail13.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail14.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail15.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail16.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail17.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail18.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail19.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail20.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail21.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail22.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail23.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail24.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail25.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail26.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail27.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail28.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail29.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail30.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail31.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail32.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail33.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail34.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail35.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail36.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail37.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail38.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail39.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail40.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail41.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail42.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail44.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/fail45.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/pass1.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/pass2.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/pass3.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/pass4.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/round1.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/round2.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/round3.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/round4.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/round5.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/round6.json -UNIVALUE_TEST_FILES_INT += %reldir%/test/round7.json diff --git a/src/univalue/test/.gitignore b/src/univalue/test/.gitignore deleted file mode 100644 index 5812c96b14..0000000000 --- a/src/univalue/test/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ - -object -unitester -test_json - -*.trs -*.log 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/CMakeLists.txt b/src/util/CMakeLists.txt new file mode 100644 index 0000000000..4999dbf13f --- /dev/null +++ b/src/util/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_library(bitcoin_util STATIC EXCLUDE_FROM_ALL + asmap.cpp + batchpriority.cpp + bip32.cpp + bytevectorhash.cpp + chaintype.cpp + check.cpp + exception.cpp + feefrac.cpp + fs.cpp + fs_helpers.cpp + hasher.cpp + moneystr.cpp + rbf.cpp + readwritefile.cpp + serfloat.cpp + signalinterrupt.cpp + sock.cpp + strencodings.cpp + string.cpp + syserror.cpp + thread.cpp + threadinterrupt.cpp + threadnames.cpp + time.cpp + tokenpipe.cpp + ../logging.cpp + ../random.cpp + ../randomenv.cpp + ../streams.cpp + ../support/lockedpool.cpp + ../sync.cpp +) + +target_link_libraries(bitcoin_util + PRIVATE + core_interface + bitcoin_clientversion + bitcoin_crypto + $<$<PLATFORM_ID:Windows>:ws2_32> + $<$<PLATFORM_ID:Windows>:iphlpapi> +) diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp index f50cd8a28c..04b0673c49 100644 --- a/src/util/asmap.cpp +++ b/src/util/asmap.cpp @@ -203,10 +203,10 @@ std::vector<bool> DecodeAsmap(fs::path path) LogPrintf("Failed to open asmap file from disk\n"); return bits; } - fseek(filestr, 0, SEEK_END); - int length = ftell(filestr); + file.seek(0, SEEK_END); + int length = file.tell(); LogPrintf("Opened asmap file %s (%d bytes) from disk\n", fs::quoted(fs::PathToString(path)), length); - fseek(filestr, 0, SEEK_SET); + file.seek(0, SEEK_SET); uint8_t cur_byte; for (int i = 0; i < length; ++i) { file >> cur_byte; diff --git a/src/util/bitset.h b/src/util/bitset.h new file mode 100644 index 0000000000..6f9e808c37 --- /dev/null +++ b/src/util/bitset.h @@ -0,0 +1,527 @@ +// 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_UTIL_BITSET_H +#define BITCOIN_UTIL_BITSET_H + +#include <util/check.h> + +#include <array> +#include <bit> +#include <cstdint> +#include <limits> +#include <type_traits> + +/* This file provides data types similar to std::bitset, but adds the following functionality: + * + * - Efficient iteration over all set bits (compatible with range-based for loops). + * - Efficient search for the first and last set bit (First() and Last()). + * - Efficient set subtraction: (a - b) implements "a and not b". + * - Efficient non-strict subset/superset testing: IsSubsetOf() and IsSupersetOf(). + * - Efficient set overlap testing: a.Overlaps(b) + * - Efficient construction of set containing 0..N-1 (S::Fill). + * - Efficient construction of a single set (S::Singleton). + * - Construction from initializer lists. + * + * Other differences: + * - BitSet<N> is a bitset that supports at least N elements, but may support more (Size() reports + * the actual number). Because the actual number is unpredictable, there are no operations that + * affect all positions (like std::bitset's operator~, flip(), or all()). + * - Various other unimplemented features. + */ + +namespace bitset_detail { + +/** Count the number of bits set in an unsigned integer type. */ +template<typename I> +unsigned inline constexpr PopCount(I v) +{ + static_assert(std::is_integral_v<I> && std::is_unsigned_v<I> && std::numeric_limits<I>::radix == 2); + constexpr auto BITS = std::numeric_limits<I>::digits; + // Algorithms from https://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation. + // These seem to be faster than std::popcount when compiling for non-SSE4 on x86_64. + if constexpr (BITS <= 32) { + v -= (v >> 1) & 0x55555555; + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + v = (v + (v >> 4)) & 0x0f0f0f0f; + if constexpr (BITS > 8) v += v >> 8; + if constexpr (BITS > 16) v += v >> 16; + return v & 0x3f; + } else { + static_assert(BITS <= 64); + v -= (v >> 1) & 0x5555555555555555; + v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333); + v = (v + (v >> 4)) & 0x0f0f0f0f0f0f0f0f; + return (v * uint64_t{0x0101010101010101}) >> 56; + } +} + +/** A bitset implementation backed by a single integer of type I. */ +template<typename I> +class IntBitSet +{ + // Only binary, unsigned, integer, types allowed. + static_assert(std::is_integral_v<I> && std::is_unsigned_v<I> && std::numeric_limits<I>::radix == 2); + /** The maximum number of bits this bitset supports. */ + static constexpr unsigned MAX_SIZE = std::numeric_limits<I>::digits; + /** Integer whose bits represent this bitset. */ + I m_val; + /** Internal constructor with a given integer as contents. */ + IntBitSet(I val) noexcept : m_val{val} {} + /** Dummy type to return using end(). Only used for comparing with Iterator. */ + class IteratorEnd + { + friend class IntBitSet; + constexpr IteratorEnd() = default; + public: + constexpr IteratorEnd(const IteratorEnd&) = default; + }; + /** Iterator type returned by begin(), which efficiently iterates all 1 positions. */ + class Iterator + { + friend class IntBitSet; + I m_val; /**< The original integer's remaining bits. */ + unsigned m_pos; /** Last reported 1 position (if m_pos != 0). */ + constexpr Iterator(I val) noexcept : m_val(val), m_pos(0) + { + if (m_val != 0) m_pos = std::countr_zero(m_val); + } + public: + /** Do not allow external code to construct an Iterator. */ + Iterator() = delete; + // Copying is allowed. + constexpr Iterator(const Iterator&) noexcept = default; + constexpr Iterator& operator=(const Iterator&) noexcept = default; + /** Test whether we are done (can only compare with IteratorEnd). */ + constexpr friend bool operator==(const Iterator& a, const IteratorEnd&) noexcept + { + return a.m_val == 0; + } + /** Progress to the next 1 bit (only if != IteratorEnd). */ + constexpr Iterator& operator++() noexcept + { + Assume(m_val != 0); + m_val &= m_val - I{1U}; + if (m_val != 0) m_pos = std::countr_zero(m_val); + return *this; + } + /** Get the current bit position (only if != IteratorEnd). */ + constexpr unsigned operator*() const noexcept + { + Assume(m_val != 0); + return m_pos; + } + }; + +public: + /** Construct an all-zero bitset. */ + constexpr IntBitSet() noexcept : m_val{0} {} + /** Copy construct a bitset. */ + constexpr IntBitSet(const IntBitSet&) noexcept = default; + /** Construct from a list of values. */ + constexpr IntBitSet(std::initializer_list<unsigned> ilist) noexcept : m_val(0) + { + for (auto pos : ilist) Set(pos); + } + /** Copy assign a bitset. */ + constexpr IntBitSet& operator=(const IntBitSet&) noexcept = default; + /** Assign from a list of positions (which will be made true, all others false). */ + constexpr IntBitSet& operator=(std::initializer_list<unsigned> ilist) noexcept + { + m_val = 0; + for (auto pos : ilist) Set(pos); + return *this; + } + /** Construct a bitset with the singleton i. */ + static constexpr IntBitSet Singleton(unsigned i) noexcept + { + Assume(i < MAX_SIZE); + return IntBitSet(I(1U) << i); + } + /** Construct a bitset with bits 0..count-1 (inclusive) set to 1. */ + static constexpr IntBitSet Fill(unsigned count) noexcept + { + IntBitSet ret; + Assume(count <= MAX_SIZE); + if (count) ret.m_val = I(~I{0}) >> (MAX_SIZE - count); + return ret; + } + /** Set a bit to 1. */ + constexpr void Set(unsigned pos) noexcept + { + Assume(pos < MAX_SIZE); + m_val |= I{1U} << pos; + } + /** Set a bit to the specified value. */ + constexpr void Set(unsigned pos, bool val) noexcept + { + Assume(pos < MAX_SIZE); + m_val = (m_val & ~I(I{1U} << pos)) | (I(val) << pos); + } + /** Set a bit to 0. */ + constexpr void Reset(unsigned pos) noexcept + { + Assume(pos < MAX_SIZE); + m_val &= ~I(I{1U} << pos); + } + /** Retrieve a bit at the given position. */ + constexpr bool operator[](unsigned pos) const noexcept + { + Assume(pos < MAX_SIZE); + return (m_val >> pos) & 1U; + } + /** Compute the number of 1 bits in the bitset. */ + constexpr unsigned Count() const noexcept { return PopCount(m_val); } + /** Return the number of bits that this object holds. */ + static constexpr unsigned Size() noexcept { return MAX_SIZE; } + /** Check if all bits are 0. */ + constexpr bool None() const noexcept { return m_val == 0; } + /** Check if any bits are 1. */ + constexpr bool Any() const noexcept { return !None(); } + /** Return an object that iterates over all 1 bits (++ and * only allowed when != end()). */ + constexpr Iterator begin() const noexcept { return Iterator(m_val); } + /** Return a dummy object to compare Iterators with. */ + constexpr IteratorEnd end() const noexcept { return IteratorEnd(); } + /** Find the first element (requires Any()). */ + constexpr unsigned First() const noexcept + { + Assume(m_val != 0); + return std::countr_zero(m_val); + } + /** Find the last element (requires Any()). */ + constexpr unsigned Last() const noexcept + { + Assume(m_val != 0); + return std::bit_width(m_val) - 1; + } + /** Set this object's bits to be the binary AND between respective bits from this and a. */ + constexpr IntBitSet& operator|=(const IntBitSet& a) noexcept { m_val |= a.m_val; return *this; } + /** Set this object's bits to be the binary OR between respective bits from this and a. */ + constexpr IntBitSet& operator&=(const IntBitSet& a) noexcept { m_val &= a.m_val; return *this; } + /** Set this object's bits to be the binary AND NOT between respective bits from this and a. */ + constexpr IntBitSet& operator-=(const IntBitSet& a) noexcept { m_val &= ~a.m_val; return *this; } + /** Set this object's bits to be the binary XOR between respective bits from this as a. */ + constexpr IntBitSet& operator^=(const IntBitSet& a) noexcept { m_val ^= a.m_val; return *this; } + /** Check if the intersection between two sets is non-empty. */ + constexpr bool Overlaps(const IntBitSet& a) const noexcept { return m_val & a.m_val; } + /** Return an object with the binary AND between respective bits from a and b. */ + friend constexpr IntBitSet operator&(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val & b.m_val); } + /** Return an object with the binary OR between respective bits from a and b. */ + friend constexpr IntBitSet operator|(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val | b.m_val); } + /** Return an object with the binary AND NOT between respective bits from a and b. */ + friend constexpr IntBitSet operator-(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val & ~b.m_val); } + /** Return an object with the binary XOR between respective bits from a and b. */ + friend constexpr IntBitSet operator^(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val ^ b.m_val); } + /** Check if bitset a and bitset b are identical. */ + friend constexpr bool operator==(const IntBitSet& a, const IntBitSet& b) noexcept = default; + /** Check if bitset a is a superset of bitset b (= every 1 bit in b is also in a). */ + constexpr bool IsSupersetOf(const IntBitSet& a) const noexcept { return (a.m_val & ~m_val) == 0; } + /** Check if bitset a is a subset of bitset b (= every 1 bit in a is also in b). */ + constexpr bool IsSubsetOf(const IntBitSet& a) const noexcept { return (m_val & ~a.m_val) == 0; } + /** Swap two bitsets. */ + friend constexpr void swap(IntBitSet& a, IntBitSet& b) noexcept { std::swap(a.m_val, b.m_val); } +}; + +/** A bitset implementation backed by N integers of type I. */ +template<typename I, unsigned N> +class MultiIntBitSet +{ + // Only binary, unsigned, integer, types allowed. + static_assert(std::is_integral_v<I> && std::is_unsigned_v<I> && std::numeric_limits<I>::radix == 2); + // Cannot be empty. + static_assert(N > 0); + /** The number of bits per integer. */ + static constexpr unsigned LIMB_BITS = std::numeric_limits<I>::digits; + /** Number of elements this set type supports. */ + static constexpr unsigned MAX_SIZE = LIMB_BITS * N; + // No overflow allowed here. + static_assert(MAX_SIZE / LIMB_BITS == N); + /** Array whose member integers store the bits of the set. */ + std::array<I, N> m_val; + /** Dummy type to return using end(). Only used for comparing with Iterator. */ + class IteratorEnd + { + friend class MultiIntBitSet; + constexpr IteratorEnd() = default; + public: + constexpr IteratorEnd(const IteratorEnd&) = default; + }; + /** Iterator type returned by begin(), which efficiently iterates all 1 positions. */ + class Iterator + { + friend class MultiIntBitSet; + const std::array<I, N>* m_ptr; /**< Pointer to array to fetch bits from. */ + I m_val; /**< The remaining bits of (*m_ptr)[m_idx]. */ + unsigned m_pos; /**< The last reported position. */ + unsigned m_idx; /**< The index in *m_ptr currently being iterated over. */ + constexpr Iterator(const std::array<I, N>& ref) noexcept : m_ptr(&ref), m_idx(0) + { + do { + m_val = (*m_ptr)[m_idx]; + if (m_val) { + m_pos = std::countr_zero(m_val) + m_idx * LIMB_BITS; + break; + } + ++m_idx; + } while(m_idx < N); + } + + public: + /** Do not allow external code to construct an Iterator. */ + Iterator() = delete; + // Copying is allowed. + constexpr Iterator(const Iterator&) noexcept = default; + constexpr Iterator& operator=(const Iterator&) noexcept = default; + /** Test whether we are done (can only compare with IteratorEnd). */ + friend constexpr bool operator==(const Iterator& a, const IteratorEnd&) noexcept + { + return a.m_idx == N; + } + /** Progress to the next 1 bit (only if != IteratorEnd). */ + constexpr Iterator& operator++() noexcept + { + Assume(m_idx < N); + m_val &= m_val - I{1U}; + if (m_val == 0) { + while (true) { + ++m_idx; + if (m_idx == N) break; + m_val = (*m_ptr)[m_idx]; + if (m_val) { + m_pos = std::countr_zero(m_val) + m_idx * LIMB_BITS; + break; + } + } + } else { + m_pos = std::countr_zero(m_val) + m_idx * LIMB_BITS; + } + return *this; + } + /** Get the current bit position (only if != IteratorEnd). */ + constexpr unsigned operator*() const noexcept + { + Assume(m_idx < N); + return m_pos; + } + }; + +public: + /** Construct an all-zero bitset. */ + constexpr MultiIntBitSet() noexcept : m_val{} {} + /** Copy construct a bitset. */ + constexpr MultiIntBitSet(const MultiIntBitSet&) noexcept = default; + /** Copy assign a bitset. */ + constexpr MultiIntBitSet& operator=(const MultiIntBitSet&) noexcept = default; + /** Set a bit to 1. */ + void constexpr Set(unsigned pos) noexcept + { + Assume(pos < MAX_SIZE); + m_val[pos / LIMB_BITS] |= I{1U} << (pos % LIMB_BITS); + } + /** Set a bit to the specified value. */ + void constexpr Set(unsigned pos, bool val) noexcept + { + Assume(pos < MAX_SIZE); + m_val[pos / LIMB_BITS] = (m_val[pos / LIMB_BITS] & ~I(I{1U} << (pos % LIMB_BITS))) | + (I{val} << (pos % LIMB_BITS)); + } + /** Construct a bitset from a list of values. */ + constexpr MultiIntBitSet(std::initializer_list<unsigned> ilist) noexcept : m_val{} + { + for (auto pos : ilist) Set(pos); + } + /** Set a bitset to a list of values. */ + constexpr MultiIntBitSet& operator=(std::initializer_list<unsigned> ilist) noexcept + { + m_val.fill(0); + for (auto pos : ilist) Set(pos); + return *this; + } + /** Set a bit to 0. */ + void constexpr Reset(unsigned pos) noexcept + { + Assume(pos < MAX_SIZE); + m_val[pos / LIMB_BITS] &= ~I(I{1U} << (pos % LIMB_BITS)); + } + /** Retrieve a bit at the given position. */ + bool constexpr operator[](unsigned pos) const noexcept + { + Assume(pos < MAX_SIZE); + return (m_val[pos / LIMB_BITS] >> (pos % LIMB_BITS)) & 1U; + } + /** Construct a bitset with the singleton pos. */ + static constexpr MultiIntBitSet Singleton(unsigned pos) noexcept + { + Assume(pos < MAX_SIZE); + MultiIntBitSet ret; + ret.m_val[pos / LIMB_BITS] = I{1U} << (pos % LIMB_BITS); + return ret; + } + /** Construct a bitset with bits 0..count-1 (inclusive) set to 1. */ + static constexpr MultiIntBitSet Fill(unsigned count) noexcept + { + Assume(count <= MAX_SIZE); + MultiIntBitSet ret; + if (count) { + unsigned i = 0; + while (count > LIMB_BITS) { + ret.m_val[i++] = ~I{0}; + count -= LIMB_BITS; + } + ret.m_val[i] = I(~I{0}) >> (LIMB_BITS - count); + } + return ret; + } + /** Return the number of bits that this object holds. */ + static constexpr unsigned Size() noexcept { return MAX_SIZE; } + /** Compute the number of 1 bits in the bitset. */ + unsigned constexpr Count() const noexcept + { + unsigned ret{0}; + for (I v : m_val) ret += PopCount(v); + return ret; + } + /** Check if all bits are 0. */ + bool constexpr None() const noexcept + { + for (auto v : m_val) { + if (v != 0) return false; + } + return true; + } + /** Check if any bits are 1. */ + bool constexpr Any() const noexcept { return !None(); } + /** Return an object that iterates over all 1 bits (++ and * only allowed when != end()). */ + Iterator constexpr begin() const noexcept { return Iterator(m_val); } + /** Return a dummy object to compare Iterators with. */ + IteratorEnd constexpr end() const noexcept { return IteratorEnd(); } + /** Find the first element (requires Any()). */ + unsigned constexpr First() const noexcept + { + unsigned p = 0; + while (m_val[p] == 0) { + ++p; + Assume(p < N); + } + return std::countr_zero(m_val[p]) + p * LIMB_BITS; + } + /** Find the last element (requires Any()). */ + unsigned constexpr Last() const noexcept + { + unsigned p = N - 1; + while (m_val[p] == 0) { + Assume(p > 0); + --p; + } + return std::bit_width(m_val[p]) - 1 + p * LIMB_BITS; + } + /** Set this object's bits to be the binary OR between respective bits from this and a. */ + constexpr MultiIntBitSet& operator|=(const MultiIntBitSet& a) noexcept + { + for (unsigned i = 0; i < N; ++i) { + m_val[i] |= a.m_val[i]; + } + return *this; + } + /** Set this object's bits to be the binary AND between respective bits from this and a. */ + constexpr MultiIntBitSet& operator&=(const MultiIntBitSet& a) noexcept + { + for (unsigned i = 0; i < N; ++i) { + m_val[i] &= a.m_val[i]; + } + return *this; + } + /** Set this object's bits to be the binary AND NOT between respective bits from this and a. */ + constexpr MultiIntBitSet& operator-=(const MultiIntBitSet& a) noexcept + { + for (unsigned i = 0; i < N; ++i) { + m_val[i] &= ~a.m_val[i]; + } + return *this; + } + /** Set this object's bits to be the binary XOR between respective bits from this and a. */ + constexpr MultiIntBitSet& operator^=(const MultiIntBitSet& a) noexcept + { + for (unsigned i = 0; i < N; ++i) { + m_val[i] ^= a.m_val[i]; + } + return *this; + } + /** Check whether the intersection between two sets is non-empty. */ + constexpr bool Overlaps(const MultiIntBitSet& a) const noexcept + { + for (unsigned i = 0; i < N; ++i) { + if (m_val[i] & a.m_val[i]) return true; + } + return false; + } + /** Return an object with the binary AND between respective bits from a and b. */ + friend constexpr MultiIntBitSet operator&(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept + { + MultiIntBitSet r; + for (unsigned i = 0; i < N; ++i) { + r.m_val[i] = a.m_val[i] & b.m_val[i]; + } + return r; + } + /** Return an object with the binary OR between respective bits from a and b. */ + friend constexpr MultiIntBitSet operator|(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept + { + MultiIntBitSet r; + for (unsigned i = 0; i < N; ++i) { + r.m_val[i] = a.m_val[i] | b.m_val[i]; + } + return r; + } + /** Return an object with the binary AND NOT between respective bits from a and b. */ + friend constexpr MultiIntBitSet operator-(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept + { + MultiIntBitSet r; + for (unsigned i = 0; i < N; ++i) { + r.m_val[i] = a.m_val[i] & ~b.m_val[i]; + } + return r; + } + /** Return an object with the binary XOR between respective bits from a and b. */ + friend constexpr MultiIntBitSet operator^(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept + { + MultiIntBitSet r; + for (unsigned i = 0; i < N; ++i) { + r.m_val[i] = a.m_val[i] ^ b.m_val[i]; + } + return r; + } + /** Check if bitset a is a superset of bitset b (= every 1 bit in b is also in a). */ + constexpr bool IsSupersetOf(const MultiIntBitSet& a) const noexcept + { + for (unsigned i = 0; i < N; ++i) { + if (a.m_val[i] & ~m_val[i]) return false; + } + return true; + } + /** Check if bitset a is a subset of bitset b (= every 1 bit in a is also in b). */ + constexpr bool IsSubsetOf(const MultiIntBitSet& a) const noexcept + { + for (unsigned i = 0; i < N; ++i) { + if (m_val[i] & ~a.m_val[i]) return false; + } + return true; + } + /** Check if bitset a and bitset b are identical. */ + friend constexpr bool operator==(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept = default; + /** Swap two bitsets. */ + friend constexpr void swap(MultiIntBitSet& a, MultiIntBitSet& b) noexcept { std::swap(a.m_val, b.m_val); } +}; + +} // namespace bitset_detail + +// BitSet dispatches to IntBitSet or MultiIntBitSet as appropriate for the requested minimum number +// of bits. Use IntBitSet up to 32-bit, or up to 64-bit on 64-bit platforms; above that, use a +// MultiIntBitSet of size_t. +template<unsigned BITS> +using BitSet = std::conditional_t<(BITS <= 32), bitset_detail::IntBitSet<uint32_t>, + std::conditional_t<(BITS <= std::numeric_limits<size_t>::digits), bitset_detail::IntBitSet<size_t>, + bitset_detail::MultiIntBitSet<size_t, (BITS + std::numeric_limits<size_t>::digits - 1) / std::numeric_limits<size_t>::digits>>>; + +#endif // BITCOIN_UTIL_BITSET_H 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/check.cpp b/src/util/check.cpp index eb3885832b..e1956042c3 100644 --- a/src/util/check.cpp +++ b/src/util/check.cpp @@ -4,7 +4,7 @@ #include <util/check.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <clientversion.h> #include <tinyformat.h> diff --git a/src/util/check.h b/src/util/check.h index a02a1de8dc..8f28f5dc94 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -40,7 +40,7 @@ void assertion_fail(std::string_view file, int line, std::string_view func, std: /** Helper for Assert()/Assume() */ template <bool IS_ASSERT, typename T> -T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion) +constexpr T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion) { if constexpr (IS_ASSERT #ifdef ABORT_ON_FAILED_ASSUME diff --git a/src/util/error.cpp b/src/util/error.cpp deleted file mode 100644 index 309877d067..0000000000 --- a/src/util/error.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2010-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <util/error.h> - -#include <tinyformat.h> -#include <util/translation.h> - -#include <cassert> -#include <string> - -bilingual_str TransactionErrorString(const TransactionError err) -{ - switch (err) { - case TransactionError::OK: - 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::P2P_DISABLED: - return Untranslated("Peer-to-peer functionality missing or disabled"); - case TransactionError::MEMPOOL_REJECTED: - return Untranslated("Transaction rejected by mempool"); - case TransactionError::MEMPOOL_ERROR: - return Untranslated("Mempool internal error"); - case TransactionError::INVALID_PSBT: - return Untranslated("PSBT is not well-formed"); - case TransactionError::PSBT_MISMATCH: - return Untranslated("PSBTs not compatible (different transactions)"); - case TransactionError::SIGHASH_MISMATCH: - return Untranslated("Specified sighash value does not match value stored in PSBT"); - case TransactionError::MAX_FEE_EXCEEDED: - return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"); - case TransactionError::MAX_BURN_EXCEEDED: - return Untranslated("Unspendable output exceeds maximum configured by user (maxburnamount)"); - case TransactionError::EXTERNAL_SIGNER_NOT_FOUND: - return Untranslated("External signer not found"); - case TransactionError::EXTERNAL_SIGNER_FAILED: - return Untranslated("External signer failed to sign"); - case TransactionError::INVALID_PACKAGE: - return Untranslated("Transaction rejected due to invalid package"); - // no default case, so the compiler can warn about missing cases - } - assert(false); -} - -bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind) -{ - return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); -} - -bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& invalid_value) -{ - return strprintf(_("Invalid port specified in %s: '%s'"), optname, invalid_value); -} - -bilingual_str AmountHighWarn(const std::string& optname) -{ - return strprintf(_("%s is set very high!"), optname); -} - -bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue) -{ - return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue); -} diff --git a/src/util/error.h b/src/util/error.h deleted file mode 100644 index a52a8f47de..0000000000 --- a/src/util/error.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2010-2021 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UTIL_ERROR_H -#define BITCOIN_UTIL_ERROR_H - -/** - * util/error.h is a common place for definitions of simple error types and - * string functions. Types and functions defined here should not require any - * outside dependencies. - * - * Error types defined here can be used in different parts of the - * codebase, to avoid the need to write boilerplate code catching and - * translating errors passed across wallet/node/rpc/gui code boundaries. - */ - -#include <string> - -struct bilingual_str; - -enum class TransactionError { - OK, //!< No error - MISSING_INPUTS, - ALREADY_IN_CHAIN, - P2P_DISABLED, - MEMPOOL_REJECTED, - MEMPOOL_ERROR, - INVALID_PSBT, - PSBT_MISMATCH, - SIGHASH_MISMATCH, - MAX_FEE_EXCEEDED, - MAX_BURN_EXCEEDED, - EXTERNAL_SIGNER_NOT_FOUND, - EXTERNAL_SIGNER_FAILED, - INVALID_PACKAGE, -}; - -bilingual_str TransactionErrorString(const TransactionError error); - -bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind); - -bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& strPort); - -bilingual_str AmountHighWarn(const std::string& optname); - -bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue); - -#endif // BITCOIN_UTIL_ERROR_H diff --git a/src/util/feefrac.h b/src/util/feefrac.h index 9772162010..161322b50a 100644 --- a/src/util/feefrac.h +++ b/src/util/feefrac.h @@ -64,13 +64,13 @@ struct FeeFrac int32_t size; /** Construct an IsEmpty() FeeFrac. */ - inline FeeFrac() noexcept : fee{0}, size{0} {} + constexpr inline FeeFrac() noexcept : fee{0}, size{0} {} /** Construct a FeeFrac with specified fee and size. */ - inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {} + constexpr inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {} - inline FeeFrac(const FeeFrac&) noexcept = default; - inline FeeFrac& operator=(const FeeFrac&) noexcept = default; + constexpr inline FeeFrac(const FeeFrac&) noexcept = default; + constexpr inline FeeFrac& operator=(const FeeFrac&) noexcept = default; /** Check if this is empty (size and fee are 0). */ bool inline IsEmpty() const noexcept { diff --git a/src/util/fees.cpp b/src/util/fees.cpp deleted file mode 100644 index 8ada02ce54..0000000000 --- a/src/util/fees.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <util/fees.h> - -#include <policy/fees.h> -#include <util/strencodings.h> -#include <util/string.h> - -#include <map> -#include <string> -#include <vector> -#include <utility> - -std::string StringForFeeReason(FeeReason reason) -{ - static const std::map<FeeReason, std::string> fee_reason_strings = { - {FeeReason::NONE, "None"}, - {FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"}, - {FeeReason::FULL_ESTIMATE, "Target 85% Threshold"}, - {FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"}, - {FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"}, - {FeeReason::MEMPOOL_MIN, "Mempool Min Fee"}, - {FeeReason::PAYTXFEE, "PayTxFee set"}, - {FeeReason::FALLBACK, "Fallback fee"}, - {FeeReason::REQUIRED, "Minimum Required Fee"}, - }; - auto reason_string = fee_reason_strings.find(reason); - - if (reason_string == fee_reason_strings.end()) return "Unknown"; - - return reason_string->second; -} - -const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap() -{ - static const std::vector<std::pair<std::string, FeeEstimateMode>> FEE_MODES = { - {"unset", FeeEstimateMode::UNSET}, - {"economical", FeeEstimateMode::ECONOMICAL}, - {"conservative", FeeEstimateMode::CONSERVATIVE}, - }; - return FEE_MODES; -} - -std::string FeeModes(const std::string& delimiter) -{ - return Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; }); -} - -std::string InvalidEstimateModeErrorMessage() -{ - return "Invalid estimate_mode parameter, must be one of: \"" + FeeModes("\", \"") + "\""; -} - -bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) -{ - auto searchkey = ToUpper(mode_string); - for (const auto& pair : FeeModeMap()) { - if (ToUpper(pair.first) == searchkey) { - fee_estimate_mode = pair.second; - return true; - } - } - return false; -} diff --git a/src/util/fees.h b/src/util/fees.h deleted file mode 100644 index 10ba1e4f85..0000000000 --- a/src/util/fees.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_UTIL_FEES_H -#define BITCOIN_UTIL_FEES_H - -#include <string> - -enum class FeeEstimateMode; -enum class FeeReason; - -bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode); -std::string StringForFeeReason(FeeReason reason); -std::string FeeModes(const std::string& delimiter); -std::string InvalidEstimateModeErrorMessage(); - -#endif // BITCOIN_UTIL_FEES_H diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp index 8952f20f79..7ac7b829d8 100644 --- a/src/util/fs_helpers.cpp +++ b/src/util/fs_helpers.cpp @@ -5,7 +5,7 @@ #include <util/fs_helpers.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <logging.h> #include <sync.h> @@ -16,12 +16,13 @@ #include <fstream> #include <map> #include <memory> +#include <optional> #include <string> #include <system_error> #include <utility> #ifndef WIN32 -// for posix_fallocate, in configure.ac we check if it is present after this +// for posix_fallocate, in cmake/introspection.cmake we check if it is present after this #ifdef __linux__ #ifdef _POSIX_C_SOURCE @@ -269,3 +270,42 @@ bool TryCreateDirectories(const fs::path& p) // create_directories didn't create the directory, it had to have existed already return false; } + +std::string PermsToSymbolicString(fs::perms p) +{ + std::string perm_str(9, '-'); + + auto set_perm = [&](size_t pos, fs::perms required_perm, char letter) { + if ((p & required_perm) != fs::perms::none) { + perm_str[pos] = letter; + } + }; + + set_perm(0, fs::perms::owner_read, 'r'); + set_perm(1, fs::perms::owner_write, 'w'); + set_perm(2, fs::perms::owner_exec, 'x'); + set_perm(3, fs::perms::group_read, 'r'); + set_perm(4, fs::perms::group_write, 'w'); + set_perm(5, fs::perms::group_exec, 'x'); + set_perm(6, fs::perms::others_read, 'r'); + set_perm(7, fs::perms::others_write, 'w'); + set_perm(8, fs::perms::others_exec, 'x'); + + return perm_str; +} + +std::optional<fs::perms> InterpretPermString(const std::string& s) +{ + if (s == "owner") { + return fs::perms::owner_read | fs::perms::owner_write; + } else if (s == "group") { + return fs::perms::owner_read | fs::perms::owner_write | + fs::perms::group_read; + } else if (s == "all") { + return fs::perms::owner_read | fs::perms::owner_write | + fs::perms::group_read | + fs::perms::others_read; + } else { + return std::nullopt; + } +} diff --git a/src/util/fs_helpers.h b/src/util/fs_helpers.h index ea3778eac3..28dd6d979d 100644 --- a/src/util/fs_helpers.h +++ b/src/util/fs_helpers.h @@ -12,6 +12,7 @@ #include <cstdio> #include <iosfwd> #include <limits> +#include <optional> /** * Ensure file contents are fully committed to disk, using a platform-specific @@ -62,6 +63,19 @@ void ReleaseDirectoryLocks(); bool TryCreateDirectories(const fs::path& p); fs::path GetDefaultDataDir(); +/** Convert fs::perms to symbolic string of the form 'rwxrwxrwx' + * + * @param[in] p the perms to be converted + * @return Symbolic permissions string + */ +std::string PermsToSymbolicString(fs::perms p); +/** Interpret a custom permissions level string as fs::perms + * + * @param[in] s Permission level string + * @return Permissions as fs::perms + */ +std::optional<fs::perms> InterpretPermString(const std::string& s); + #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif 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/moneystr.cpp b/src/util/moneystr.cpp index 9181329afc..1ed3b2ac96 100644 --- a/src/util/moneystr.cpp +++ b/src/util/moneystr.cpp @@ -13,6 +13,9 @@ #include <cstdint> #include <optional> +using util::ContainsNoNUL; +using util::TrimString; + std::string FormatMoney(const CAmount n) { // Note: not using straight sprintf here because we do NOT want diff --git a/src/util/spanparsing.h b/src/util/spanparsing.h deleted file mode 100644 index 765fe13aca..0000000000 --- a/src/util/spanparsing.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2018-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UTIL_SPANPARSING_H -#define BITCOIN_UTIL_SPANPARSING_H - -#include <span.h> - -#include <string> -#include <string_view> -#include <vector> - -namespace spanparsing { - -/** Parse a constant. - * - * If sp's initial part matches str, sp is updated to skip that part, and true is returned. - * Otherwise sp is unmodified and false is returned. - */ -bool Const(const std::string& str, Span<const char>& sp); - -/** Parse a function call. - * - * If sp's initial part matches str + "(", and sp ends with ")", sp is updated to be the - * section between the braces, and true is returned. Otherwise sp is unmodified and false - * is returned. - */ -bool Func(const std::string& str, Span<const char>& sp); - -/** Extract the expression that sp begins with. - * - * This function will return the initial part of sp, up to (but not including) the first - * comma or closing brace, skipping ones that are surrounded by braces. So for example, - * for "foo(bar(1),2),3" the initial part "foo(bar(1),2)" will be returned. sp will be - * updated to skip the initial part that is returned. - */ -Span<const char> Expr(Span<const char>& sp); - -/** Split a string on any char found in separators, returning a vector. - * - * If sep does not occur in sp, a singleton with the entirety of sp is returned. - * - * Note that this function does not care about braces, so splitting - * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. - */ -template <typename T = Span<const char>> -std::vector<T> Split(const Span<const char>& sp, std::string_view separators) -{ - std::vector<T> ret; - auto it = sp.begin(); - auto start = it; - while (it != sp.end()) { - if (separators.find(*it) != std::string::npos) { - ret.emplace_back(start, it); - start = it + 1; - } - ++it; - } - ret.emplace_back(start, it); - return ret; -} - -/** Split a string on every instance of sep, returning a vector. - * - * If sep does not occur in sp, a singleton with the entirety of sp is returned. - * - * Note that this function does not care about braces, so splitting - * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. - */ -template <typename T = Span<const char>> -std::vector<T> Split(const Span<const char>& sp, char sep) -{ - return Split<T>(sp, std::string_view{&sep, 1}); -} - -} // namespace spanparsing - -#endif // BITCOIN_UTIL_SPANPARSING_H diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 7b5ded2975..15cb40aba1 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -3,9 +3,11 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <span.h> #include <util/strencodings.h> +#include <crypto/hex_base.h> +#include <span.h> + #include <array> #include <cassert> #include <cstring> @@ -36,29 +38,6 @@ std::string SanitizeString(std::string_view str, int rule) return result; } -const signed char p_util_hexdigit[256] = -{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; - -signed char HexDigit(char c) -{ - return p_util_hexdigit[(unsigned char)c]; -} - bool IsHex(std::string_view str) { for (char c : str) { @@ -67,16 +46,6 @@ bool IsHex(std::string_view str) return (str.size() > 0) && (str.size()%2 == 0); } -bool IsHexNumber(std::string_view str) -{ - if (str.substr(0, 2) == "0x") str.remove_prefix(2); - for (char c : str) { - if (HexDigit(c) < 0) return false; - } - // Return false for empty string or "0x". - return str.size() > 0; -} - template <typename Byte> std::optional<std::vector<Byte>> TryParseHex(std::string_view str) { @@ -466,40 +435,6 @@ std::string Capitalize(std::string str) return str; } -namespace { - -using ByteAsHex = std::array<char, 2>; - -constexpr std::array<ByteAsHex, 256> CreateByteToHexMap() -{ - constexpr char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - std::array<ByteAsHex, 256> byte_to_hex{}; - for (size_t i = 0; i < byte_to_hex.size(); ++i) { - byte_to_hex[i][0] = hexmap[i >> 4]; - byte_to_hex[i][1] = hexmap[i & 15]; - } - return byte_to_hex; -} - -} // namespace - -std::string HexStr(const Span<const uint8_t> s) -{ - std::string rv(s.size() * 2, '\0'); - static constexpr auto byte_to_hex = CreateByteToHexMap(); - static_assert(sizeof(byte_to_hex) == 512); - - char* it = rv.data(); - for (uint8_t v : s) { - std::memcpy(it, byte_to_hex[v].data(), 2); - it += 2; - } - - assert(it == rv.data() + rv.size()); - return rv; -} - std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier) { if (str.empty()) { diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 439678c24a..1543de03ab 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -9,9 +9,12 @@ #ifndef BITCOIN_UTIL_STRENCODINGS_H #define BITCOIN_UTIL_STRENCODINGS_H +#include <crypto/hex_base.h> // IWYU pragma: export #include <span.h> #include <util/string.h> +#include <array> +#include <bit> #include <charconv> #include <cstddef> #include <cstdint> @@ -66,14 +69,9 @@ std::vector<Byte> ParseHex(std::string_view hex_str) { return TryParseHex<Byte>(hex_str).value_or(std::vector<Byte>{}); } -signed char HexDigit(char c); /* Returns true if each character in str is a hex character, and has an even * number of hex digits.*/ bool IsHex(std::string_view str); -/** -* Return true if the string is a hex number, optionally prefixed with "0x" -*/ -bool IsHexNumber(std::string_view str); std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str); std::string EncodeBase64(Span<const unsigned char> input); inline std::string EncodeBase64(Span<const std::byte> input) { return EncodeBase64(MakeUCharSpan(input)); } @@ -122,7 +120,7 @@ T LocaleIndependentAtoi(std::string_view str) static_assert(std::is_integral<T>::value); T result; // Emulate atoi(...) handling of white space and leading +/-. - std::string_view s = TrimStringView(str); + std::string_view s = util::TrimStringView(str); if (!s.empty() && s[0] == '+') { if (s.length() >= 2 && s[1] == '-') { return 0; @@ -232,13 +230,6 @@ std::optional<T> ToIntegral(std::string_view str) [[nodiscard]] bool ParseUInt64(std::string_view str, uint64_t *out); /** - * Convert a span of bytes to a lower-case hexadecimal string. - */ -std::string HexStr(const Span<const uint8_t> s); -inline std::string HexStr(const Span<const char> s) { return HexStr(MakeUCharSpan(s)); } -inline std::string HexStr(const Span<const std::byte> s) { return HexStr(MakeUCharSpan(s)); } - -/** * Format a paragraph of text to a fixed width, adding spaces for * indentation to any added line. */ @@ -376,4 +367,79 @@ std::string Capitalize(std::string str); */ std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier); +namespace util { +/** consteval version of HexDigit() without the lookup table. */ +consteval uint8_t ConstevalHexDigit(const char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 0xa; + + throw "Only lowercase hex digits are allowed, for consistency"; +} + +/** + * ""_hex is a compile-time user-defined literal returning a + * `std::array<std::byte>`, equivalent to ParseHex(). Variants provided: + * + * - ""_hex_v: Returns `std::vector<std::byte>`, useful for heap allocation or + * variable-length serialization. + * + * - ""_hex_u8: Returns `std::array<uint8_t>`, for cases where `std::byte` is + * incompatible. + * + * - ""_hex_v_u8: Returns `std::vector<uint8_t>`, combining heap allocation with + * `uint8_t`. + * + * @warning It could be necessary to use vector instead of array variants when + * serializing, or vice versa, because vectors are assumed to be variable- + * length and serialized with a size prefix, while arrays are considered fixed + * length and serialized with no prefix. + * + * @warning It may be preferable to use vector variants to save stack space when + * declaring local variables if hex strings are large. Alternatively variables + * could be declared constexpr to avoid using stack space. + * + * @warning Avoid `uint8_t` variants when not necessary, as the codebase + * migrates to use `std::byte` instead of `unsigned char` and `uint8_t`. + * + * @note One reason ""_hex uses `std::array` instead of `std::vector` like + * ParseHex() does is because heap-based containers cannot cross the compile- + * time/runtime barrier. + */ +inline namespace hex_literals { +namespace detail { + +template <size_t N> +struct Hex { + std::array<std::byte, N / 2> bytes{}; + consteval Hex(const char (&hex_str)[N]) + // 2 hex digits required per byte + implicit null terminator + requires(N % 2 == 1) + { + if (hex_str[N - 1]) throw "null terminator required"; + for (std::size_t i = 0; i < bytes.size(); ++i) { + bytes[i] = static_cast<std::byte>( + (ConstevalHexDigit(hex_str[2 * i]) << 4) | + ConstevalHexDigit(hex_str[2 * i + 1])); + } + } +}; + +} // namespace detail + +template <util::detail::Hex str> +constexpr auto operator""_hex() { return str.bytes; } + +template <util::detail::Hex str> +constexpr auto operator""_hex_u8() { return std::bit_cast<std::array<uint8_t, str.bytes.size()>>(str.bytes); } + +template <util::detail::Hex str> +constexpr auto operator""_hex_v() { return std::vector<std::byte>{str.bytes.begin(), str.bytes.end()}; } + +template <util::detail::Hex str> +inline auto operator""_hex_v_u8() { return std::vector<uint8_t>{UCharCast(str.bytes.data()), UCharCast(str.bytes.data() + str.bytes.size())}; } + +} // inline namespace hex_literals +} // namespace util + #endif // BITCOIN_UTIL_STRENCODINGS_H diff --git a/src/util/string.cpp b/src/util/string.cpp index 3d31849745..47c6b74d4f 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -7,8 +7,10 @@ #include <regex> #include <string> +namespace util { void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute) { if (search.empty()) return; in_out = std::regex_replace(in_out, std::regex(search), substitute); } +} // namespace util diff --git a/src/util/string.h b/src/util/string.h index dab92942fb..c5183d6c80 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,11 +1,12 @@ -// 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. #ifndef BITCOIN_UTIL_STRING_H #define BITCOIN_UTIL_STRING_H -#include <util/spanparsing.h> +#include <span.h> +#include <tinyformat.h> #include <array> #include <cstdint> @@ -16,16 +17,115 @@ #include <string_view> // IWYU pragma: export #include <vector> +namespace util { +/** + * @brief A wrapper for a compile-time partially validated format string + * + * This struct can be used to enforce partial compile-time validation of format + * strings, to reduce the likelihood of tinyformat throwing exceptions at + * run-time. Validation is partial to try and prevent the most common errors + * while avoiding re-implementing the entire parsing logic. + * + * @note Counting of `*` dynamic width and precision fields (such as `%*c`, + * `%2$*3$d`, `%.*f`) is not implemented to minimize code complexity as long as + * they are not used in the codebase. Usage of these fields is not counted and + * can lead to run-time exceptions. Code wanting to use the `*` specifier can + * side-step this struct and call tinyformat directly. + */ +template <unsigned num_params> +struct ConstevalFormatString { + const char* const fmt; + consteval ConstevalFormatString(const char* str) : fmt{str} { Detail_CheckNumFormatSpecifiers(fmt); } + constexpr static void Detail_CheckNumFormatSpecifiers(std::string_view str) + { + unsigned count_normal{0}; // Number of "normal" specifiers, like %s + unsigned count_pos{0}; // Max number in positional specifier, like %8$s + for (auto it{str.begin()}; it < str.end();) { + if (*it != '%') { + ++it; + continue; + } + + if (++it >= str.end()) throw "Format specifier incorrectly terminated by end of string"; + if (*it == '%') { + // Percent escape: %% + ++it; + continue; + } + + unsigned maybe_num{0}; + while ('0' <= *it && *it <= '9') { + maybe_num *= 10; + maybe_num += *it - '0'; + ++it; + }; + + if (*it == '$') { + // Positional specifier, like %8$s + if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; + count_pos = std::max(count_pos, maybe_num); + if (++it >= str.end()) throw "Format specifier incorrectly terminated by end of string"; + } else { + // Non-positional specifier, like %s + ++count_normal; + ++it; + } + // The remainder "[flags][width][.precision][length]type" of the + // specifier is not checked. Parsing continues with the next '%'. + } + if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; + unsigned count{count_normal | count_pos}; + if (num_params != count) throw "Format specifier count must match the argument count!"; + } +}; + void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute); +/** Split a string on any char found in separators, returning a vector. + * + * If sep does not occur in sp, a singleton with the entirety of sp is returned. + * + * Note that this function does not care about braces, so splitting + * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. + */ +template <typename T = Span<const char>> +std::vector<T> Split(const Span<const char>& sp, std::string_view separators) +{ + std::vector<T> ret; + auto it = sp.begin(); + auto start = it; + while (it != sp.end()) { + if (separators.find(*it) != std::string::npos) { + ret.emplace_back(start, it); + start = it + 1; + } + ++it; + } + ret.emplace_back(start, it); + return ret; +} + +/** Split a string on every instance of sep, returning a vector. + * + * If sep does not occur in sp, a singleton with the entirety of sp is returned. + * + * Note that this function does not care about braces, so splitting + * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. + */ +template <typename T = Span<const char>> +std::vector<T> Split(const Span<const char>& sp, char sep) +{ + return Split<T>(sp, std::string_view{&sep, 1}); +} + [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep) { - return spanparsing::Split<std::string>(str, sep); + return Split<std::string>(str, sep); } [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators) { - return spanparsing::Split<std::string>(str, separators); + return Split<std::string>(str, separators); } [[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v") @@ -43,6 +143,14 @@ void ReplaceAll(std::string& in_out, const std::string& search, const std::strin 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) { @@ -125,5 +233,14 @@ template <typename T1, size_t PREFIX_LEN> return obj.size() >= PREFIX_LEN && std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); } +} // namespace util + +namespace tinyformat { +template <typename... Args> +std::string format(util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) +{ + return format(fmt.fmt, args...); +} +} // namespace tinyformat #endif // BITCOIN_UTIL_STRING_H 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/syserror.cpp b/src/util/syserror.cpp index 6f3a724483..a902826f8e 100644 --- a/src/util/syserror.cpp +++ b/src/util/syserror.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <tinyformat.h> #include <util/syserror.h> 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/threadnames.cpp b/src/util/threadnames.cpp index 0249de37e3..37c5b8f617 100644 --- a/src/util/threadnames.cpp +++ b/src/util/threadnames.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <cstring> #include <string> diff --git a/src/util/tokenpipe.cpp b/src/util/tokenpipe.cpp index 16fbb664ea..9425c62ebf 100644 --- a/src/util/tokenpipe.cpp +++ b/src/util/tokenpipe.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <util/tokenpipe.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #ifndef WIN32 diff --git a/src/util/trace.h b/src/util/trace.h index d9ed65e3aa..72a486d562 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_UTIL_TRACE_H #define BITCOIN_UTIL_TRACE_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #ifdef ENABLE_TRACING 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/util/vecdeque.h b/src/util/vecdeque.h new file mode 100644 index 0000000000..a9264a5ad6 --- /dev/null +++ b/src/util/vecdeque.h @@ -0,0 +1,317 @@ +// 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_UTIL_VECDEQUE_H +#define BITCOIN_UTIL_VECDEQUE_H + +#include <util/check.h> + +#include <cstring> +#include <memory> +#include <type_traits> + +/** Data structure largely mimicking std::deque, but using single preallocated ring buffer. + * + * - More efficient and better memory locality than std::deque. + * - Most operations ({push_,pop_,emplace_,}{front,back}(), operator[], ...) are O(1), + * unless reallocation is needed (in which case they are O(n)). + * - Supports reserve(), capacity(), shrink_to_fit() like vectors. + * - No iterator support. + * - Data is not stored in a single contiguous block, so no data(). + */ +template<typename T> +class VecDeque +{ + /** Pointer to allocated memory. Can contain constructed and uninitialized T objects. */ + T* m_buffer{nullptr}; + /** m_buffer + m_offset points to first object in queue. m_offset = 0 if m_capacity is 0; + * otherwise 0 <= m_offset < m_capacity. */ + size_t m_offset{0}; + /** Number of objects in the container. 0 <= m_size <= m_capacity. */ + size_t m_size{0}; + /** The size of m_buffer, expressed as a multiple of the size of T. */ + size_t m_capacity{0}; + + /** Returns the number of populated objects between m_offset and the end of the buffer. */ + size_t FirstPart() const noexcept { return std::min(m_capacity - m_offset, m_size); } + + void Reallocate(size_t capacity) + { + Assume(capacity >= m_size); + Assume((m_offset == 0 && m_capacity == 0) || m_offset < m_capacity); + // Allocate new buffer. + T* new_buffer = capacity ? std::allocator<T>().allocate(capacity) : nullptr; + if (capacity) { + if constexpr (std::is_trivially_copyable_v<T>) { + // When T is trivially copyable, just copy the data over from old to new buffer. + size_t first_part = FirstPart(); + if (first_part != 0) { + std::memcpy(new_buffer, m_buffer + m_offset, first_part * sizeof(T)); + } + if (first_part != m_size) { + std::memcpy(new_buffer + first_part, m_buffer, (m_size - first_part) * sizeof(T)); + } + } else { + // Otherwise move-construct in place in the new buffer, and destroy old buffer objects. + size_t old_pos = m_offset; + for (size_t new_pos = 0; new_pos < m_size; ++new_pos) { + std::construct_at(new_buffer + new_pos, std::move(*(m_buffer + old_pos))); + std::destroy_at(m_buffer + old_pos); + ++old_pos; + if (old_pos == m_capacity) old_pos = 0; + } + } + } + // Deallocate old buffer and update housekeeping. + std::allocator<T>().deallocate(m_buffer, m_capacity); + m_buffer = new_buffer; + m_offset = 0; + m_capacity = capacity; + Assume((m_offset == 0 && m_capacity == 0) || m_offset < m_capacity); + } + + /** What index in the buffer does logical entry number pos have? */ + size_t BufferIndex(size_t pos) const noexcept + { + Assume(pos < m_capacity); + // The expression below is used instead of the more obvious (pos + m_offset >= m_capacity), + // because the addition there could in theory overflow with very large deques. + if (pos >= m_capacity - m_offset) { + return (m_offset + pos) - m_capacity; + } else { + return m_offset + pos; + } + } + + /** Specialization of resize() that can only shrink. Separate so that clear() can call it + * without requiring a default T constructor. */ + void ResizeDown(size_t size) noexcept + { + Assume(size <= m_size); + if constexpr (std::is_trivially_destructible_v<T>) { + // If T is trivially destructible, we do not need to do anything but update the + // housekeeping record. Default constructor or zero-filling will be used when + // the space is reused. + m_size = size; + } else { + // If not, we need to invoke the destructor for every element separately. + while (m_size > size) { + std::destroy_at(m_buffer + BufferIndex(m_size - 1)); + --m_size; + } + } + } + +public: + VecDeque() noexcept = default; + + /** Resize the deque to be exactly size size (adding default-constructed elements if needed). */ + void resize(size_t size) + { + if (size < m_size) { + // Delegate to ResizeDown when shrinking. + ResizeDown(size); + } else if (size > m_size) { + // When growing, first see if we need to allocate more space. + if (size > m_capacity) Reallocate(size); + while (m_size < size) { + std::construct_at(m_buffer + BufferIndex(m_size)); + ++m_size; + } + } + } + + /** Resize the deque to be size 0. The capacity will remain unchanged. */ + void clear() noexcept { ResizeDown(0); } + + /** Destroy a deque. */ + ~VecDeque() + { + clear(); + Reallocate(0); + } + + /** Copy-assign a deque. */ + VecDeque& operator=(const VecDeque& other) + { + if (&other == this) [[unlikely]] return *this; + clear(); + Reallocate(other.m_size); + if constexpr (std::is_trivially_copyable_v<T>) { + size_t first_part = other.FirstPart(); + Assume(first_part > 0 || m_size == 0); + if (first_part != 0) { + std::memcpy(m_buffer, other.m_buffer + other.m_offset, first_part * sizeof(T)); + } + if (first_part != other.m_size) { + std::memcpy(m_buffer + first_part, other.m_buffer, (other.m_size - first_part) * sizeof(T)); + } + m_size = other.m_size; + } else { + while (m_size < other.m_size) { + std::construct_at(m_buffer + BufferIndex(m_size), other[m_size]); + ++m_size; + } + } + return *this; + } + + /** Swap two deques. */ + void swap(VecDeque& other) noexcept + { + std::swap(m_buffer, other.m_buffer); + std::swap(m_offset, other.m_offset); + std::swap(m_size, other.m_size); + std::swap(m_capacity, other.m_capacity); + } + + /** Non-member version of swap. */ + friend void swap(VecDeque& a, VecDeque& b) noexcept { a.swap(b); } + + /** Move-assign a deque. */ + VecDeque& operator=(VecDeque&& other) noexcept + { + swap(other); + return *this; + } + + /** Copy-construct a deque. */ + VecDeque(const VecDeque& other) { *this = other; } + /** Move-construct a deque. */ + VecDeque(VecDeque&& other) noexcept { swap(other); } + + /** Equality comparison between two deques (only compares size+contents, not capacity). */ + bool friend operator==(const VecDeque& a, const VecDeque& b) + { + if (a.m_size != b.m_size) return false; + for (size_t i = 0; i < a.m_size; ++i) { + if (a[i] != b[i]) return false; + } + return true; + } + + /** Comparison between two deques, implementing lexicographic ordering on the contents. */ + std::strong_ordering friend operator<=>(const VecDeque& a, const VecDeque& b) + { + size_t pos_a{0}, pos_b{0}; + while (pos_a < a.m_size && pos_b < b.m_size) { + auto cmp = a[pos_a++] <=> b[pos_b++]; + if (cmp != 0) return cmp; + } + return a.m_size <=> b.m_size; + } + + /** Increase the capacity to capacity. Capacity will not shrink. */ + void reserve(size_t capacity) + { + if (capacity > m_capacity) Reallocate(capacity); + } + + /** Make the capacity equal to the size. The contents does not change. */ + void shrink_to_fit() + { + if (m_capacity > m_size) Reallocate(m_size); + } + + /** Construct a new element at the end of the deque. */ + template<typename... Args> + void emplace_back(Args&&... args) + { + if (m_size == m_capacity) Reallocate((m_size + 1) * 2); + std::construct_at(m_buffer + BufferIndex(m_size), std::forward<Args>(args)...); + ++m_size; + } + + /** Move-construct a new element at the end of the deque. */ + void push_back(T&& elem) { emplace_back(std::move(elem)); } + + /** Copy-construct a new element at the end of the deque. */ + void push_back(const T& elem) { emplace_back(elem); } + + /** Construct a new element at the beginning of the deque. */ + template<typename... Args> + void emplace_front(Args&&... args) + { + if (m_size == m_capacity) Reallocate((m_size + 1) * 2); + std::construct_at(m_buffer + BufferIndex(m_capacity - 1), std::forward<Args>(args)...); + if (m_offset == 0) m_offset = m_capacity; + --m_offset; + ++m_size; + } + + /** Copy-construct a new element at the beginning of the deque. */ + void push_front(const T& elem) { emplace_front(elem); } + + /** Move-construct a new element at the beginning of the deque. */ + void push_front(T&& elem) { emplace_front(std::move(elem)); } + + /** Remove the first element of the deque. Requires !empty(). */ + void pop_front() + { + Assume(m_size); + std::destroy_at(m_buffer + m_offset); + --m_size; + ++m_offset; + if (m_offset == m_capacity) m_offset = 0; + } + + /** Remove the last element of the deque. Requires !empty(). */ + void pop_back() + { + Assume(m_size); + std::destroy_at(m_buffer + BufferIndex(m_size - 1)); + --m_size; + } + + /** Get a mutable reference to the first element of the deque. Requires !empty(). */ + T& front() noexcept + { + Assume(m_size); + return m_buffer[m_offset]; + } + + /** Get a const reference to the first element of the deque. Requires !empty(). */ + const T& front() const noexcept + { + Assume(m_size); + return m_buffer[m_offset]; + } + + /** Get a mutable reference to the last element of the deque. Requires !empty(). */ + T& back() noexcept + { + Assume(m_size); + return m_buffer[BufferIndex(m_size - 1)]; + } + + /** Get a const reference to the last element of the deque. Requires !empty(). */ + const T& back() const noexcept + { + Assume(m_size); + return m_buffer[BufferIndex(m_size - 1)]; + } + + /** Get a mutable reference to the element in the deque at the given index. Requires idx < size(). */ + T& operator[](size_t idx) noexcept + { + Assume(idx < m_size); + return m_buffer[BufferIndex(idx)]; + } + + /** Get a const reference to the element in the deque at the given index. Requires idx < size(). */ + const T& operator[](size_t idx) const noexcept + { + Assume(idx < m_size); + return m_buffer[BufferIndex(idx)]; + } + + /** Test whether the contents of this deque is empty. */ + bool empty() const noexcept { return m_size == 0; } + /** Get the number of elements in this deque. */ + size_t size() const noexcept { return m_size; } + /** Get the capacity of this deque (maximum size it can have without reallocating). */ + size_t capacity() const noexcept { return m_capacity; } +}; + +#endif // BITCOIN_UTIL_VECDEQUE_H diff --git a/src/validation.cpp b/src/validation.cpp index 4e6f0ed702..ab94ac02eb 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,9 +1,9 @@ // 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. -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <validation.h> @@ -27,19 +27,19 @@ #include <kernel/mempool_entry.h> #include <kernel/messagestartchars.h> #include <kernel/notifications_interface.h> +#include <kernel/warning.h> #include <logging.h> #include <logging/timer.h> #include <node/blockstorage.h> #include <node/utxo_snapshot.h> -#include <policy/v3_policy.h> #include <policy/policy.h> #include <policy/rbf.h> #include <policy/settings.h> +#include <policy/truc_policy.h> #include <pow.h> #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> @@ -57,11 +57,11 @@ #include <util/result.h> #include <util/signalinterrupt.h> #include <util/strencodings.h> +#include <util/string.h> #include <util/time.h> #include <util/trace.h> #include <util/translation.h> #include <validationinterface.h> -#include <warnings.h> #include <algorithm> #include <cassert> @@ -69,6 +69,8 @@ #include <deque> #include <numeric> #include <optional> +#include <ranges> +#include <span> #include <string> #include <tuple> #include <utility> @@ -106,10 +108,6 @@ const std::vector<std::string> CHECKLEVEL_DOC { * */ static constexpr int PRUNE_LOCK_BUFFER{10}; -GlobalMutex g_best_block_mutex; -std::condition_variable g_best_block_cv; -uint256 g_best_block; - const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locator) const { AssertLockHeld(cs_main); @@ -133,6 +131,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); @@ -267,7 +266,7 @@ static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache) AssertLockHeld(pool.cs); int expired = pool.Expire(GetTime<std::chrono::seconds>() - pool.m_opts.expiry); if (expired != 0) { - LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired); + LogDebug(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired); } std::vector<COutPoint> vNoSpendsRemaining; @@ -335,7 +334,7 @@ void Chainstate::MaybeUpdateMempoolForReorg( // Also updates valid entries' cached LockPoints if needed. // If false, the tx is still valid and its lockpoints are updated. // If true, the tx would be invalid in the next block; remove this entry and all of its descendants. - // Note that v3 rules are not applied here, so reorgs may cause violations of v3 inheritance or + // Note that TRUC rules are not applied here, so reorgs may cause violations of TRUC inheritance or // topology restrictions. const auto filter_final_and_mature = [&](CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main) { @@ -393,7 +392,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); @@ -425,7 +425,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 { @@ -524,7 +524,7 @@ public: /* m_bypass_limits */ false, /* m_coins_to_uncache */ coins_to_uncache, /* m_test_accept */ false, - /* m_allow_replacement */ false, + /* m_allow_replacement */ true, /* m_allow_sibling_eviction */ false, /* m_package_submission */ true, /* m_package_feerates */ true, @@ -602,8 +602,8 @@ public: /** * Submission of a subpackage. * If subpackage size == 1, calls AcceptSingleTransaction() with adjusted ATMPArgs to avoid - * package policy restrictions like no CPFP carve out (PackageMempoolChecks) and disabled RBF - * (m_allow_replacement), and creates a PackageMempoolAcceptResult wrapping the result. + * package policy restrictions like no CPFP carve out (PackageMempoolChecks) + * and creates a PackageMempoolAcceptResult wrapping the result. * * If subpackage size > 1, calls AcceptMultipleTransactions() with the provided ATMPArgs. * @@ -666,12 +666,13 @@ private: // only tests that are fast should be done here (to avoid CPU DoS). bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); - // Run checks for mempool replace-by-fee. + // Run checks for mempool replace-by-fee, only used in AcceptSingleTransaction. bool ReplacementChecks(Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Enforce package mempool ancestor/descendant limits (distinct from individual - // ancestor/descendant limits done in PreChecks). + // ancestor/descendant limits done in PreChecks) and run Package RBF checks. bool PackageMempoolChecks(const std::vector<CTransactionRef>& txns, + std::vector<Workspace>& workspaces, int64_t total_vsize, PackageValidationState& package_state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); @@ -714,6 +715,11 @@ private: return true; } + ValidationCache& GetValidationCache() + { + return m_active_chainstate.m_chainman.m_validation_cache; + } + private: CTxMemPool& m_pool; CCoinsViewCache m_view; @@ -827,11 +833,11 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // check all unconfirmed ancestors; otherwise an opt-in ancestor // might be replaced, causing removal of this descendant. // - // All V3 transactions are considered replaceable. + // All TRUC transactions are considered replaceable. // // Replaceability signaling of the original transactions may be // ignored due to node setting. - const bool allow_rbf{m_pool.m_opts.full_rbf || SignalsOptInRBF(*ptxConflicting) || ptxConflicting->nVersion == 3}; + const bool allow_rbf{m_pool.m_opts.full_rbf || SignalsOptInRBF(*ptxConflicting) || ptxConflicting->version == TRUC_VERSION}; if (!allow_rbf) { return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict"); } @@ -934,8 +940,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // while a tx could be package CPFP'd when entering the mempool, we do not have a DoS-resistant // method of ensuring the tx remains bumped. For example, the fee-bumping child could disappear // due to a replacement. - // The only exception is v3 transactions. - if (!bypass_limits && ws.m_ptx->nVersion != 3 && ws.m_modified_fees < m_pool.m_opts.min_relay_feerate.GetFee(ws.m_vsize)) { + // The only exception is TRUC transactions. + if (!bypass_limits && ws.m_ptx->version != TRUC_VERSION && ws.m_modified_fees < m_pool.m_opts.min_relay_feerate.GetFee(ws.m_vsize)) { // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not // TX_RECONSIDERABLE, because it cannot be bypassed using package validation. return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", @@ -949,7 +955,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts); // Note that these modifications are only applicable to single transaction scenarios; - // carve-outs and package RBF are disabled for multi-transaction evaluations. + // carve-outs are disabled for multi-transaction evaluations. CTxMemPool::Limits maybe_rbf_limits = m_pool.m_opts.limits; // Calculate in-mempool ancestors, up to a limit. @@ -1003,7 +1009,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // If the new transaction is relatively small (up to 40k weight) // and has at most one ancestor (ie ancestor limit of 2, including // the new transaction), allow it if its parent has exactly the - // descendant limit descendants. The transaction also cannot be v3, + // descendant limit descendants. The transaction also cannot be TRUC, // as its topology restrictions do not allow a second child. // // This allows protocols which rely on distrusting counterparties @@ -1017,7 +1023,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) .descendant_count = maybe_rbf_limits.descendant_count + 1, .descendant_size_vbytes = maybe_rbf_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT, }; - if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->nVersion == 3) { + if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->version == TRUC_VERSION) { return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message); } if (auto ancestors_retry{m_pool.CalculateMemPoolAncestors(*entry, cpfp_carve_out_limits)}) { @@ -1030,7 +1036,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Even though just checking direct mempool parents for inheritance would be sufficient, we // check using the full ancestor set here because it's more convenient to use what we have // already calculated. - if (const auto err{SingleV3Checks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) { + if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) { // Single transaction contexts only. if (args.m_allow_sibling_eviction && err->second != nullptr) { // We should only be considering where replacement is considered valid as well. @@ -1041,15 +1047,15 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) ws.m_conflicts.insert(err->second->GetHash()); // Adding the sibling to m_iters_conflicting here means that it doesn't count towards // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from - // the descendant count is done separately in SingleV3Checks for v3 transactions. + // the descendant count is done separately in SingleTRUCChecks for TRUC transactions. ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value()); ws.m_sibling_eviction = true; // The sibling will be treated as part of the to-be-replaced set in ReplacementChecks. - // Note that we are not checking whether it opts in to replaceability via BIP125 or v3 - // (which is normally done in PreChecks). However, the only way a v3 transaction can - // have a non-v3 and non-BIP125 descendant is due to a reorg. + // Note that we are not checking whether it opts in to replaceability via BIP125 or TRUC + // (which is normally done in PreChecks). However, the only way a TRUC transaction can + // have a non-TRUC and non-BIP125 descendant is due to a reorg. } else { - return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "v3-rule-violation", err->first); + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first); } } @@ -1088,10 +1094,9 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws) // descendant transaction of a direct conflict to pay a higher feerate than the transaction that // might replace them, under these rules. if (const auto err_string{PaysMoreThanConflicts(ws.m_iters_conflicting, newFeeRate, hash)}) { - // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not - // TX_RECONSIDERABLE, because it cannot be bypassed using package validation. - // This must be changed if package RBF is enabled. - return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, + // This fee-related failure is TX_RECONSIDERABLE because validating in a package may change + // the result. + return state.Invalid(TxValidationResult::TX_RECONSIDERABLE, strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string); } @@ -1102,7 +1107,7 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws) } // Enforce Rule #2. if (const auto err_string{HasNoNewUnconfirmed(tx, m_pool, m_subpackage.m_all_conflicts)}) { - // Sibling eviction is only done for v3 transactions, which cannot have multiple ancestors. + // Sibling eviction is only done for TRUC transactions, which cannot have multiple ancestors. Assume(!ws.m_sibling_eviction); return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, strprintf("replacement-adds-unconfirmed%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string); @@ -1116,16 +1121,15 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws) } if (const auto err_string{PaysForRBF(m_subpackage.m_conflicting_fees, ws.m_modified_fees, ws.m_vsize, m_pool.m_opts.incremental_relay_feerate, hash)}) { - // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not - // TX_RECONSIDERABLE, because it cannot be bypassed using package validation. - // This must be changed if package RBF is enabled. - return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, + // Result may change in a package context + return state.Invalid(TxValidationResult::TX_RECONSIDERABLE, strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string); } return true; } bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txns, + std::vector<Workspace>& workspaces, const int64_t total_vsize, PackageValidationState& package_state) { @@ -1136,12 +1140,88 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn assert(std::all_of(txns.cbegin(), txns.cend(), [this](const auto& tx) { return !m_pool.exists(GenTxid::Txid(tx->GetHash()));})); + assert(txns.size() == workspaces.size()); + auto result = m_pool.CheckPackageLimits(txns, total_vsize); if (!result) { // This is a package-wide error, separate from an individual transaction error. return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", util::ErrorString(result).original); } - return true; + + // No conflicts means we're finished. Further checks are all RBF-only. + if (!m_subpackage.m_rbf) return true; + + // We're in package RBF context; replacement proposal must be size 2 + if (workspaces.size() != 2 || !Assume(IsChildWithParents(txns))) { + return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package RBF failed: package must be 1-parent-1-child"); + } + + // If the package has in-mempool ancestors, we won't consider a package RBF + // since it would result in a cluster larger than 2. + // N.B. To relax this constraint we will need to revisit how CCoinsViewMemPool::PackageAddTransaction + // is being used inside AcceptMultipleTransactions to track available inputs while processing a package. + for (const auto& ws : workspaces) { + if (!ws.m_ancestors.empty()) { + return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package RBF failed: new transaction cannot have mempool ancestors"); + } + } + + // Aggregate all conflicts into one set. + CTxMemPool::setEntries direct_conflict_iters; + for (Workspace& ws : workspaces) { + // Aggregate all conflicts into one set. + direct_conflict_iters.merge(ws.m_iters_conflicting); + } + + const auto& parent_ws = workspaces[0]; + const auto& child_ws = workspaces[1]; + + // Don't consider replacements that would cause us to remove a large number of mempool entries. + // This limit is not increased in a package RBF. Use the aggregate number of transactions. + if (const auto err_string{GetEntriesForConflicts(*child_ws.m_ptx, m_pool, direct_conflict_iters, + m_subpackage.m_all_conflicts)}) { + return package_state.Invalid(PackageValidationResult::PCKG_POLICY, + "package RBF failed: too many potential replacements", *err_string); + } + + for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts) { + m_subpackage.m_conflicting_fees += it->GetModifiedFee(); + m_subpackage.m_conflicting_size += it->GetTxSize(); + } + + // Use the child as the transaction for attributing errors to. + const Txid& child_hash = child_ws.m_ptx->GetHash(); + if (const auto err_string{PaysForRBF(/*original_fees=*/m_subpackage.m_conflicting_fees, + /*replacement_fees=*/m_subpackage.m_total_modified_fees, + /*replacement_vsize=*/m_subpackage.m_total_vsize, + m_pool.m_opts.incremental_relay_feerate, child_hash)}) { + return package_state.Invalid(PackageValidationResult::PCKG_POLICY, + "package RBF failed: insufficient anti-DoS fees", *err_string); + } + + // Ensure this two transaction package is a "chunk" on its own; we don't want the child + // to be only paying anti-DoS fees + const CFeeRate parent_feerate(parent_ws.m_modified_fees, parent_ws.m_vsize); + 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 or equal to parent feerate", + strprintf("package feerate %s <= parent feerate is %s", package_feerate.ToString(), parent_feerate.ToString())); + } + + // Check if it's economically rational to mine this package rather than the ones it replaces. + // This takes the place of ReplacementChecks()'s PaysMoreThanConflicts() in the package RBF setting. + if (const auto err_tup{ImprovesFeerateDiagram(m_pool, direct_conflict_iters, m_subpackage.m_all_conflicts, m_subpackage.m_total_modified_fees, m_subpackage.m_total_vsize)}) { + return package_state.Invalid(PackageValidationResult::PCKG_POLICY, + "package RBF failed: " + err_tup.value().second, ""); + } + + LogDebug(BCLog::TXPACKAGES, "package RBF checks passed: parent %s (wtxid=%s), child %s (wtxid=%s)\n", + txns.front()->GetHash().ToString(), txns.front()->GetWitnessHash().ToString(), + txns.back()->GetHash().ToString(), txns.back()->GetWitnessHash().ToString()); + + + return true; } bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws) @@ -1155,13 +1235,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()); @@ -1197,7 +1277,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); } @@ -1215,16 +1295,19 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws) const bool bypass_limits = args.m_bypass_limits; std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry; + if (!m_subpackage.m_all_conflicts.empty()) Assume(args.m_allow_replacement); // Remove conflicting transactions from the mempool for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts) { - LogPrint(BCLog::MEMPOOL, "replacing tx %s (wtxid=%s) with %s (wtxid=%s) for %s additional fees, %d delta bytes\n", + LogDebug(BCLog::MEMPOOL, "replacing mempool tx %s (wtxid=%s, fees=%s, vsize=%s). New tx %s (wtxid=%s, fees=%s, vsize=%s)\n", it->GetTx().GetHash().ToString(), it->GetTx().GetWitnessHash().ToString(), + it->GetFee(), + it->GetTxSize(), hash.ToString(), tx.GetWitnessHash().ToString(), - FormatMoney(ws.m_modified_fees - m_subpackage.m_conflicting_fees), - (int)entry->GetTxSize() - (int)m_subpackage.m_conflicting_size); + entry->GetFee(), + entry->GetTxSize()); TRACE7(mempool, replaced, it->GetTx().GetHash().data(), it->GetTxSize(), @@ -1318,6 +1401,13 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& std::transform(workspaces.cbegin(), workspaces.cend(), std::back_inserter(all_package_wtxids), [](const auto& ws) { return ws.m_ptx->GetWitnessHash(); }); + if (!m_subpackage.m_replaced_transactions.empty()) { + LogDebug(BCLog::MEMPOOL, "replaced %u mempool transactions with %u new one(s) for %s additional fees, %d delta bytes\n", + m_subpackage.m_replaced_transactions.size(), workspaces.size(), + m_subpackage.m_total_modified_fees - m_subpackage.m_conflicting_fees, + m_subpackage.m_total_vsize - static_cast<int>(m_subpackage.m_conflicting_size)); + } + // Add successful results. The returned results may change later if LimitMempoolSize() evicts them. for (Workspace& ws : workspaces) { const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate : @@ -1361,7 +1451,13 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef return MempoolAcceptResult::Failure(ws.m_state); } - if (m_subpackage.m_rbf && !ReplacementChecks(ws)) return MempoolAcceptResult::Failure(ws.m_state); + if (m_subpackage.m_rbf && !ReplacementChecks(ws)) { + if (ws.m_state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) { + // Failed for incentives-based fee reasons. Provide the effective feerate and which tx was included. + return MempoolAcceptResult::FeeFailure(ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), single_wtxid); + } + return MempoolAcceptResult::Failure(ws.m_state); + } // Perform the inexpensive checks first and avoid hashing and signature verification unless // those checks pass, to mitigate CPU exhaustion denial-of-service attacks. @@ -1393,6 +1489,13 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef m_pool.m_opts.signals->TransactionAddedToMempool(tx_info, m_pool.GetAndIncrementSequence()); } + if (!m_subpackage.m_replaced_transactions.empty()) { + LogDebug(BCLog::MEMPOOL, "replaced %u mempool transactions with 1 new transaction for %s additional fees, %d delta bytes\n", + m_subpackage.m_replaced_transactions.size(), + ws.m_modified_fees - m_subpackage.m_conflicting_fees, + ws.m_vsize - static_cast<int>(m_subpackage.m_conflicting_size)); + } + return MempoolAcceptResult::Success(std::move(m_subpackage.m_replaced_transactions), ws.m_vsize, ws.m_base_fees, effective_feerate, single_wtxid); } @@ -1434,19 +1537,22 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std:: } // Make the coins created by this transaction available for subsequent transactions in the - // package to spend. Since we already checked conflicts in the package and we don't allow - // replacements, we don't need to track the coins spent. Note that this logic will need to be - // updated if package replace-by-fee is allowed in the future. - assert(!args.m_allow_replacement); - assert(!m_subpackage.m_rbf); + // package to spend. If there are no conflicts within the package, no transaction can spend a coin + // needed by another transaction in the package. We also need to make sure that no package + // tx replaces (or replaces the ancestor of) the parent of another package tx. As long as we + // check these two things, we don't need to track the coins spent. + // If a package tx conflicts with a mempool tx, PackageMempoolChecks() ensures later that any package RBF attempt + // has *no* in-mempool ancestors, so we don't have to worry about subsequent transactions in + // same package spending the same in-mempool outpoints. This needs to be revisited for general + // package RBF. m_viewmempool.PackageAddTransaction(ws.m_ptx); } // At this point we have all in-mempool ancestors, and we know every transaction's vsize. - // Run the v3 checks on the package. + // Run the TRUC checks on the package. for (Workspace& ws : workspaces) { - if (auto err{PackageV3Checks(ws.m_ptx, ws.m_vsize, txns, ws.m_ancestors)}) { - package_state.Invalid(PackageValidationResult::PCKG_POLICY, "v3-violation", err.value()); + if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, txns, ws.m_ancestors)}) { + package_state.Invalid(PackageValidationResult::PCKG_POLICY, "TRUC-violation", err.value()); return PackageMempoolAcceptResult(package_state, {}); } } @@ -1479,7 +1585,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std:: // Apply package mempool ancestor/descendant limits. Skip if there is only one transaction, // because it's unnecessary. - if (txns.size() > 1 && !PackageMempoolChecks(txns, m_subpackage.m_total_vsize, package_state)) { + if (txns.size() > 1 && !PackageMempoolChecks(txns, workspaces, m_subpackage.m_total_vsize, package_state)) { return PackageMempoolAcceptResult(package_state, std::move(results)); } @@ -1747,7 +1853,6 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx, int64_t accept_time, bool bypass_limits, bool test_accept) - EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { AssertLockHeld(::cs_main); const CChainParams& chainparams{active_chainstate.m_chainman.GetParams()}; @@ -1915,15 +2020,18 @@ void Chainstate::CheckForkWarningConditions() // Before we get past initial download, we cannot reliably alert about forks // (we assume we don't get stuck on a fork before finishing our initial sync) - if (m_chainman.IsInitialBlockDownload()) { + // Also not applicable to the background chainstate + if (m_chainman.IsInitialBlockDownload() || this->GetRole() == ChainstateRole::BACKGROUND) { return; } if (m_chainman.m_best_invalid && m_chainman.m_best_invalid->nChainWork > m_chain.Tip()->nChainWork + (GetBlockProof(*m_chain.Tip()) * 6)) { LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); - SetfLargeWorkInvalidChainFound(true); + m_chainman.GetNotifications().warningSet( + kernel::Warning::LARGE_WORK_INVALID_CHAIN, + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.")); } else { - SetfLargeWorkInvalidChainFound(false); + m_chainman.GetNotifications().warningUnset(kernel::Warning::LARGE_WORK_INVALID_CHAIN); } } @@ -1981,29 +2089,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); + m_script_execution_cache_hasher.Write(nonce.begin(), 32); + m_script_execution_cache_hasher.Write(nonce.begin(), 32); - auto setup_results = g_scriptExecutionCache.setup_bytes(max_size_bytes); - if (!setup_results) return false; - - 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); } /** @@ -2023,11 +2125,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; @@ -2042,10 +2145,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; } @@ -2072,10 +2175,12 @@ 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()) { + ScriptError error{check.GetScriptError()}; + if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { // Check whether the failure was caused by a // non-mandatory script verification check, such as @@ -2085,10 +2190,18 @@ 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()))); + + // If the second check failed, it failed due to a mandatory script verification + // flag, but the first check might have failed on a non-mandatory script + // verification flag. + // + // Avoid reporting a mandatory script check failure with a non-mandatory error + // string by reporting the error from the second check. + error = check2.GetScriptError(); } // MANDATORY flag failures correspond to // TxValidationResult::TX_CONSENSUS. Because CONSENSUS @@ -2099,14 +2212,14 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, // support, to avoid splitting the network (but this // depends on the details of how net_processing handles // such errors). - return state.Invalid(TxValidationResult::TX_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); + return state.Invalid(TxValidationResult::TX_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(error))); } } 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; @@ -2177,8 +2290,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--) { @@ -2294,15 +2407,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). */ @@ -2347,7 +2451,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) @@ -2389,11 +2493,11 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, } const auto time_1{SteadyClock::now()}; - time_check += time_1 - time_start; - LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_check += time_1 - time_start; + LogDebug(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. @@ -2491,11 +2595,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; - LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_forks += time_2 - time_1; + LogDebug(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; @@ -2564,7 +2668,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()); @@ -2582,12 +2686,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; - LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), + m_chainman.time_connect += time_3 - time_2; + LogDebug(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) { @@ -2600,12 +2704,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; - LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, + m_chainman.time_verify += time_4 - time_2; + LogDebug(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; @@ -2615,11 +2719,11 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, } const auto time_5{SteadyClock::now()}; - time_undo += time_5 - time_4; - LogPrint(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_undo += time_5 - time_4; + LogDebug(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); @@ -2630,11 +2734,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; - LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_index += time_6 - time_5; + LogDebug(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(), @@ -2642,7 +2746,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, block.vtx.size(), nInputs, nSigOpsCost, - time_5 - time_start // in microseconds (µs) + Ticks<std::chrono::nanoseconds>(time_5 - time_start) ); return true; @@ -2700,7 +2804,7 @@ bool Chainstate::FlushStateToDisk( CoinsCacheSizeState cache_state = GetCoinsCacheSizeState(); LOCK(m_blockman.cs_LastBlockFile); - if (m_blockman.IsPruneMode() && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !m_chainman.m_blockman.m_reindexing) { + if (m_blockman.IsPruneMode() && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && m_chainman.m_blockman.m_blockfiles_indexed) { // make sure we don't prune above any of the prune locks bestblocks // pruning is height-based int last_prune{m_chain.Height()}; // last height we can prune @@ -2717,7 +2821,7 @@ bool Chainstate::FlushStateToDisk( } if (limiting_lock) { - LogPrint(BCLog::PRUNE, "%s limited pruning to height %d\n", limiting_lock.value(), last_prune); + LogDebug(BCLog::PRUNE, "%s limited pruning to height %d\n", limiting_lock.value(), last_prune); } if (nManualPruneHeight > 0) { @@ -2806,7 +2910,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.")); } @@ -2847,13 +2951,6 @@ void Chainstate::PruneAndFlush() } } -/** Private helper function that concatenates warning messages. */ -static void AppendWarning(bilingual_str& res, const bilingual_str& warn) -{ - if (!res.empty()) res += Untranslated(", "); - res += warn; -} - static void UpdateTipLog( const CCoinsViewCache& coins_tip, const CBlockIndex* tip, @@ -2867,7 +2964,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)), @@ -2898,13 +2995,7 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew) m_mempool->AddTransactionsUpdated(1); } - { - LOCK(g_best_block_mutex); - g_best_block = pindexNew->GetBlockHash(); - g_best_block_cv.notify_all(); - } - - bilingual_str warning_messages; + std::vector<bilingual_str> warning_messages; if (!m_chainman.IsInitialBlockDownload()) { const CBlockIndex* pindex = pindexNew; for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { @@ -2913,14 +3004,15 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew) if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) { const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit); if (state == ThresholdState::ACTIVE) { - m_chainman.GetNotifications().warning(warning); + m_chainman.GetNotifications().warningSet(kernel::Warning::UNKNOWN_NEW_RULES_ACTIVATED, warning); } else { - AppendWarning(warning_messages, warning); + warning_messages.push_back(warning); } } } } - UpdateTipLog(coins_tip, pindexNew, params, __func__, "", warning_messages.original); + UpdateTipLog(coins_tip, pindexNew, params, __func__, "", + util::Join(warning_messages, Untranslated(", ")).original); } /** Disconnect m_chain's tip. @@ -2960,7 +3052,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra bool flushed = view.Flush(); assert(flushed); } - LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", + LogDebug(BCLog::BENCH, "- Disconnect block: %.2fms\n", Ticks<MillisecondsDouble>(SteadyClock::now() - time_start)); { @@ -2970,7 +3062,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra if (prune_lock.second.height_first <= max_height_first) continue; prune_lock.second.height_first = max_height_first; - LogPrint(BCLog::PRUNE, "%s prune lock moved back to %d\n", prune_lock.first, max_height_first); + LogDebug(BCLog::PRUNE, "%s prune lock moved back to %d\n", prune_lock.first, max_height_first); } } @@ -2998,11 +3090,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; @@ -3065,7 +3152,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, } pthisBlock = pblockNew; } else { - LogPrint(BCLog::BENCH, " - Using cached block\n"); + LogDebug(BCLog::BENCH, " - Using cached block\n"); pthisBlock = pblock; } const CBlock& blockConnecting = *pthisBlock; @@ -3074,7 +3161,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, SteadyClock::time_point time_3; // When adding aggregate statistics in the future, keep in mind that // num_blocks_total may be zero until the ConnectBlock() call below. - LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms\n", + LogDebug(BCLog::BENCH, " - Load block from disk: %.2fms\n", Ticks<MillisecondsDouble>(time_2 - time_1)); { CCoinsViewCache view(&CoinsTip()); @@ -3089,31 +3176,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); - LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_connect_total += time_3 - time_2; + assert(m_chainman.num_blocks_total > 0); + LogDebug(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; - LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_flush += time_4 - time_3; + LogDebug(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; - LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_chainstate += time_5 - time_4; + LogDebug(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); @@ -3124,16 +3211,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; - LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", + m_chainman.time_post_connect += time_6 - time_5; + m_chainman.time_total += time_6 - time_1; + LogDebug(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", Ticks<MillisecondsDouble>(time_6 - time_5), - Ticks<SecondsDouble>(time_post_connect), - Ticks<MillisecondsDouble>(time_post_connect) / num_blocks_total); - LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<SecondsDouble>(m_chainman.time_post_connect), + Ticks<MillisecondsDouble>(m_chainman.time_post_connect) / m_chainman.num_blocks_total); + LogDebug(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). @@ -3272,7 +3359,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. @@ -3313,32 +3400,31 @@ bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* return true; } -static SynchronizationState GetSynchronizationState(bool init, bool reindexing) +static SynchronizationState GetSynchronizationState(bool init, bool blockfiles_indexed) { if (!init) return SynchronizationState::POST_INIT; - if (reindexing) return SynchronizationState::INIT_REINDEX; + if (!blockfiles_indexed) return SynchronizationState::INIT_REINDEX; 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_reindexing), pindexHeader->nHeight, pindexHeader->nTime, false); + GetNotifications().headerTip(GetSynchronizationState(fInitialBlockDownload, m_blockman.m_blockfiles_indexed), pindexHeader->nHeight, pindexHeader->nTime, false); } return fNotify; } @@ -3389,6 +3475,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(); @@ -3456,8 +3543,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< m_chainman.m_options.signals->UpdatedBlockTip(pindexNewTip, pindexFork, still_in_ibd); } - // Always notify the UI if a new block tip was connected - if (kernel::IsInterrupted(m_chainman.GetNotifications().blockTip(GetSynchronizationState(still_in_ibd, m_chainman.m_blockman.m_reindexing), *pindexNewTip))) { + if (kernel::IsInterrupted(m_chainman.GetNotifications().blockTip(GetSynchronizationState(still_in_ibd, m_chainman.m_blockman.m_blockfiles_indexed), *pindexNewTip))) { // Just breaking and returning success for now. This could // be changed to bubble up the kernel::Interrupted value to // the caller so the caller could distinguish between @@ -3465,7 +3551,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) { @@ -3484,8 +3575,8 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< // // This cannot be done while holding cs_main (within // MaybeCompleteSnapshotValidation) or a cs_main deadlock will occur. - if (m_chainman.restart_indexes) { - m_chainman.restart_indexes(); + if (m_chainman.snapshot_download_completed) { + m_chainman.snapshot_download_completed(); } break; } @@ -3683,7 +3774,13 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde // parameter indicating the source of the tip change so hooks can // distinguish user-initiated invalidateblock changes from other // changes. - (void)m_chainman.GetNotifications().blockTip(GetSynchronizationState(m_chainman.IsInitialBlockDownload(), m_chainman.m_blockman.m_reindexing), *to_mark_failed->pprev); + (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; } @@ -3750,17 +3847,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; @@ -3781,15 +3878,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); @@ -4040,7 +4137,7 @@ bool IsBlockMutated(const CBlock& block, bool check_witness_root) return false; } -arith_uint256 CalculateClaimedHeadersWork(const std::vector<CBlockHeader>& headers) +arith_uint256 CalculateClaimedHeadersWork(std::span<const CBlockHeader> headers) { arith_uint256 total_work{0}; for (const CBlockHeader& header : headers) { @@ -4086,6 +4183,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 and regtest 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"); @@ -4179,14 +4288,14 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida if (ppindex) *ppindex = pindex; if (pindex->nStatus & BLOCK_FAILED_MASK) { - LogPrint(BCLog::VALIDATION, "%s: block %s is marked invalid\n", __func__, hash.ToString()); + LogDebug(BCLog::VALIDATION, "%s: block %s is marked invalid\n", __func__, hash.ToString()); return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, "duplicate"); } return true; } if (!CheckBlockHeader(block, state, GetConsensus())) { - LogPrint(BCLog::VALIDATION, "%s: Consensus::CheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString()); + LogDebug(BCLog::VALIDATION, "%s: Consensus::CheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString()); return false; } @@ -4194,16 +4303,16 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida CBlockIndex* pindexPrev = nullptr; BlockMap::iterator mi{m_blockman.m_block_index.find(block.hashPrevBlock)}; if (mi == m_blockman.m_block_index.end()) { - LogPrint(BCLog::VALIDATION, "header %s has prev block not found: %s\n", hash.ToString(), block.hashPrevBlock.ToString()); + LogDebug(BCLog::VALIDATION, "header %s has prev block not found: %s\n", hash.ToString(), block.hashPrevBlock.ToString()); return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, "prev-blk-not-found"); } pindexPrev = &((*mi).second); if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { - LogPrint(BCLog::VALIDATION, "header %s has prev block invalid: %s\n", hash.ToString(), block.hashPrevBlock.ToString()); + LogDebug(BCLog::VALIDATION, "header %s has prev block invalid: %s\n", hash.ToString(), block.hashPrevBlock.ToString()); return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk"); } if (!ContextualCheckBlockHeader(block, state, m_blockman, *this, pindexPrev)) { - LogPrint(BCLog::VALIDATION, "%s: Consensus::ContextualCheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString()); + LogDebug(BCLog::VALIDATION, "%s: Consensus::ContextualCheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString()); return false; } @@ -4240,14 +4349,14 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida m_blockman.m_dirty_blockindex.insert(invalid_walk); invalid_walk = invalid_walk->pprev; } - LogPrint(BCLog::VALIDATION, "header %s has prev block invalid: %s\n", hash.ToString(), block.hashPrevBlock.ToString()); + LogDebug(BCLog::VALIDATION, "header %s has prev block invalid: %s\n", hash.ToString(), block.hashPrevBlock.ToString()); return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk"); } } } } if (!min_pow_checked) { - LogPrint(BCLog::VALIDATION, "%s: not adding new block header %s, missing anti-dos proof-of-work validation\n", __func__, hash.ToString()); + LogDebug(BCLog::VALIDATION, "%s: not adding new block header %s, missing anti-dos proof-of-work validation\n", __func__, hash.ToString()); return state.Invalid(BlockValidationResult::BLOCK_HEADER_LOW_WORK, "too-little-chainwork"); } CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, m_best_header)}; @@ -4276,7 +4385,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida } // Exposed wrapper for AcceptBlockHeader -bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex) +bool ChainstateManager::ProcessNewBlockHeaders(std::span<const CBlockHeader> headers, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex) { AssertLockNotHeld(cs_main); { @@ -4294,7 +4403,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()}; @@ -4322,7 +4431,7 @@ void ChainstateManager::ReportHeadersPresync(const arith_uint256& work, int64_t m_last_presync_update = now; } bool initial_download = IsInitialBlockDownload(); - GetNotifications().headerTip(GetSynchronizationState(initial_download, m_blockman.m_reindexing), height, timestamp, /*presync=*/true); + GetNotifications().headerTip(GetSynchronizationState(initial_download, m_blockman.m_blockfiles_indexed), height, timestamp, /*presync=*/true); if (initial_download) { int64_t blocks_left{(NodeClock::now() - NodeSeconds{std::chrono::seconds{timestamp}}) / GetConsensus().PowTargetSpacing()}; blocks_left = std::max<int64_t>(0, blocks_left); @@ -4465,7 +4574,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)) { @@ -4849,8 +4958,7 @@ bool ChainstateManager::LoadBlockIndex() { AssertLockHeld(cs_main); // Load block index from databases - bool needs_init = m_blockman.m_reindexing; - if (!m_blockman.m_reindexing) { + if (m_blockman.m_blockfiles_indexed) { bool ret{m_blockman.LoadBlockIndexDB(SnapshotBlockhash())}; if (!ret) return false; @@ -4881,18 +4989,6 @@ bool ChainstateManager::LoadBlockIndex() if (pindex->IsValid(BLOCK_VALID_TREE) && (m_best_header == nullptr || CBlockIndexWorkComparator()(m_best_header, pindex))) m_best_header = pindex; } - - needs_init = m_blockman.m_block_index.empty(); - } - - if (needs_init) { - // Everything here is for *new* reindex/DBs. Thus, though - // LoadBlockIndexDB may have set m_reindexing if we shut down - // mid-reindex previously, we don't check m_reindexing and - // instead only check it prior to LoadBlockIndexDB to set - // needs_init. - - LogPrintf("Initializing databases...\n"); } return true; } @@ -4989,7 +5085,7 @@ void ChainstateManager::LoadExternalBlockFile( LOCK(cs_main); // detect out of order blocks, and store them for later if (hash != params.GetConsensus().hashGenesisBlock && !m_blockman.LookupBlockIndex(header.hashPrevBlock)) { - LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), + LogDebug(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), header.hashPrevBlock.ToString()); if (dbp && blocks_with_unknown_parent) { blocks_with_unknown_parent->emplace(header.hashPrevBlock, *dbp); @@ -5014,7 +5110,7 @@ void ChainstateManager::LoadExternalBlockFile( break; } } else if (hash != params.GetConsensus().hashGenesisBlock && pindex->nHeight % 1000 == 0) { - LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), pindex->nHeight); + LogDebug(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), pindex->nHeight); } } @@ -5033,7 +5129,7 @@ void ChainstateManager::LoadExternalBlockFile( } } - if (m_blockman.IsPruneMode() && !m_blockman.m_reindexing && pblock) { + if (m_blockman.IsPruneMode() && m_blockman.m_blockfiles_indexed && pblock) { // must update the tip for pruning to work while importing with -loadblock. // this is a tradeoff to conserve disk space at the expense of time // spent updating the tip to be able to prune. @@ -5045,7 +5141,7 @@ void ChainstateManager::LoadExternalBlockFile( for (auto c : GetAll()) { BlockValidationState state; if (!c->ActivateBestChain(state, pblock)) { - LogPrint(BCLog::REINDEX, "failed to activate chain (%s)\n", state.ToString()); + LogDebug(BCLog::REINDEX, "failed to activate chain (%s)\n", state.ToString()); activation_failure = true; break; } @@ -5055,7 +5151,7 @@ void ChainstateManager::LoadExternalBlockFile( } } - NotifyHeaderTip(*this); + NotifyHeaderTip(); if (!blocks_with_unknown_parent) continue; @@ -5070,7 +5166,7 @@ void ChainstateManager::LoadExternalBlockFile( std::multimap<uint256, FlatFilePos>::iterator it = range.first; std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>(); if (m_blockman.ReadBlockFromDisk(*pblockrecursive, it->second)) { - LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(), + LogDebug(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(), head.ToString()); LOCK(cs_main); BlockValidationState dummy; @@ -5081,7 +5177,7 @@ void ChainstateManager::LoadExternalBlockFile( } range.first++; blocks_with_unknown_parent->erase(it); - NotifyHeaderTip(*this); + NotifyHeaderTip(); } } } catch (const std::exception& e) { @@ -5096,7 +5192,7 @@ void ChainstateManager::LoadExternalBlockFile( // the reindex process is not the place to attempt to clean and/or compact the block files. if so desired, a studious node operator // may use knowledge of the fact that the block files are not entirely pristine in order to prepare a set of pristine, and // perhaps ordered, block files for later reindexing. - LogPrint(BCLog::REINDEX, "%s: unexpected data at file offset 0x%x - %s. continuing\n", __func__, (nRewind - 1), e.what()); + LogDebug(BCLog::REINDEX, "%s: unexpected data at file offset 0x%x - %s. continuing\n", __func__, (nRewind - 1), e.what()); } } } catch (const std::runtime_error& e) { @@ -5105,6 +5201,14 @@ void ChainstateManager::LoadExternalBlockFile( LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } +bool ChainstateManager::ShouldCheckBlockIndex() const +{ + // Assert to verify Flatten() has been called. + if (!*Assert(m_options.check_block_index)) return false; + if (FastRandomContext().randrange(*m_options.check_block_index) >= 1) return false; + return true; +} + void ChainstateManager::CheckBlockIndex() { if (!ShouldCheckBlockIndex()) { @@ -5121,19 +5225,28 @@ void ChainstateManager::CheckBlockIndex() return; } - // Build forward-pointing map of the entire block tree. + // Build forward-pointing data structure for the entire block tree. + // For performance reasons, indexes of the best header chain are stored in a vector (within CChain). + // All remaining blocks are stored in a multimap. + // The best header chain can differ from the active chain: E.g. its entries may belong to blocks that + // are not yet validated. + CChain best_hdr_chain; + assert(m_best_header); + best_hdr_chain.SetTip(*m_best_header); + std::multimap<CBlockIndex*,CBlockIndex*> forward; for (auto& [_, block_index] : m_blockman.m_block_index) { - forward.emplace(block_index.pprev, &block_index); + // Only save indexes in forward that are not part of the best header chain. + if (!best_hdr_chain.Contains(&block_index)) { + // Only genesis, which must be part of the best header chain, can have a nullptr parent. + assert(block_index.pprev); + forward.emplace(block_index.pprev, &block_index); + } } + assert(forward.size() + best_hdr_chain.Height() + 1 == m_blockman.m_block_index.size()); - assert(forward.size() == m_blockman.m_block_index.size()); - - std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range(nullptr); - CBlockIndex *pindex = rangeGenesis.first->second; - rangeGenesis.first++; - assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent nullptr. - + CBlockIndex* pindex = best_hdr_chain[0]; + assert(pindex); // Iterate over the entire block tree, using depth-first search. // Along the way, remember whether there are blocks on the path from genesis // block being explored which are the first to have certain properties. @@ -5233,17 +5346,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 @@ -5272,7 +5385,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 @@ -5345,14 +5458,21 @@ void ChainstateManager::CheckBlockIndex() // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow // End: actual consistency checks. - // Try descending into the first subnode. + + // Try descending into the first subnode. Always process forks first and the best header chain after. snap_update_firsts(); std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> range = forward.equal_range(pindex); if (range.first != range.second) { - // A subnode was found. + // A subnode not part of the best header chain was found. pindex = range.first->second; nHeight++; continue; + } else if (best_hdr_chain.Contains(pindex)) { + // Descend further into best header chain. + nHeight++; + pindex = best_hdr_chain[nHeight]; + if (!pindex) break; // we are finished, since the best header chain is always processed last + continue; } // This is a leaf node. // Move upwards until we reach a node of which we have not yet visited the last child. @@ -5378,9 +5498,15 @@ void ChainstateManager::CheckBlockIndex() // Proceed to the next one. rangePar.first++; if (rangePar.first != rangePar.second) { - // Move to the sibling. + // Move to a sibling not part of the best header chain. pindex = rangePar.first->second; break; + } else if (pindexPar == best_hdr_chain[nHeight - 1]) { + // Move to pindex's sibling on the best-chain, if it has one. + pindex = best_hdr_chain[nHeight]; + // There will not be a next block if (and only if) parent block is the best header. + assert((pindex == nullptr) == (pindexPar == best_hdr_chain.Tip())); + break; } else { // Move up further. pindex = pindexPar; @@ -5390,8 +5516,8 @@ void ChainstateManager::CheckBlockIndex() } } - // Check that we actually traversed the entire map. - assert(nNodes == forward.size()); + // Check that we actually traversed the entire block index. + assert(nNodes == forward.size() + best_hdr_chain.Height() + 1); } std::string Chainstate::ToString() @@ -5435,13 +5561,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; } @@ -5450,13 +5576,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 @@ -5532,7 +5658,7 @@ Chainstate& ChainstateManager::InitializeChainstate(CTxMemPool* mempool) return destroyed && !fs::exists(db_path); } -bool ChainstateManager::ActivateSnapshot( +util::Result<CBlockIndex*> ChainstateManager::ActivateSnapshot( AutoFile& coins_file, const SnapshotMetadata& metadata, bool in_memory) @@ -5540,15 +5666,40 @@ bool ChainstateManager::ActivateSnapshot( uint256 base_blockhash = metadata.m_base_blockhash; if (this->SnapshotBlockhash()) { - LogPrintf("[snapshot] can't activate a snapshot-based chainstate more than once\n"); - return false; + return util::Error{Untranslated("Can't activate a snapshot-based chainstate more than once")}; } + CBlockIndex* snapshot_start_block{}; + { LOCK(::cs_main); - if (Assert(m_active_chainstate->GetMempool())->size() > 0) { - LogPrintf("[snapshot] can't activate a snapshot when mempool not empty\n"); - return false; + + 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(Untranslated("assumeutxo block hash in snapshot metadata not recognized (hash: %s). The following snapshot heights are available: %s"), + base_blockhash.ToString(), + heights_formatted)}; + } + + snapshot_start_block = m_blockman.LookupBlockIndex(base_blockhash); + if (!snapshot_start_block) { + 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(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.")}; + } + + auto mempool{m_active_chainstate->GetMempool()}; + if (mempool && mempool->size() > 0) { + return util::Error{Untranslated("Can't activate a snapshot when mempool not empty")}; } } @@ -5597,8 +5748,7 @@ bool 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) { - LogPrintf("[snapshot] activation failed - %s\n", reason); + auto cleanup_bad_snapshot = [&](bilingual_str reason) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { this->MaybeRebalanceCaches(); // PopulateAndValidateSnapshot can return (in error) before the leveldb datadir @@ -5614,12 +5764,12 @@ bool ChainstateManager::ActivateSnapshot( "Manually remove it before restarting.\n"), fs::PathToString(*snapshot_datadir))); } } - return false; + 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. @@ -5628,13 +5778,13 @@ bool 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")); } } @@ -5657,7 +5807,7 @@ bool ChainstateManager::ActivateSnapshot( m_snapshot_chainstate->CoinsTip().DynamicMemoryUsage() / (1000 * 1000)); this->MaybeRebalanceCaches(); - return true; + return snapshot_start_block; } static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_loaded) @@ -5684,7 +5834,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) @@ -5700,18 +5850,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; @@ -5720,8 +5868,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; @@ -5738,8 +5885,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++) { @@ -5751,14 +5897,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)); @@ -5778,7 +5922,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, @@ -5796,9 +5940,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)}; } } @@ -5818,9 +5961,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", @@ -5843,18 +5985,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); @@ -5874,7 +6014,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( index = snapshot_chainstate.m_chain[i]; // Fake BLOCK_OPT_WITNESS so that Chainstate::NeedsRedownload() - // won't ask to rewind the entire assumed-valid chain on startup. + // won't ask for -reindex on startup. if (DeploymentActiveAt(*index, *this, Consensus::DEPLOYMENT_SEGWIT)) { index->nStatus |= BLOCK_OPT_WITNESS; } @@ -5889,12 +6029,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 @@ -5950,8 +6090,8 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation() PACKAGE_NAME, snapshot_tip_height, snapshot_base_height, snapshot_base_height, PACKAGE_BUGREPORT ); - LogPrintf("[snapshot] !!! %s\n", user_error.original); - LogPrintf("[snapshot] deleting snapshot, reverting to validated chain, and stopping node\n"); + LogError("[snapshot] !!! %s\n", user_error.original); + LogError("[snapshot] deleting snapshot, reverting to validated chain, and stopping node\n"); m_active_chainstate = m_ibd_chainstate.get(); m_snapshot_chainstate->m_disabled = true; @@ -6115,7 +6255,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} { } @@ -6162,14 +6303,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) @@ -6303,7 +6444,7 @@ bool ChainstateManager::ValidatedSnapshotCleanup() fs::path p_old, fs::path p_new, const fs::filesystem_error& err) { - LogPrintf("Error renaming path (%s) -> (%s): %s\n", + LogError("[snapshot] Error renaming path (%s) -> (%s): %s\n", fs::PathToString(p_old), fs::PathToString(p_new), err.what()); GetNotifications().fatalError(strprintf(_( "Rename of '%s' -> '%s' failed. " diff --git a/src/validation.h b/src/validation.h index ea6b6cad7e..f6aeea3faa 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 @@ -37,9 +39,9 @@ #include <memory> #include <optional> #include <set> +#include <span> #include <stdint.h> #include <string> -#include <thread> #include <type_traits> #include <utility> #include <vector> @@ -83,11 +85,6 @@ enum class SynchronizationState { POST_INIT }; -extern GlobalMutex g_best_block_mutex; -extern std::condition_variable g_best_block_cv; -/** Used to notify getblocktemplate RPC of new tips. */ -extern uint256 g_best_block; - /** Documentation for argument 'checklevel'. */ extern const std::vector<std::string> CHECKLEVEL_DOC; @@ -340,10 +337,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 +358,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 */ @@ -384,7 +402,7 @@ bool HasValidProofOfWork(const std::vector<CBlockHeader>& headers, const Consens bool IsBlockMutated(const CBlock& block, bool check_witness_root); /** Return the sum of the claimed work on a given set of headers. No verification of PoW is done. */ -arith_uint256 CalculateClaimedHeadersWork(const std::vector<CBlockHeader>& headers); +arith_uint256 CalculateClaimedHeadersWork(std::span<const CBlockHeader> headers); enum class VerifyDBResult { SUCCESS, @@ -796,7 +814,6 @@ private: friend ChainstateManager; }; - enum class SnapshotCompletionResult { SUCCESS, SKIPPED, @@ -884,14 +901,19 @@ 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 - //! CreateUTXOSnapshot() in rpc/blockchain.cpp. + //! the dumptxoutset RPC. //! 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 +949,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; @@ -934,11 +971,11 @@ public: //! Function to restart active indexes; set dynamically to avoid a circular //! dependency on `base/index.cpp`. - std::function<void()> restart_indexes = std::function<void()>(); + std::function<void()> snapshot_download_completed = std::function<void()>(); const CChainParams& GetParams() const { return m_options.chainparams; } const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); } - bool ShouldCheckBlockIndex() const { return *Assert(m_options.check_block_index); } + bool ShouldCheckBlockIndex() const; const arith_uint256& MinimumChainWork() const { return *Assert(m_options.minimum_chain_work); } const uint256& AssumedValidBlock() const { return *Assert(m_options.assumed_valid_block); } kernel::Notifications& GetNotifications() const { return m_options.notifications; }; @@ -965,11 +1002,12 @@ public: const util::SignalInterrupt& m_interrupt; const Options m_options; - std::thread m_thread_load; //! A single BlockManager instance is shared across each constructed //! 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 +1088,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]] bool 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 @@ -1174,12 +1211,12 @@ public: * May not be called in a * validationinterface callback. * - * @param[in] block The block headers themselves + * @param[in] headers The block headers themselves * @param[in] min_pow_checked True if proof-of-work anti-DoS checks have been done by caller for headers chain * @param[out] state This may be set to an Error state if any error occurred processing them * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers */ - bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlockHeaders(std::span<const CBlockHeader> headers, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main); /** * Sufficiently validate a block for disk storage (and store on disk). diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 813fde109c..da2685d771 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -9,6 +9,7 @@ #include <consensus/validation.h> #include <kernel/chain.h> #include <kernel/mempool_entry.h> +#include <kernel/mempool_removal_reason.h> #include <logging.h> #include <primitives/block.h> #include <primitives/transaction.h> @@ -19,8 +20,6 @@ #include <unordered_map> #include <utility> -std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept; - /** * ValidationSignalsImpl manages a list of shared_ptr<CValidationInterface> callbacks. * @@ -95,7 +94,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() { @@ -167,7 +166,7 @@ void ValidationSignals::SyncWithValidationInterfaceQueue() } while (0) #define LOG_EVENT(fmt, ...) \ - LogPrint(BCLog::VALIDATION, fmt "\n", __VA_ARGS__) + LogDebug(BCLog::VALIDATION, fmt "\n", __VA_ARGS__) void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which @@ -183,6 +182,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/CMakeLists.txt b/src/wallet/CMakeLists.txt new file mode 100644 index 0000000000..121e6e3c83 --- /dev/null +++ b/src/wallet/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# Wallet functionality used by bitcoind and bitcoin-wallet executables. +add_library(bitcoin_wallet STATIC EXCLUDE_FROM_ALL + coincontrol.cpp + coinselection.cpp + context.cpp + crypter.cpp + db.cpp + dump.cpp + external_signer_scriptpubkeyman.cpp + feebumper.cpp + fees.cpp + interfaces.cpp + load.cpp + migrate.cpp + receive.cpp + rpc/addresses.cpp + rpc/backup.cpp + rpc/coins.cpp + rpc/encrypt.cpp + rpc/signmessage.cpp + rpc/spend.cpp + rpc/transactions.cpp + rpc/util.cpp + rpc/wallet.cpp + scriptpubkeyman.cpp + spend.cpp + transaction.cpp + wallet.cpp + walletdb.cpp + walletutil.cpp +) +target_link_libraries(bitcoin_wallet + PRIVATE + core_interface + bitcoin_common + univalue + Boost::headers + $<TARGET_NAME_IF_EXISTS:USDT::headers> +) + +if(NOT USE_SQLITE AND NOT USE_BDB) + message(FATAL_ERROR "Wallet functionality requested but no BDB or SQLite support available.") +endif() +if(USE_SQLITE) + target_sources(bitcoin_wallet PRIVATE sqlite.cpp) + target_link_libraries(bitcoin_wallet + PRIVATE + $<TARGET_NAME_IF_EXISTS:unofficial::sqlite3::sqlite3> + $<TARGET_NAME_IF_EXISTS:SQLite::SQLite3> + ) +endif() +if(USE_BDB) + target_sources(bitcoin_wallet PRIVATE bdb.cpp salvage.cpp) + target_link_libraries(bitcoin_wallet PUBLIC BerkeleyDB::BerkeleyDB) +endif() diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index d82d8d4513..79851dff33 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -211,7 +211,7 @@ BerkeleyEnvironment::BerkeleyEnvironment() : m_use_shared_memory(false) { Reset(); - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::MakeMock\n"); + LogDebug(BCLog::WALLETDB, "BerkeleyEnvironment::MakeMock\n"); dbenv->set_cachesize(1, 0, 1); dbenv->set_lg_bsize(10485760 * 4); @@ -605,7 +605,7 @@ void BerkeleyEnvironment::Flush(bool fShutdown) { const auto start{SteadyClock::now()}; // Flush log data to the actual data file on all files that are not in use - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); + LogDebug(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); if (!fDbEnvInit) return; { @@ -616,22 +616,22 @@ void BerkeleyEnvironment::Flush(bool fShutdown) int nRefCount = db_it.second.get().m_refcount; if (nRefCount < 0) continue; const std::string strFile = fs::PathToString(filename); - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount); + LogDebug(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount); if (nRefCount == 0) { // Move log data to the dat file CloseDb(filename); - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s checkpoint\n", strFile); + LogDebug(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s checkpoint\n", strFile); dbenv->txn_checkpoint(0, 0, 0); - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s detach\n", strFile); + LogDebug(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s detach\n", strFile); if (!fMockDb) dbenv->lsn_reset(strFile.c_str(), 0); - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s closed\n", strFile); + LogDebug(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s closed\n", strFile); nRefCount = -1; } else { no_dbs_accessed = false; } } - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); + LogDebug(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); if (fShutdown) { char** listp; if (no_dbs_accessed) { @@ -660,7 +660,7 @@ bool BerkeleyDatabase::PeriodicFlush() if (m_refcount < 0) return false; const std::string strFile = fs::PathToString(m_filename); - LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile); + LogDebug(BCLog::WALLETDB, "Flushing %s\n", strFile); const auto start{SteadyClock::now()}; // Flush wallet file so it's self contained @@ -668,7 +668,7 @@ bool BerkeleyDatabase::PeriodicFlush() env->CheckpointLSN(strFile); m_refcount = -1; - LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); + LogDebug(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); return true; } 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..cee558088f 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(); @@ -725,10 +740,10 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c log_message += strprintf("%s ", FormatMoney(applicable_groups[i].m_value)); } } - LogPrint(BCLog::SELECTCOINS, "%stotal %s\n", log_message, FormatMoney(nBest)); + LogDebug(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/crypter.cpp b/src/wallet/crypter.cpp index 57a19fb5f2..ffb1d29e16 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -8,10 +8,11 @@ #include <crypto/aes.h> #include <crypto/sha512.h> +#include <type_traits> #include <vector> namespace wallet { -int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const +int CCrypter::BytesToKeySHA512AES(const std::span<const unsigned char> salt, const SecureString& key_data, int count, unsigned char* key, unsigned char* iv) const { // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc // cipher and sha512 message digest. Because sha512's output size (64b) is @@ -24,8 +25,8 @@ int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, cons unsigned char buf[CSHA512::OUTPUT_SIZE]; CSHA512 di; - di.Write((const unsigned char*)strKeyData.data(), strKeyData.size()); - di.Write(chSalt.data(), chSalt.size()); + di.Write(UCharCast(key_data.data()), key_data.size()); + di.Write(salt.data(), salt.size()); di.Finalize(buf); for(int i = 0; i != count - 1; i++) @@ -37,14 +38,16 @@ int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, cons return WALLET_CRYPTO_KEY_SIZE; } -bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) +bool CCrypter::SetKeyFromPassphrase(const SecureString& key_data, const std::span<const unsigned char> salt, const unsigned int rounds, const unsigned int derivation_method) { - if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) + if (rounds < 1 || salt.size() != WALLET_CRYPTO_SALT_SIZE) { return false; + } int i = 0; - if (nDerivationMethod == 0) - i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data()); + if (derivation_method == 0) { + i = BytesToKeySHA512AES(salt, key_data, rounds, vchKey.data(), vchIV.data()); + } if (i != (int)WALLET_CRYPTO_KEY_SIZE) { @@ -57,13 +60,14 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v return true; } -bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV) +bool CCrypter::SetKey(const CKeyingMaterial& new_key, const std::span<const unsigned char> new_iv) { - if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE) + if (new_key.size() != WALLET_CRYPTO_KEY_SIZE || new_iv.size() != WALLET_CRYPTO_IV_SIZE) { return false; + } - memcpy(vchKey.data(), chNewKey.data(), chNewKey.size()); - memcpy(vchIV.data(), chNewIV.data(), chNewIV.size()); + memcpy(vchKey.data(), new_key.data(), new_key.size()); + memcpy(vchIV.data(), new_iv.data(), new_iv.size()); fKeySet = true; return true; @@ -87,21 +91,20 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned return true; } -bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const +bool CCrypter::Decrypt(const std::span<const unsigned char> ciphertext, CKeyingMaterial& plaintext) const { if (!fKeySet) return false; // plaintext will always be equal to or lesser than length of ciphertext - int nLen = vchCiphertext.size(); - - vchPlaintext.resize(nLen); + plaintext.resize(ciphertext.size()); AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true); - nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), vchPlaintext.data()); - if(nLen == 0) + int len = dec.Decrypt(ciphertext.data(), ciphertext.size(), plaintext.data()); + if (len == 0) { return false; - vchPlaintext.resize(nLen); + } + plaintext.resize(len); return true; } @@ -115,26 +118,29 @@ bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vch return cKeyCrypter.Encrypt(vchPlaintext, vchCiphertext); } -bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) +bool DecryptSecret(const CKeyingMaterial& master_key, const std::span<const unsigned char> ciphertext, const uint256& iv, CKeyingMaterial& plaintext) { - CCrypter cKeyCrypter; - std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE); - memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE); - if(!cKeyCrypter.SetKey(vMasterKey, chIV)) + CCrypter key_crypter; + static_assert(WALLET_CRYPTO_IV_SIZE <= std::remove_reference_t<decltype(iv)>::size()); + const std::span iv_prefix{iv.data(), WALLET_CRYPTO_IV_SIZE}; + if (!key_crypter.SetKey(master_key, iv_prefix)) { return false; - return cKeyCrypter.Decrypt(vchCiphertext, vchPlaintext); + } + return key_crypter.Decrypt(ciphertext, plaintext); } -bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key) +bool DecryptKey(const CKeyingMaterial& master_key, const std::span<const unsigned char> crypted_secret, const CPubKey& pub_key, CKey& key) { - CKeyingMaterial vchSecret; - if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) + CKeyingMaterial secret; + if (!DecryptSecret(master_key, crypted_secret, pub_key.GetHash(), secret)) { return false; + } - if (vchSecret.size() != 32) + if (secret.size() != 32) { return false; + } - key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); - return key.VerifyPubKey(vchPubKey); + key.Set(secret.begin(), secret.end(), pub_key.IsCompressed()); + return key.VerifyPubKey(pub_key); } } // namespace wallet diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index b776a9c497..944858fb3f 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -75,13 +75,13 @@ private: std::vector<unsigned char, secure_allocator<unsigned char>> vchIV; bool fKeySet; - int BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const; + int BytesToKeySHA512AES(std::span<const unsigned char> salt, const SecureString& key_data, int count, unsigned char* key, unsigned char* iv) const; public: - bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod); + bool SetKeyFromPassphrase(const SecureString& key_data, std::span<const unsigned char> salt, const unsigned int rounds, const unsigned int derivation_method); bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const; - bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const; - bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV); + bool Decrypt(std::span<const unsigned char> ciphertext, CKeyingMaterial& plaintext) const; + bool SetKey(const CKeyingMaterial& new_key, std::span<const unsigned char> new_iv); void CleanKey() { @@ -104,8 +104,8 @@ public: }; bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext); -bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); -bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key); +bool DecryptSecret(const CKeyingMaterial& master_key, std::span<const unsigned char> ciphertext, const uint256& iv, CKeyingMaterial& plaintext); +bool DecryptKey(const CKeyingMaterial& master_key, std::span<const unsigned char> crypted_secret, const CPubKey& pub_key, CKey& key); } // namespace wallet #endif // BITCOIN_WALLET_CRYPTER_H diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index a5a5f8ec6f..1c007ba949 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -9,6 +9,7 @@ #include <util/fs.h> #include <wallet/db.h> +#include <algorithm> #include <exception> #include <fstream> #include <string> @@ -16,12 +17,12 @@ #include <vector> 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; } +bool operator<(BytePrefix a, Span<const std::byte> b) { return std::ranges::lexicographical_compare(a.prefix, b.subspan(0, std::min(a.prefix.size(), b.size()))); } +bool operator<(Span<const std::byte> a, BytePrefix b) { return std::ranges::lexicographical_compare(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 +39,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/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp index b5703fa54a..32e9941453 100644 --- a/src/wallet/external_signer_scriptpubkeyman.cpp +++ b/src/wallet/external_signer_scriptpubkeyman.cpp @@ -6,6 +6,7 @@ #include <common/args.h> #include <common/system.h> #include <external_signer.h> +#include <node/types.h> #include <wallet/external_signer_scriptpubkeyman.h> #include <iostream> @@ -17,6 +18,8 @@ #include <utility> #include <vector> +using common::PSBTError; + namespace wallet { bool ExternalSignerScriptPubKeyMan::SetupDescriptor(WalletBatch& batch, std::unique_ptr<Descriptor> desc) { @@ -76,7 +79,7 @@ util::Result<void> ExternalSignerScriptPubKeyMan::DisplayAddress(const CTxDestin } // If sign is true, transaction must previously have been filled -TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const +std::optional<PSBTError> ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const { if (!sign) { return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed, finalize); @@ -88,14 +91,14 @@ TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransact // TODO: for multisig wallets, we should only care if all _our_ inputs are signed complete &= PSBTInputSigned(input); } - if (complete) return TransactionError::OK; + if (complete) return {}; std::string strFailReason; if(!GetExternalSigner().SignTransaction(psbt, strFailReason)) { tfm::format(std::cerr, "Failed to sign: %s\n", strFailReason); - return TransactionError::EXTERNAL_SIGNER_FAILED; + return PSBTError::EXTERNAL_SIGNER_FAILED; } if (finalize) FinalizePSBT(psbt); // This won't work in a multisig setup - return TransactionError::OK; + return {}; } } // namespace wallet diff --git a/src/wallet/external_signer_scriptpubkeyman.h b/src/wallet/external_signer_scriptpubkeyman.h index 44286456b6..10d67d2ab4 100644 --- a/src/wallet/external_signer_scriptpubkeyman.h +++ b/src/wallet/external_signer_scriptpubkeyman.h @@ -35,7 +35,7 @@ class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan */ util::Result<void> DisplayAddress(const CTxDestination& dest, const ExternalSigner& signer) const; - TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; + std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; }; } // namespace wallet #endif // BITCOIN_WALLET_EXTERNAL_SIGNER_SCRIPTPUBKEYMAN_H diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 6a8453965b..3184d0f3b0 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -5,6 +5,7 @@ #include <common/system.h> #include <consensus/validation.h> #include <interfaces/chain.h> +#include <node/types.h> #include <policy/fees.h> #include <policy/policy.h> #include <util/moneystr.h> @@ -92,7 +93,7 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CMutableTrans } CAmount new_total_fee = newFeerate.GetFee(maxTxSize) + combined_bump_fee.value(); - CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE)); + CFeeRate incrementalRelayFee = wallet.chain().relayIncrementalFee(); // Min total fee is old fee + relay fee CAmount minTotalFee = old_fee + incrementalRelayFee.GetFee(maxTxSize); @@ -343,8 +344,8 @@ bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) { // so external signers are not asked to sign more than once. bool complete; wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */); - const TransactionError err = wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true /* sign */, false /* bip32derivs */); - if (err != TransactionError::OK) return false; + auto err{wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true /* sign */, false /* bip32derivs */)}; + if (err) return false; complete = FinalizeAndExtractPSBT(psbtx, mtx); return complete; } else { diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 14d22bb54e..cfd09a2e10 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <common/args.h> #include <init.h> diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 0c1cae7253..21e8a0b3bd 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -8,6 +8,7 @@ #include <consensus/amount.h> #include <interfaces/chain.h> #include <interfaces/handler.h> +#include <node/types.h> #include <policy/fees.h> #include <primitives/transaction.h> #include <rpc/server.h> @@ -34,6 +35,7 @@ #include <utility> #include <vector> +using common::PSBTError; using interfaces::Chain; using interfaces::FoundBlock; using interfaces::Handler; @@ -389,7 +391,7 @@ public: } return {}; } - TransactionError fillPSBT(int sighash_type, + std::optional<PSBTError> fillPSBT(int sighash_type, bool sign, bool bip32derivs, size_t* n_signed, @@ -650,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 8b78a670e4..2b5c021cda 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -21,6 +21,8 @@ #include <system_error> +using util::Join; + namespace wallet { bool VerifyWallets(WalletContext& context) { @@ -67,7 +69,7 @@ bool VerifyWallets(WalletContext& context) // Pass write=false because no need to write file and probably // better not to. If unnamed wallet needs to be added next startup // and the setting is empty, this code will just run again. - chain.updateRwSetting("wallet", wallets, /* write= */ false); + chain.overwriteRwSetting("wallet", std::move(wallets), interfaces::SettingsAction::SKIP_WRITE); } } @@ -75,6 +77,11 @@ bool VerifyWallets(WalletContext& context) std::set<fs::path> wallet_paths; for (const auto& wallet : chain.getSettingsList("wallet")) { + if (!wallet.isStr()) { + chain.initError(_("Invalid value detected for '-wallet' or '-nowallet'. " + "'-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets")); + return false; + } const auto& wallet_file = wallet.get_str(); const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(wallet_file)); @@ -108,6 +115,11 @@ bool LoadWallets(WalletContext& context) try { std::set<fs::path> wallet_paths; for (const auto& wallet : chain.getSettingsList("wallet")) { + if (!wallet.isStr()) { + chain.initError(_("Invalid value detected for '-wallet' or '-nowallet'. " + "'-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets")); + return false; + } const auto& name = wallet.get_str(); if (!wallet_paths.insert(fs::PathFromString(name)).second) { continue; @@ -176,7 +188,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.cpp b/src/wallet/migrate.cpp index 09254a76ad..d7d8577374 100644 --- a/src/wallet/migrate.cpp +++ b/src/wallet/migrate.cpp @@ -551,7 +551,7 @@ void BerkeleyRODatabase::Open() // } // Check the last page number - uint32_t expected_last_page = (size / page_size) - 1; + uint32_t expected_last_page{uint32_t((size / page_size) - 1)}; if (outer_meta.last_page != expected_last_page) { throw std::runtime_error("Last page number could not fit in file"); } 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..1c2951deee 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -1,8 +1,8 @@ -// 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. -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <core_io.h> #include <key_io.h> @@ -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 a76ae7196c..4ffc6f1e0d 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <chain.h> #include <clientversion.h> @@ -34,6 +34,7 @@ using interfaces::FoundBlock; +using util::SplitString; namespace wallet { std::string static EncodeDumpString(const std::string &str) { @@ -470,7 +471,7 @@ RPCHelpMan importpubkey() pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, /*have_solving_data=*/true, /*apply_label=*/true, /*timestamp=*/1); - pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*internal=*/false, /*timestamp=*/1); + pwallet->ImportPubKeys({{pubKey.GetID(), false}}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*timestamp=*/1); } if (fRescan) { @@ -909,12 +910,13 @@ 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(); } -static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys) +static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys) { UniValue warnings(UniValue::VARR); @@ -980,7 +982,7 @@ static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CP for (size_t i = 0; i < pubKeys.size(); ++i) { CPubKey pubkey = HexToPubKey(pubKeys[i].get_str()); pubkey_map.emplace(pubkey.GetID(), pubkey); - ordered_pubkeys.push_back(pubkey.GetID()); + ordered_pubkeys.emplace_back(pubkey.GetID(), internal); } for (size_t i = 0; i < keys.size(); ++i) { const auto& str = keys[i].get_str(); @@ -1053,28 +1055,36 @@ static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CP return warnings; } -static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys) +static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys) { UniValue warnings(UniValue::VARR); const std::string& descriptor = data["desc"].get_str(); FlatSigningProvider keys; std::string error; - auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true); - if (!parsed_desc) { + auto parsed_descs = Parse(descriptor, keys, error, /* require_checksum = */ true); + if (parsed_descs.empty()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } - if (parsed_desc->GetOutputType() == OutputType::BECH32M) { + if (parsed_descs.at(0)->GetOutputType() == OutputType::BECH32M) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m descriptors cannot be imported into legacy wallets"); } - have_solving_data = parsed_desc->IsSolvable(); + std::optional<bool> internal; + if (data.exists("internal")) { + if (parsed_descs.size() > 1) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot have multipath descriptor while also specifying \'internal\'"); + } + internal = data["internal"].get_bool(); + } + + have_solving_data = parsed_descs.at(0)->IsSolvable(); const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false; int64_t range_start = 0, range_end = 0; - if (!parsed_desc->IsRange() && data.exists("range")) { + if (!parsed_descs.at(0)->IsRange() && data.exists("range")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor"); - } else if (parsed_desc->IsRange()) { + } else if (parsed_descs.at(0)->IsRange()) { if (!data.exists("range")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range"); } @@ -1083,25 +1093,34 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); - // Expand all descriptors to get public keys and scripts, and private keys if available. - for (int i = range_start; i <= range_end; ++i) { - FlatSigningProvider out_keys; - std::vector<CScript> scripts_temp; - parsed_desc->Expand(i, keys, scripts_temp, out_keys); - std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end())); - for (const auto& key_pair : out_keys.pubkeys) { - ordered_pubkeys.push_back(key_pair.first); - } + for (size_t j = 0; j < parsed_descs.size(); ++j) { + const auto& parsed_desc = parsed_descs.at(j); + bool desc_internal = internal.has_value() && internal.value(); + if (parsed_descs.size() == 2) { + desc_internal = j == 1; + } else if (parsed_descs.size() > 2) { + CHECK_NONFATAL(!desc_internal); + } + // Expand all descriptors to get public keys and scripts, and private keys if available. + for (int i = range_start; i <= range_end; ++i) { + FlatSigningProvider out_keys; + std::vector<CScript> scripts_temp; + parsed_desc->Expand(i, keys, scripts_temp, out_keys); + std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end())); + for (const auto& key_pair : out_keys.pubkeys) { + ordered_pubkeys.emplace_back(key_pair.first, desc_internal); + } - for (const auto& x : out_keys.scripts) { - import_data.import_scripts.emplace(x.second); - } + for (const auto& x : out_keys.scripts) { + import_data.import_scripts.emplace(x.second); + } - parsed_desc->ExpandPrivate(i, keys, out_keys); + parsed_desc->ExpandPrivate(i, keys, out_keys); - std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end())); - std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end())); - import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end()); + std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end())); + std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end())); + import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end()); + } } for (size_t i = 0; i < priv_keys.size(); ++i) { @@ -1165,7 +1184,7 @@ static UniValue ProcessImport(CWallet& wallet, const UniValue& data, const int64 std::map<CKeyID, CPubKey> pubkey_map; std::map<CKeyID, CKey> privkey_map; std::set<CScript> script_pub_keys; - std::vector<CKeyID> ordered_pubkeys; + std::vector<std::pair<CKeyID, bool>> ordered_pubkeys; bool have_solving_data; if (data.exists("scriptPubKey") && data.exists("desc")) { @@ -1198,7 +1217,7 @@ static UniValue ProcessImport(CWallet& wallet, const UniValue& data, const int64 if (!wallet.ImportPrivKeys(privkey_map, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); } - if (!wallet.ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) { + if (!wallet.ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } if (!wallet.ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) { @@ -1445,22 +1464,28 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c const std::string& descriptor = data["desc"].get_str(); const bool active = data.exists("active") ? data["active"].get_bool() : false; - const bool internal = data.exists("internal") ? data["internal"].get_bool() : false; const std::string label{LabelFromValue(data["label"])}; // Parse descriptor string FlatSigningProvider keys; std::string error; - auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true); - if (!parsed_desc) { + auto parsed_descs = Parse(descriptor, keys, error, /* require_checksum = */ true); + if (parsed_descs.empty()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } + std::optional<bool> internal; + if (data.exists("internal")) { + if (parsed_descs.size() > 1) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot have multipath descriptor while also specifying \'internal\'"); + } + internal = data["internal"].get_bool(); + } // Range check int64_t range_start = 0, range_end = 1, next_index = 0; - if (!parsed_desc->IsRange() && data.exists("range")) { + if (!parsed_descs.at(0)->IsRange() && data.exists("range")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor"); - } else if (parsed_desc->IsRange()) { + } else if (parsed_descs.at(0)->IsRange()) { if (data.exists("range")) { auto range = ParseDescriptorRange(data["range"]); range_start = range.first; @@ -1482,10 +1507,15 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c } // Active descriptors must be ranged - if (active && !parsed_desc->IsRange()) { + if (active && !parsed_descs.at(0)->IsRange()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Active descriptors must be ranged"); } + // Multipath descriptors should not have a label + if (parsed_descs.size() > 1 && data.exists("label")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Multipath descriptors should not have a label"); + } + // Ranged descriptors should not have a label if (data.exists("range") && data.exists("label")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptors should not have a label"); @@ -1497,7 +1527,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c } // Combo descriptor check - if (active && !parsed_desc->IsSingleType()) { + if (active && !parsed_descs.at(0)->IsSingleType()) { throw JSONRPCError(RPC_WALLET_ERROR, "Combo descriptors cannot be set to active"); } @@ -1506,61 +1536,70 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled"); } - // Need to ExpandPrivate to check if private keys are available for all pubkeys - FlatSigningProvider expand_keys; - std::vector<CScript> scripts; - if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Cannot expand descriptor. Probably because of hardened derivations without private keys provided"); - } - parsed_desc->ExpandPrivate(0, keys, expand_keys); - - // Check if all private keys are provided - bool have_all_privkeys = !expand_keys.keys.empty(); - for (const auto& entry : expand_keys.origins) { - const CKeyID& key_id = entry.first; - CKey key; - if (!expand_keys.GetKey(key_id, key)) { - have_all_privkeys = false; - break; + for (size_t j = 0; j < parsed_descs.size(); ++j) { + auto parsed_desc = std::move(parsed_descs[j]); + bool desc_internal = internal.has_value() && internal.value(); + if (parsed_descs.size() == 2) { + desc_internal = j == 1; + } else if (parsed_descs.size() > 2) { + CHECK_NONFATAL(!desc_internal); + } + // Need to ExpandPrivate to check if private keys are available for all pubkeys + FlatSigningProvider expand_keys; + std::vector<CScript> scripts; + if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot expand descriptor. Probably because of hardened derivations without private keys provided"); + } + parsed_desc->ExpandPrivate(0, keys, expand_keys); + + // Check if all private keys are provided + bool have_all_privkeys = !expand_keys.keys.empty(); + for (const auto& entry : expand_keys.origins) { + const CKeyID& key_id = entry.first; + CKey key; + if (!expand_keys.GetKey(key_id, key)) { + have_all_privkeys = false; + break; + } } - } - // If private keys are enabled, check some things. - if (!wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - if (keys.keys.empty()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import descriptor without private keys to a wallet with private keys enabled"); - } - if (!have_all_privkeys) { - warnings.push_back("Not all private keys provided. Some wallet functionality may return unexpected errors"); - } - } + // If private keys are enabled, check some things. + if (!wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (keys.keys.empty()) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import descriptor without private keys to a wallet with private keys enabled"); + } + if (!have_all_privkeys) { + warnings.push_back("Not all private keys provided. Some wallet functionality may return unexpected errors"); + } + } - WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index); + WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index); - // Check if the wallet already contains the descriptor - auto existing_spk_manager = wallet.GetDescriptorScriptPubKeyMan(w_desc); - if (existing_spk_manager) { - if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, error); + // Check if the wallet already contains the descriptor + auto existing_spk_manager = wallet.GetDescriptorScriptPubKeyMan(w_desc); + if (existing_spk_manager) { + if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, error); + } } - } - // Add descriptor to the wallet - auto spk_manager = wallet.AddWalletDescriptor(w_desc, keys, label, internal); - if (spk_manager == nullptr) { - throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor)); - } + // Add descriptor to the wallet + auto spk_manager = wallet.AddWalletDescriptor(w_desc, keys, label, desc_internal); + if (spk_manager == nullptr) { + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor)); + } - // Set descriptor as active if necessary - if (active) { - if (!w_desc.descriptor->GetOutputType()) { - warnings.push_back("Unknown output type, cannot set descriptor to active."); + // Set descriptor as active if necessary + if (active) { + if (!w_desc.descriptor->GetOutputType()) { + warnings.push_back("Unknown output type, cannot set descriptor to active."); + } else { + wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), desc_internal); + } } else { - wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal); - } - } else { - if (w_desc.descriptor->GetOutputType()) { - wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal); + if (w_desc.descriptor->GetOutputType()) { + wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), desc_internal); + } } } @@ -1577,6 +1616,7 @@ RPCHelpMan importdescriptors() { return RPCHelpMan{"importdescriptors", "\nImport descriptors. This will trigger a rescan of the blockchain based on the earliest timestamp of all descriptors being imported. Requires a new wallet backup.\n" + "When importing descriptors with multipath key expressions, if the multipath specifier contains exactly two elements, the descriptor produced from the second elements will be imported as an internal descriptor.\n" "\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n" "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n" "The rescan is significantly faster if block filters are available (using startup option \"-blockfilterindex=1\").\n", 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/signmessage.cpp b/src/wallet/rpc/signmessage.cpp index c9fb693482..edf93ecab7 100644 --- a/src/wallet/rpc/signmessage.cpp +++ b/src/wallet/rpc/signmessage.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 <common/signmessage.h> #include <key_io.h> #include <rpc/util.h> -#include <util/message.h> #include <wallet/rpc/util.h> #include <wallet/wallet.h> diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 169f72c406..bea9b2eec1 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -2,14 +2,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/messages.h> #include <consensus/validation.h> #include <core_io.h> #include <key_io.h> +#include <node/types.h> #include <policy/policy.h> #include <rpc/rawtransaction_util.h> #include <rpc/util.h> #include <script/script.h> -#include <util/fees.h> #include <util/rbf.h> #include <util/translation.h> #include <util/vector.h> @@ -22,6 +23,12 @@ #include <univalue.h> +using common::FeeModeFromString; +using common::FeeModesDetail; +using common::InvalidEstimateModeErrorMessage; +using common::StringForFeeReason; +using common::TransactionErrorString; +using node::TransactionError; namespace wallet { std::vector<CRecipient> CreateRecipients(const std::vector<std::pair<CTxDestination, CAmount>>& outputs, const std::set<int>& subtract_fee_outputs) @@ -97,9 +104,9 @@ static UniValue FinishTransaction(const std::shared_ptr<CWallet> pwallet, const // so external signers are not asked to sign more than once. bool complete; pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true); - const TransactionError err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/true, /*bip32derivs=*/false)}; - if (err != TransactionError::OK) { - throw JSONRPCTransactionError(err); + const auto err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/true, /*bip32derivs=*/false)}; + if (err) { + throw JSONRPCPSBTError(*err); } CMutableTransaction mtx; @@ -238,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."}, @@ -342,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."}, }, @@ -456,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" @@ -535,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); @@ -653,11 +661,13 @@ CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransact FlatSigningProvider desc_out; std::string error; std::vector<CScript> scripts_temp; - std::unique_ptr<Descriptor> desc = Parse(desc_str, desc_out, error, true); - if (!desc) { + auto descs = Parse(desc_str, desc_out, error, true); + if (descs.empty()) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unable to parse descriptor '%s': %s", desc_str, error)); } - desc->Expand(0, desc_out, scripts_temp, desc_out); + for (auto& desc : descs) { + desc->Expand(0, desc_out, scripts_temp, desc_out); + } coinControl.m_external_provider.Merge(std::move(desc_out)); } } @@ -694,6 +704,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"); @@ -779,6 +793,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{ @@ -868,7 +884,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"}, @@ -1004,7 +1020,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" @@ -1153,8 +1169,8 @@ static RPCHelpMan bumpfee_helper(std::string method_name) } else { PartiallySignedTransaction psbtx(mtx); bool complete = false; - const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true); - CHECK_NONFATAL(err == TransactionError::OK); + const auto err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true)}; + CHECK_NONFATAL(!err); CHECK_NONFATAL(!complete); DataStream ssTx{}; ssTx << psbtx; @@ -1191,7 +1207,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>>( @@ -1233,6 +1249,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"}}, @@ -1280,6 +1298,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 @@ -1312,7 +1333,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, "", @@ -1610,9 +1631,9 @@ RPCHelpMan walletprocesspsbt() if (sign) EnsureWalletIsUnlocked(*pwallet); - const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs, nullptr, finalize)}; - if (err != TransactionError::OK) { - throw JSONRPCTransactionError(err); + const auto err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs, nullptr, finalize)}; + if (err) { + throw JSONRPCPSBTError(*err); } UniValue result(UniValue::VOBJ); @@ -1690,6 +1711,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"}}, @@ -1744,9 +1767,9 @@ RPCHelpMan walletcreatefundedpsbt() // Fill transaction with out data but don't sign bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool(); bool complete = true; - const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, /*sign=*/false, /*bip32derivs=*/bip32derivs)}; - if (err != TransactionError::OK) { - throw JSONRPCTransactionError(err); + const auto err{wallet.FillPSBT(psbtx, complete, 1, /*sign=*/false, /*bip32derivs=*/bip32derivs)}; + if (err) { + throw JSONRPCPSBTError(*err); } // Serialize the PSBT diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 5abc983701..61cf36a6c1 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -415,13 +415,13 @@ static std::vector<RPCResult> TransactionDescriptionString() {RPCResult::Type::NUM_TIME, "blocktime", /*optional=*/true, "The block time expressed in " + UNIX_EPOCH_TIME + "."}, {RPCResult::Type::STR_HEX, "txid", "The transaction id."}, {RPCResult::Type::STR_HEX, "wtxid", "The hash of serialized transaction, including witness data."}, - {RPCResult::Type::ARR, "walletconflicts", "Conflicting transaction ids.", + {RPCResult::Type::ARR, "walletconflicts", "Confirmed transactions that have been detected by the wallet to conflict with this transaction.", { {RPCResult::Type::STR_HEX, "txid", "The transaction id."}, }}, {RPCResult::Type::STR_HEX, "replaced_by_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx was replaced."}, {RPCResult::Type::STR_HEX, "replaces_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx replaces another."}, - {RPCResult::Type::ARR, "mempoolconflicts", "Transactions that directly conflict with either this transaction or an ancestor transaction", + {RPCResult::Type::ARR, "mempoolconflicts", "Transactions in the mempool that directly conflict with either this transaction or an ancestor transaction", { {RPCResult::Type::STR_HEX, "txid", "The transaction id."}, }}, @@ -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/util.cpp b/src/wallet/rpc/util.cpp index eb23c4555b..ec3b7c1085 100644 --- a/src/wallet/rpc/util.cpp +++ b/src/wallet/rpc/util.cpp @@ -91,7 +91,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)"); } throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED, - "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path)."); + "Multiple wallets are loaded. Please select which wallet to use by requesting the RPC through the /wallet/<walletname> URI path."); } void EnsureWalletIsUnlocked(const CWallet& wallet) @@ -179,7 +179,7 @@ void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& st } } -void AppendLastProcessedBlock(UniValue& entry, const CWallet& wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) +void AppendLastProcessedBlock(UniValue& entry, const CWallet& wallet) { AssertLockHeld(wallet.cs_wallet); UniValue lastprocessedblock{UniValue::VOBJ}; diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 8c218ad766..5140ac8c05 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <core_io.h> #include <key_io.h> @@ -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 b42275fe4b..46ec5dc1ac 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -5,6 +5,7 @@ #include <hash.h> #include <key_io.h> #include <logging.h> +#include <node/types.h> #include <outputtype.h> #include <script/descriptor.h> #include <script/script.h> @@ -20,6 +21,9 @@ #include <optional> +using common::PSBTError; +using util::ToString; + namespace wallet { //! Value for the first BIP 32 hardened derivation. Can be used as a bit mask and as a value. See BIP 32 for more details. const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; @@ -80,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(); @@ -98,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; @@ -111,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(); @@ -213,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: @@ -227,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); @@ -581,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); } @@ -627,7 +632,7 @@ SigningResult LegacyScriptPubKeyMan::SignMessage(const std::string& message, con return SigningResult::SIGNING_FAILED; } -TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const +std::optional<PSBTError> LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const { if (n_signed) { *n_signed = 0; @@ -642,13 +647,13 @@ TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psb // Get the Sighash type if (sign && input.sighash_type != std::nullopt && *input.sighash_type != sighash_type) { - return TransactionError::SIGHASH_MISMATCH; + return PSBTError::SIGHASH_MISMATCH; } // Check non_witness_utxo has specified prevout if (input.non_witness_utxo) { if (txin.prevout.n >= input.non_witness_utxo->vout.size()) { - return TransactionError::MISSING_INPUTS; + return PSBTError::MISSING_INPUTS; } } else if (input.witness_utxo.IsNull()) { // There's no UTXO so we can just skip this now @@ -670,7 +675,7 @@ TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psb UpdatePSBTOutput(HidingSigningProvider(this, true, !bip32derivs), psbtx, i); } - return TransactionError::OK; + return {}; } std::unique_ptr<CKeyMetadata> LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const @@ -717,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); } @@ -769,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 @@ -784,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) @@ -823,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) { @@ -833,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()); @@ -861,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()); @@ -901,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); @@ -950,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; @@ -971,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()) { @@ -987,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()) { @@ -1006,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; { @@ -1026,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); @@ -1037,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()) { @@ -1156,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) { @@ -1619,13 +1642,13 @@ bool LegacyScriptPubKeyMan::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey return true; } -bool LegacyScriptPubKeyMan::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) +bool LegacyScriptPubKeyMan::ImportPubKeys(const std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const int64_t timestamp) { WalletBatch batch(m_storage.GetDatabase()); for (const auto& entry : key_origins) { AddKeyOriginWithDB(batch, entry.second.first, entry.second.second); } - for (const CKeyID& id : ordered_pubkeys) { + for (const auto& [id, internal] : ordered_pubkeys) { auto entry = pubkey_map.find(id); if (entry == pubkey_map.end()) { continue; @@ -1677,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; @@ -1735,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; @@ -1745,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()) { @@ -1808,11 +1831,12 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor() std::string desc_str = "combo(" + origin_str + HexStr(key.GetPubKey()) + ")"; FlatSigningProvider keys; std::string error; - std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false); - WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); + std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, error, false); + CHECK_NONFATAL(descs.size() == 1); // It shouldn't be possible to have an invalid or multipath descriptor + WalletDescriptor w_desc(std::move(descs.at(0)), 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(); @@ -1852,12 +1876,13 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor() std::string desc_str = "combo(" + xpub + "/0h/" + ToString(i) + "h/*h)"; FlatSigningProvider keys; std::string error; - std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false); + std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, error, false); + CHECK_NONFATAL(descs.size() == 1); // It shouldn't be possible to have an invalid or multipath descriptor uint32_t chain_counter = std::max((i == 1 ? chain.nInternalChainCounter : chain.nExternalChainCounter), (uint32_t)0); - WalletDescriptor w_desc(std::move(desc), 0, 0, chain_counter, 0); + WalletDescriptor w_desc(std::move(descs.at(0)), 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(); @@ -1919,7 +1944,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)) { @@ -1997,7 +2022,7 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor() return out; } -bool LegacyScriptPubKeyMan::DeleteRecords() +bool LegacyDataSPKM::DeleteRecords() { LOCK(cs_KeyStore); WalletBatch batch(m_storage.GetDatabase()); @@ -2485,7 +2510,7 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, return SigningResult::OK; } -TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const +std::optional<PSBTError> DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const { if (n_signed) { *n_signed = 0; @@ -2500,7 +2525,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& // Get the Sighash type if (sign && input.sighash_type != std::nullopt && *input.sighash_type != sighash_type) { - return TransactionError::SIGHASH_MISMATCH; + return PSBTError::SIGHASH_MISMATCH; } // Get the scriptPubKey to know which SigningProvider to use @@ -2509,7 +2534,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& script = input.witness_utxo.scriptPubKey; } else if (input.non_witness_utxo) { if (txin.prevout.n >= input.non_witness_utxo->vout.size()) { - return TransactionError::MISSING_INPUTS; + return PSBTError::MISSING_INPUTS; } script = input.non_witness_utxo->vout[txin.prevout.n].scriptPubKey; } else { @@ -2580,7 +2605,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& UpdatePSBTOutput(HidingSigningProvider(keys.get(), /*hide_secret=*/true, /*hide_origin=*/!bip32derivs), psbtx, i); } - return TransactionError::OK; + return {}; } std::unique_ptr<CKeyMetadata> DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 2c1ab8d44a..cf7b7eaf31 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -6,13 +6,15 @@ #define BITCOIN_WALLET_SCRIPTPUBKEYMAN_H #include <addresstype.h> +#include <common/messages.h> +#include <common/signmessage.h> +#include <common/types.h> #include <logging.h> +#include <node/types.h> #include <psbt.h> #include <script/descriptor.h> #include <script/script.h> #include <script/signingprovider.h> -#include <util/error.h> -#include <util/message.h> #include <util/result.h> #include <util/time.h> #include <wallet/crypter.h> @@ -176,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; } @@ -243,7 +245,7 @@ public: /** Sign a message with the given script */ virtual SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; }; /** Adds script and derivation path information to a PSBT, and optionally signs it. */ - virtual TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const { return TransactionError::INVALID_PSBT; } + virtual std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const { return common::PSBTError::UNSUPPORTED; } virtual uint256 GetID() const { return uint256(); } @@ -252,9 +254,9 @@ public: /** Prepends the wallet name in logging output to ease debugging in multi-wallet use cases */ template <typename... Params> - void WalletLogPrintf(const char* fmt, Params... parameters) const + void WalletLogPrintf(util::ConstevalFormatString<sizeof...(Params)> wallet_fmt, const Params&... params) const { - LogPrintf(("%s " + std::string{fmt}).c_str(), m_storage.GetDisplayName(), parameters...); + LogInfo("%s %s", m_storage.GetDisplayName(), tfm::format(wallet_fmt, params...)); }; /** Watch-only address added */ @@ -276,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 @@ -313,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); @@ -328,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; @@ -376,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; @@ -415,74 +485,41 @@ 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; SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override; - TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; + std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; 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); bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); - bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); + bool ImportPubKeys(const std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool ImportScriptPubKeys(const std::set<CScript>& script_pub_keys, const bool have_solving_data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); /* Returns true if the wallet can generate new keys */ @@ -525,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); } @@ -651,7 +675,7 @@ public: bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override; SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override; - TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; + std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; uint256 GetID() const override; diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 2322471402..aceed24a86 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -4,10 +4,12 @@ #include <algorithm> #include <common/args.h> +#include <common/messages.h> #include <common/system.h> #include <consensus/amount.h> #include <consensus/validation.h> #include <interfaces/chain.h> +#include <node/types.h> #include <numeric> #include <policy/policy.h> #include <primitives/transaction.h> @@ -15,7 +17,6 @@ #include <script/signingprovider.h> #include <script/solver.h> #include <util/check.h> -#include <util/fees.h> #include <util/moneystr.h> #include <util/rbf.h> #include <util/trace.h> @@ -29,7 +30,10 @@ #include <cmath> +using common::StringForFeeReason; +using common::TransactionErrorString; using interfaces::FoundBlock; +using node::TransactionError; namespace wallet { static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100}; @@ -132,7 +136,7 @@ static std::optional<int64_t> GetSignedTxinWeight(const CWallet* wallet, const C // txouts needs to be in the order of tx.vin TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control) { - // nVersion + nLockTime + input count + output count + // version + nLockTime + input count + output count int64_t weight = (4 + 4 + GetSizeOfCompactSize(tx.vin.size()) + GetSizeOfCompactSize(tx.vout.size())) * WITNESS_SCALE_FACTOR; // Whether any input spends a witness program. Necessary to run before the next loop over the // inputs in order to accurately compute the compactSize length for the witness data per input. @@ -222,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); } } @@ -256,7 +260,7 @@ static OutputType GetOutputType(TxoutType type, bool is_from_p2sh) // Fetch and validate the coin control selected inputs. // Coins could be internal (from the wallet) or external. util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const CCoinControl& coin_control, - const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) + const CoinSelectionParams& coin_selection_params) { PreSelectedInputs result; const bool can_grind_r = wallet.CanGrindR(); @@ -691,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 { @@ -718,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)); @@ -795,6 +808,13 @@ util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& av op_selection_result->RecalculateWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee); + + // Verify we haven't exceeded the maximum allowed weight + 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")}; + } } return op_selection_result; } @@ -972,6 +992,16 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng } } +size_t GetSerializeSizeForRecipient(const CRecipient& recipient) +{ + return ::GetSerializeSize(CTxOut(recipient.nAmount, GetScriptForDestination(recipient.dest))); +} + +bool IsDust(const CRecipient& recipient, const CFeeRate& dustRelayFee) +{ + return ::IsDust(CTxOut(recipient.nAmount, GetScriptForDestination(recipient.dest)), dustRelayFee); +} + static util::Result<CreatedTransactionResult> CreateTransactionInternal( CWallet& wallet, const std::vector<CRecipient>& vecSend, @@ -985,21 +1015,33 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( CMutableTransaction txNew; // The resulting transaction that we make if (coin_control.m_version) { - txNew.nVersion = coin_control.m_version.value(); + txNew.version = coin_control.m_version.value(); } 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) + coin_selection_params.tx_noinputs_size = 10 + GetSizeOfCompactSize(vecSend.size()); // bytes for output count CAmount recipients_sum = 0; const OutputType change_type = wallet.TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : wallet.m_default_change_type, vecSend); ReserveDestination reservedest(&wallet, change_type); unsigned int outputs_to_subtract_fee_from = 0; // The number of outputs which we are subtracting the fee from for (const auto& recipient : vecSend) { + if (IsDust(recipient, wallet.chain().relayDustFee())) { + return util::Error{_("Transaction amount too small")}; + } + + // Include the fee cost for outputs. + coin_selection_params.tx_noinputs_size += GetSerializeSizeForRecipient(recipient); recipients_sum += recipient.nAmount; if (recipient.fSubtractFeeFromAmount) { @@ -1048,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 @@ -1084,23 +1126,6 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( const auto change_spend_fee = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size); coin_selection_params.min_viable_change = std::max(change_spend_fee + 1, dust); - // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size) - coin_selection_params.tx_noinputs_size = 10 + GetSizeOfCompactSize(vecSend.size()); // bytes for output count - - // vouts to the payees - for (const auto& recipient : vecSend) - { - CTxOut txout(recipient.nAmount, GetScriptForDestination(recipient.dest)); - - // Include the fee cost for outputs. - coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout); - - if (IsDust(txout, wallet.chain().relayDustFee())) { - return util::Error{_("Transaction amount too small")}; - } - txNew.vout.push_back(txout); - } - // Include the fees for things that aren't inputs, excluding the change output const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.m_subtract_fee_outputs ? 0 : coin_selection_params.tx_noinputs_size); CAmount selection_target = recipients_sum + not_input_fees; @@ -1141,6 +1166,12 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( result.GetWaste(), result.GetSelectedValue()); + // vouts to the payees + txNew.vout.reserve(vecSend.size() + 1); // + 1 because of possible later insert + for (const auto& recipient : vecSend) + { + txNew.vout.emplace_back(recipient.nAmount, GetScriptForDestination(recipient.dest)); + } const CAmount change_amount = result.GetChange(coin_selection_params.min_viable_change, coin_selection_params.m_change_fee); if (change_amount > 0) { CTxOut newTxOut(change_amount, scriptChange); @@ -1187,6 +1218,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( // behavior." bool use_anti_fee_sniping = true; const uint32_t default_sequence{coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : CTxIn::MAX_SEQUENCE_NONFINAL}; + txNew.vin.reserve(selected_coins.size()); for (const auto& coin : selected_coins) { std::optional<uint32_t> sequence = coin_control.GetSequence(coin->outpoint); if (sequence) { @@ -1394,7 +1426,7 @@ util::Result<CreatedTransactionResult> FundTransaction(CWallet& wallet, const CM coinControl.m_locktime = tx.nLockTime; // Set the user desired version - coinControl.m_version = tx.nVersion; + coinControl.m_version = tx.version; // Acquire the locks to prevent races to the new locked unspents between the // CreateTransaction call and LockCoin calls (when lockUnspents is true). diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 5e3a8179a2..ab082327de 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <wallet/sqlite.h> @@ -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/CMakeLists.txt b/src/wallet/test/CMakeLists.txt new file mode 100644 index 0000000000..7332674242 --- /dev/null +++ b/src/wallet/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +# Do not use generator expressions in test sources because the +# SOURCES property is processed to gather test suite macros. +target_sources(test_bitcoin + PRIVATE + init_test_fixture.cpp + wallet_test_fixture.cpp + coinselector_tests.cpp + feebumper_tests.cpp + group_outputs_tests.cpp + init_tests.cpp + ismine_tests.cpp + psbt_wallet_tests.cpp + rpc_util_tests.cpp + scriptpubkeyman_tests.cpp + spend_tests.cpp + wallet_crypto_tests.cpp + wallet_tests.cpp + wallet_transaction_tests.cpp + walletdb_tests.cpp + walletload_tests.cpp +) +if(USE_BDB) + target_sources(test_bitcoin + PRIVATE + db_tests.cpp + ) +endif() +target_link_libraries(test_bitcoin bitcoin_wallet) 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/db_tests.cpp b/src/wallet/test/db_tests.cpp index 2fac356263..ea32199497 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <boost/test/unit_test.hpp> @@ -28,7 +28,7 @@ inline std::ostream& operator<<(std::ostream& os, const std::pair<const Serializ { Span key{kv.first}, value{kv.second}; os << "(\"" << std::string_view{reinterpret_cast<const char*>(key.data()), key.size()} << "\", \"" - << std::string_view{reinterpret_cast<const char*>(key.data()), key.size()} << "\")"; + << std::string_view{reinterpret_cast<const char*>(value.data()), value.size()} << "\")"; return os; } diff --git a/src/wallet/test/fuzz/CMakeLists.txt b/src/wallet/test/fuzz/CMakeLists.txt new file mode 100644 index 0000000000..c30671db48 --- /dev/null +++ b/src/wallet/test/fuzz/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +target_sources(fuzz + PRIVATE + coincontrol.cpp + coinselection.cpp + crypter.cpp + fees.cpp + $<$<BOOL:${USE_SQLITE}>:${CMAKE_CURRENT_LIST_DIR}/notifications.cpp> + parse_iso8601.cpp + $<$<BOOL:${USE_SQLITE}>:${CMAKE_CURRENT_LIST_DIR}/scriptpubkeyman.cpp> + wallet_bdb_parser.cpp +) +target_link_libraries(fuzz bitcoin_wallet) diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp index 644a8dd7ad..31fa00c0a2 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); } @@ -252,33 +252,38 @@ FUZZ_TARGET(coinselection) GroupCoins(fuzzed_data_provider, utxo_pool, coin_params, /*positive_only=*/false, group_all); for (const OutputGroup& group : group_all) { - const CoinEligibilityFilter filter(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + const CoinEligibilityFilter filter{fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()}; (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..7869f5f39c 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 rounds since it is otherwise uselessly expensive and causes a timeout when fuzzing. + crypt.SetKeyFromPassphrase(/*key_data=*/secure_string, + /*salt=*/ConsumeFixedLengthByteVector(fuzzed_data_provider, WALLET_CRYPTO_SALT_SIZE), + /*rounds=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 25000), + /*derivation_method=*/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/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp index 792079e6c6..a7015f6685 100644 --- a/src/wallet/test/fuzz/notifications.cpp +++ b/src/wallet/test/fuzz/notifications.cpp @@ -68,7 +68,7 @@ void ImportDescriptors(CWallet& wallet, const std::string& seed_insecure) FlatSigningProvider keys; std::string error; - auto parsed_desc = Parse(descriptor, keys, error, /*require_checksum=*/false); + auto parsed_desc = std::move(Parse(descriptor, keys, error, /*require_checksum=*/false).at(0)); assert(parsed_desc); assert(error.empty()); assert(parsed_desc->IsRange()); diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp index 835470aeae..091d42f6cf 100644 --- a/src/wallet/test/fuzz/scriptpubkeyman.cpp +++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp @@ -69,10 +69,10 @@ static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWal FlatSigningProvider keys; std::string error; - std::unique_ptr<Descriptor> parsed_desc{Parse(desc_str.value(), keys, error, false)}; - if (!parsed_desc) return std::nullopt; + std::vector<std::unique_ptr<Descriptor>> parsed_descs = Parse(desc_str.value(), keys, error, false); + if (parsed_descs.empty()) return std::nullopt; - WalletDescriptor w_desc{std::move(parsed_desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1}; + WalletDescriptor w_desc{std::move(parsed_descs.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1}; return std::make_pair(w_desc, keys); } @@ -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()) { @@ -203,11 +186,16 @@ FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm) auto psbt{*opt_psbt}; const PrecomputedTransactionData txdata{PrecomputePSBTData(psbt)}; const int sighash_type{fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 150)}; - (void)spk_manager->FillPSBT(psbt, txdata, sighash_type, fuzzed_data_provider.ConsumeBool(), fuzzed_data_provider.ConsumeBool(), nullptr, fuzzed_data_provider.ConsumeBool()); + auto sign = fuzzed_data_provider.ConsumeBool(); + auto bip32derivs = fuzzed_data_provider.ConsumeBool(); + auto finalize = fuzzed_data_provider.ConsumeBool(); + (void)spk_manager->FillPSBT(psbt, txdata, sighash_type, sign, bip32derivs, nullptr, finalize); } ); } + 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/fuzz/wallet_bdb_parser.cpp b/src/wallet/test/fuzz/wallet_bdb_parser.cpp index 5216e09769..6482b65d06 100644 --- a/src/wallet/test/fuzz/wallet_bdb_parser.cpp +++ b/src/wallet/test/fuzz/wallet_bdb_parser.cpp @@ -1,8 +1,8 @@ -// Copyright (c) 2023 The Bitcoin Core developers +// Copyright (c) 2023-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 <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -18,6 +18,13 @@ #include <fstream> #include <iostream> +// There is an inconsistency in BDB on Windows. +// See: https://github.com/bitcoin/bitcoin/pull/26606#issuecomment-2322763212 +#undef USE_BDB_NON_MSVC +#if defined(USE_BDB) && !defined(_MSC_VER) +#define USE_BDB_NON_MSVC +#endif + using wallet::DatabaseOptions; using wallet::DatabaseStatus; @@ -50,7 +57,7 @@ FUZZ_TARGET(wallet_bdb_parser, .init = initialize_wallet_bdb_parser) } g_setup->m_args.ForceSetArg("-dumpfile", fs::PathToString(bdb_ro_dumpfile)); -#ifdef USE_BDB +#ifdef USE_BDB_NON_MSVC bool bdb_ro_err = false; bool bdb_ro_strict_err = false; #endif @@ -58,11 +65,12 @@ FUZZ_TARGET(wallet_bdb_parser, .init = initialize_wallet_bdb_parser) if (db) { assert(DumpWallet(g_setup->m_args, *db, error)); } else { -#ifdef USE_BDB +#ifdef USE_BDB_NON_MSVC bdb_ro_err = true; #endif if (error.original.starts_with("AutoFile::ignore: end of file") || error.original.starts_with("AutoFile::read: end of file") || + error.original.starts_with("AutoFile::seek: ") || error.original == "Not a BDB file" || error.original == "Unexpected page type, should be 9 (BTree Metadata)" || error.original == "Unexpected database flags, should only be 0x20 (subdatabases)" || @@ -89,7 +97,7 @@ FUZZ_TARGET(wallet_bdb_parser, .init = initialize_wallet_bdb_parser) error.original == "Subdatabase has an unexpected name" || error.original == "Unsupported BDB data file version number" || error.original == "BDB builtin encryption is not supported") { -#ifdef USE_BDB +#ifdef USE_BDB_NON_MSVC bdb_ro_strict_err = true; #endif } else { @@ -97,7 +105,7 @@ FUZZ_TARGET(wallet_bdb_parser, .init = initialize_wallet_bdb_parser) } } -#ifdef USE_BDB +#ifdef USE_BDB_NON_MSVC // Try opening with BDB fs::path bdb_dumpfile{g_setup->m_args.GetDataDirNet() / "fuzzed_dumpfile_bdb.dump"}; if (fs::exists(bdb_dumpfile)) { // Writing into an existing dump file will throw an exception diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp index dfad0e2126..f6688ed30a 100644 --- a/src/wallet/test/ismine_tests.cpp +++ b/src/wallet/test/ismine_tests.cpp @@ -15,6 +15,7 @@ #include <boost/test/unit_test.hpp> +using namespace util::hex_literals; namespace wallet { BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup) @@ -25,13 +26,14 @@ wallet::ScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& FlatSigningProvider keys; std::string error; - std::unique_ptr<Descriptor> parsed_desc = Parse(desc_str, keys, error, false); - BOOST_CHECK(success == (parsed_desc != nullptr)); + auto parsed_descs = Parse(desc_str, keys, error, false); + BOOST_CHECK(success == (!parsed_descs.empty())); if (!success) return nullptr; + auto& desc = parsed_descs.at(0); const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1; - WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index); + WalletDescriptor w_desc(std::move(desc), timestamp, range_start, range_end, next_index); LOCK(keystore.cs_wallet); @@ -682,7 +684,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); scriptPubKey.clear(); - scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb")); + scriptPubKey << OP_0 << "aabb"_hex; result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey); BOOST_CHECK_EQUAL(result, ISMINE_NO); @@ -697,7 +699,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); scriptPubKey.clear(); - scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb")); + scriptPubKey << OP_16 << "aabb"_hex; result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey); BOOST_CHECK_EQUAL(result, ISMINE_NO); diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index 9f533bf6ed..09057114a0 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <key_io.h> +#include <node/types.h> #include <util/bip32.h> #include <util/strencodings.h> #include <wallet/wallet.h> @@ -11,6 +12,8 @@ #include <test/util/setup_common.h> #include <wallet/test/wallet_test_fixture.h> +using namespace util::hex_literals; + namespace wallet { BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup) @@ -20,8 +23,9 @@ static void import_descriptor(CWallet& wallet, const std::string& descriptor) AssertLockHeld(wallet.cs_wallet); FlatSigningProvider provider; std::string error; - std::unique_ptr<Descriptor> desc = Parse(descriptor, provider, error, /* require_checksum=*/ false); - assert(desc); + auto descs = Parse(descriptor, provider, error, /* require_checksum=*/ false); + assert(descs.size() == 1); + auto& desc = descs.at(0); WalletDescriptor w_desc(std::move(desc), 0, 0, 10, 0); wallet.AddWalletDescriptor(w_desc, provider, "", false); } @@ -33,14 +37,14 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test) // Create prevtxs and add to wallet DataStream s_prev_tx1{ - ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), + "0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"_hex, }; CTransactionRef prev_tx1; s_prev_tx1 >> TX_WITH_WITNESS(prev_tx1); m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(prev_tx1, TxStateInactive{})); DataStream s_prev_tx2{ - ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), + "0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"_hex, }; CTransactionRef prev_tx2; s_prev_tx2 >> TX_WITH_WITNESS(prev_tx2); @@ -54,13 +58,13 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test) // Call FillPSBT PartiallySignedTransaction psbtx; DataStream ssData{ - ParseHex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000"), + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000"_hex, }; ssData >> psbtx; // Fill transaction with our data bool complete = true; - BOOST_REQUIRE_EQUAL(TransactionError::OK, m_wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, false, true)); + BOOST_REQUIRE(!m_wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, false, true)); // Get the final tx DataStream ssTx{}; @@ -73,7 +77,7 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test) // Try to sign the mutated input SignatureData sigdata; - BOOST_CHECK(m_wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true, true) != TransactionError::OK); + BOOST_CHECK(m_wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true, true)); } BOOST_AUTO_TEST_CASE(parse_hd_keypath) diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp index b21a9a601d..43fd91fe60 100644 --- a/src/wallet/test/util.cpp +++ b/src/wallet/test/util.cpp @@ -31,8 +31,9 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc FlatSigningProvider provider; std::string error; - std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false); - assert(desc); + auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false); + assert(descs.size() == 1); + auto& desc = descs.at(0); WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1); if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false); } @@ -74,7 +75,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..ba12f5f6bf 100644 --- a/src/wallet/test/util.h +++ b/src/wallet/test/util.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_WALLET_TEST_UTIL_H #define BITCOIN_WALLET_TEST_UTIL_H -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <addresstype.h> #include <wallet/db.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_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index d5e75bb892..7c74c31308 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -11,64 +11,71 @@ #include <boost/test/unit_test.hpp> +using namespace util::hex_literals; + namespace wallet { BOOST_FIXTURE_TEST_SUITE(wallet_crypto_tests, BasicTestingSetup) class TestCrypter { public: -static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds, - const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(), - const std::vector<unsigned char>& correctIV=std::vector<unsigned char>()) +static void TestPassphraseSingle(const std::span<const unsigned char> salt, const SecureString& passphrase, uint32_t rounds, + const std::span<const unsigned char> correct_key = {}, + const std::span<const unsigned char> correct_iv = {}) { CCrypter crypt; - crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0); - - if(!correctKey.empty()) - BOOST_CHECK_MESSAGE(memcmp(crypt.vchKey.data(), correctKey.data(), crypt.vchKey.size()) == 0, \ - HexStr(crypt.vchKey) + std::string(" != ") + HexStr(correctKey)); - if(!correctIV.empty()) - BOOST_CHECK_MESSAGE(memcmp(crypt.vchIV.data(), correctIV.data(), crypt.vchIV.size()) == 0, - HexStr(crypt.vchIV) + std::string(" != ") + HexStr(correctIV)); + crypt.SetKeyFromPassphrase(passphrase, salt, rounds, 0); + + if (!correct_key.empty()) { + BOOST_CHECK_MESSAGE(memcmp(crypt.vchKey.data(), correct_key.data(), crypt.vchKey.size()) == 0, + HexStr(crypt.vchKey) + std::string(" != ") + HexStr(correct_key)); + } + if (!correct_iv.empty()) { + BOOST_CHECK_MESSAGE(memcmp(crypt.vchIV.data(), correct_iv.data(), crypt.vchIV.size()) == 0, + HexStr(crypt.vchIV) + std::string(" != ") + HexStr(correct_iv)); + } } -static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds, - const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(), - const std::vector<unsigned char>& correctIV=std::vector<unsigned char>()) +static void TestPassphrase(const std::span<const unsigned char> salt, const SecureString& passphrase, uint32_t rounds, + const std::span<const unsigned char> correct_key = {}, + const std::span<const unsigned char> correct_iv = {}) { - TestPassphraseSingle(vchSalt, passphrase, rounds, correctKey, correctIV); - for(SecureString::const_iterator i(passphrase.begin()); i != passphrase.end(); ++i) - TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds); + TestPassphraseSingle(salt, passphrase, rounds, correct_key, correct_iv); + for (SecureString::const_iterator it{passphrase.begin()}; it != passphrase.end(); ++it) { + TestPassphraseSingle(salt, SecureString{it, passphrase.end()}, rounds); + } } -static void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchCiphertext, \ - const std::vector<unsigned char>& vchPlaintext = std::vector<unsigned char>()) +static void TestDecrypt(const CCrypter& crypt, const std::span<const unsigned char> ciphertext, + const std::span<const unsigned char> correct_plaintext = {}) { - CKeyingMaterial vchDecrypted; - crypt.Decrypt(vchCiphertext, vchDecrypted); - if (vchPlaintext.size()) - BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted); + CKeyingMaterial decrypted; + crypt.Decrypt(ciphertext, decrypted); + if (!correct_plaintext.empty()) { + BOOST_CHECK_EQUAL_COLLECTIONS(decrypted.begin(), decrypted.end(), correct_plaintext.begin(), correct_plaintext.end()); + } } -static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext, - const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>()) +static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& plaintext, + const std::span<const unsigned char> correct_ciphertext = {}) { - std::vector<unsigned char> vchCiphertext; - crypt.Encrypt(vchPlaintext, vchCiphertext); + std::vector<unsigned char> ciphertext; + crypt.Encrypt(plaintext, ciphertext); - if (!vchCiphertextCorrect.empty()) - BOOST_CHECK(vchCiphertext == vchCiphertextCorrect); + if (!correct_ciphertext.empty()) { + BOOST_CHECK_EQUAL_COLLECTIONS(ciphertext.begin(), ciphertext.end(), correct_ciphertext.begin(), correct_ciphertext.end()); + } - const std::vector<unsigned char> vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end()); - TestDecrypt(crypt, vchCiphertext, vchPlaintext2); + TestDecrypt(crypt, ciphertext, /*correct_plaintext=*/plaintext); } -static void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchPlaintextIn, \ - const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>()) +static void TestEncrypt(const CCrypter& crypt, const std::span<const unsigned char> plaintext, + const std::span<const unsigned char> correct_ciphertext = {}) { - TestEncryptSingle(crypt, CKeyingMaterial(vchPlaintextIn.begin(), vchPlaintextIn.end()), vchCiphertextCorrect); - for(std::vector<unsigned char>::const_iterator i(vchPlaintextIn.begin()); i != vchPlaintextIn.end(); ++i) - TestEncryptSingle(crypt, CKeyingMaterial(i, vchPlaintextIn.end())); + TestEncryptSingle(crypt, CKeyingMaterial{plaintext.begin(), plaintext.end()}, correct_ciphertext); + for (auto it{plaintext.begin()}; it != plaintext.end(); ++it) { + TestEncryptSingle(crypt, CKeyingMaterial{it, plaintext.end()}); + } } }; @@ -76,47 +83,45 @@ static void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& BOOST_AUTO_TEST_CASE(passphrase) { // These are expensive. - TestCrypter::TestPassphrase(ParseHex("0000deadbeef0000"), "test", 25000, \ - ParseHex("fc7aba077ad5f4c3a0988d8daa4810d0d4a0e3bcb53af662998898f33df0556a"), \ - ParseHex("cf2f2691526dd1aa220896fb8bf7c369")); + TestCrypter::TestPassphrase("0000deadbeef0000"_hex_u8, "test", 25000, + "fc7aba077ad5f4c3a0988d8daa4810d0d4a0e3bcb53af662998898f33df0556a"_hex_u8, + "cf2f2691526dd1aa220896fb8bf7c369"_hex_u8); std::string hash(GetRandHash().ToString()); std::vector<unsigned char> vchSalt(8); GetRandBytes(vchSalt); - uint32_t rounds = InsecureRand32(); + uint32_t rounds = m_rng.rand32(); if (rounds > 30000) rounds = 30000; TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds); } BOOST_AUTO_TEST_CASE(encrypt) { - std::vector<unsigned char> vchSalt = ParseHex("0000deadbeef0000"); - BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE); + constexpr std::array<uint8_t, WALLET_CRYPTO_SALT_SIZE> salt{"0000deadbeef0000"_hex_u8}; CCrypter crypt; - crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0); - TestCrypter::TestEncrypt(crypt, ParseHex("22bcade09ac03ff6386914359cfe885cfeb5f77ff0d670f102f619687453b29d")); + crypt.SetKeyFromPassphrase("passphrase", salt, 25000, 0); + TestCrypter::TestEncrypt(crypt, "22bcade09ac03ff6386914359cfe885cfeb5f77ff0d670f102f619687453b29d"_hex_u8); for (int i = 0; i != 100; i++) { uint256 hash(GetRandHash()); - TestCrypter::TestEncrypt(crypt, std::vector<unsigned char>(hash.begin(), hash.end())); + TestCrypter::TestEncrypt(crypt, std::span<unsigned char>{hash.begin(), hash.end()}); } } BOOST_AUTO_TEST_CASE(decrypt) { - std::vector<unsigned char> vchSalt = ParseHex("0000deadbeef0000"); - BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE); + constexpr std::array<uint8_t, WALLET_CRYPTO_SALT_SIZE> salt{"0000deadbeef0000"_hex_u8}; CCrypter crypt; - crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0); + crypt.SetKeyFromPassphrase("passphrase", salt, 25000, 0); // Some corner cases the came up while testing - TestCrypter::TestDecrypt(crypt,ParseHex("795643ce39d736088367822cdc50535ec6f103715e3e48f4f3b1a60a08ef59ca")); - TestCrypter::TestDecrypt(crypt,ParseHex("de096f4a8f9bd97db012aa9d90d74de8cdea779c3ee8bc7633d8b5d6da703486")); - TestCrypter::TestDecrypt(crypt,ParseHex("32d0a8974e3afd9c6c3ebf4d66aa4e6419f8c173de25947f98cf8b7ace49449c")); - TestCrypter::TestDecrypt(crypt,ParseHex("e7c055cca2faa78cb9ac22c9357a90b4778ded9b2cc220a14cea49f931e596ea")); - TestCrypter::TestDecrypt(crypt,ParseHex("b88efddd668a6801d19516d6830da4ae9811988ccbaf40df8fbb72f3f4d335fd")); - TestCrypter::TestDecrypt(crypt,ParseHex("8cae76aa6a43694e961ebcb28c8ca8f8540b84153d72865e8561ddd93fa7bfa9")); + TestCrypter::TestDecrypt(crypt,"795643ce39d736088367822cdc50535ec6f103715e3e48f4f3b1a60a08ef59ca"_hex_u8); + TestCrypter::TestDecrypt(crypt,"de096f4a8f9bd97db012aa9d90d74de8cdea779c3ee8bc7633d8b5d6da703486"_hex_u8); + TestCrypter::TestDecrypt(crypt,"32d0a8974e3afd9c6c3ebf4d66aa4e6419f8c173de25947f98cf8b7ace49449c"_hex_u8); + TestCrypter::TestDecrypt(crypt,"e7c055cca2faa78cb9ac22c9357a90b4778ded9b2cc220a14cea49f931e596ea"_hex_u8); + TestCrypter::TestDecrypt(crypt,"b88efddd668a6801d19516d6830da4ae9811988ccbaf40df8fbb72f3f4d335fd"_hex_u8); + TestCrypter::TestDecrypt(crypt,"8cae76aa6a43694e961ebcb28c8ca8f8540b84153d72865e8561ddd93fa7bfa9"_hex_u8); for (int i = 0; i != 100; i++) { diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 53f3bcc421..b5de4b4b3d 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -65,8 +65,9 @@ static void AddKey(CWallet& wallet, const CKey& key) LOCK(wallet.cs_wallet); FlatSigningProvider provider; std::string error; - std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false); - assert(desc); + auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false); + assert(descs.size() == 1); + auto& desc = descs.at(0); WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1); if (!wallet.AddWalletDescriptor(w_desc, provider, "", false)) assert(false); } @@ -329,6 +330,39 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) } } +// This test verifies that wallet settings can be added and removed +// concurrently, ensuring no race conditions occur during either process. +BOOST_FIXTURE_TEST_CASE(write_wallet_settings_concurrently, TestingSetup) +{ + auto chain = m_node.chain.get(); + const auto NUM_WALLETS{5}; + + // Since we're counting the number of wallets, ensure we start without any. + BOOST_REQUIRE(chain->getRwSetting("wallet").isNull()); + + const auto& check_concurrent_wallet = [&](const auto& settings_function, int num_expected_wallets) { + std::vector<std::thread> threads; + threads.reserve(NUM_WALLETS); + for (auto i{0}; i < NUM_WALLETS; ++i) threads.emplace_back(settings_function, i); + for (auto& t : threads) t.join(); + + auto wallets = chain->getRwSetting("wallet"); + BOOST_CHECK_EQUAL(wallets.getValues().size(), num_expected_wallets); + }; + + // Add NUM_WALLETS wallets concurrently, ensure we end up with NUM_WALLETS stored. + check_concurrent_wallet([&chain](int i) { + Assert(AddWalletSetting(*chain, strprintf("wallet_%d", i))); + }, + /*num_expected_wallets=*/NUM_WALLETS); + + // Remove NUM_WALLETS wallets concurrently, ensure we end up with 0 wallets. + check_concurrent_wallet([&chain](int i) { + Assert(RemoveWalletSetting(*chain, strprintf("wallet_%d", i))); + }, + /*num_expected_wallets=*/0); +} + // Check that GetImmatureCredit() returns a newly calculated value instead of // the cached value after a MarkDirty() call. // @@ -889,7 +923,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) @@ -945,7 +979,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup) CMutableTransaction mtx; mtx.vout.emplace_back(COIN, GetScriptForDestination(op_dest)); - mtx.vin.emplace_back(Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0); + mtx.vin.emplace_back(Txid::FromUint256(m_rng.rand256()), 0); const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash(); { diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 9c27574103..9079f6dd82 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -273,7 +273,7 @@ public: mapValueCopy["fromaccount"] = ""; if (nOrderPos != -1) { - mapValueCopy["n"] = ToString(nOrderPos); + mapValueCopy["n"] = util::ToString(nOrderPos); } if (nTimeSmart) { mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); diff --git a/src/wallet/types.h b/src/wallet/types.h index 6198f1ae33..7e3b2caeb1 100644 --- a/src/wallet/types.h +++ b/src/wallet/types.h @@ -3,12 +3,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -//! @file Public type definitions that are used inside and outside of the wallet -//! (e.g. by src/wallet and src/interfaces and src/qt code). +//! @file wallet/types.h is a home for public enum and struct type definitions +//! that are used by internally by wallet code, but also used externally by node +//! or GUI code. //! -//! File is home for simple enum and struct definitions that don't deserve -//! separate header files. More complicated wallet public types like -//! CCoinControl that are used externally can have separate headers. +//! This file is intended to define only simple types that do not have external +//! dependencies. More complicated public wallet types like CCoinControl should +//! be defined in dedicated header files. #ifndef BITCOIN_WALLET_TYPES_H #define BITCOIN_WALLET_TYPES_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8a79cf730b..de565102cc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5,13 +5,15 @@ #include <wallet/wallet.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <addresstype.h> #include <blockfilter.h> #include <chain.h> #include <coins.h> #include <common/args.h> +#include <common/messages.h> #include <common/settings.h> +#include <common/signmessage.h> #include <common/system.h> #include <consensus/amount.h> #include <consensus/consensus.h> @@ -25,6 +27,7 @@ #include <key.h> #include <key_io.h> #include <logging.h> +#include <node/types.h> #include <outputtype.h> #include <policy/feerate.h> #include <primitives/block.h> @@ -49,10 +52,8 @@ #include <uint256.h> #include <univalue.h> #include <util/check.h> -#include <util/error.h> #include <util/fs.h> #include <util/fs_helpers.h> -#include <util/message.h> #include <util/moneystr.h> #include <util/result.h> #include <util/string.h> @@ -81,31 +82,41 @@ struct KeyOriginInfo; +using common::AmountErrMsg; +using common::AmountHighWarn; +using common::PSBTError; using interfaces::FoundBlock; +using util::ReplaceAll; +using util::ToString; namespace wallet { bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name) { - common::SettingsValue setting_value = chain.getRwSetting("wallet"); - if (!setting_value.isArray()) setting_value.setArray(); - for (const common::SettingsValue& value : setting_value.getValues()) { - if (value.isStr() && value.get_str() == wallet_name) return true; - } - setting_value.push_back(wallet_name); - return chain.updateRwSetting("wallet", setting_value); + const auto update_function = [&wallet_name](common::SettingsValue& setting_value) { + if (!setting_value.isArray()) setting_value.setArray(); + for (const auto& value : setting_value.getValues()) { + if (value.isStr() && value.get_str() == wallet_name) return interfaces::SettingsAction::SKIP_WRITE; + } + setting_value.push_back(wallet_name); + return interfaces::SettingsAction::WRITE; + }; + return chain.updateRwSetting("wallet", update_function); } bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name) { - common::SettingsValue setting_value = chain.getRwSetting("wallet"); - if (!setting_value.isArray()) return true; - common::SettingsValue new_value(common::SettingsValue::VARR); - for (const common::SettingsValue& value : setting_value.getValues()) { - if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value); - } - if (new_value.size() == setting_value.size()) return true; - return chain.updateRwSetting("wallet", new_value); + const auto update_function = [&wallet_name](common::SettingsValue& setting_value) { + if (!setting_value.isArray()) return interfaces::SettingsAction::SKIP_WRITE; + common::SettingsValue new_value(common::SettingsValue::VARR); + for (const auto& value : setting_value.getValues()) { + if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value); + } + if (new_value.size() == setting_value.size()) return interfaces::SettingsAction::SKIP_WRITE; + setting_value = std::move(new_value); + return interfaces::SettingsAction::WRITE; + }; + return chain.updateRwSetting("wallet", update_function); } static void UpdateWalletSetting(interfaces::Chain& chain, @@ -156,10 +167,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); @@ -217,38 +232,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); @@ -1031,9 +1043,8 @@ bool CWallet::IsSpentKey(const CScript& scriptPubKey) const if (IsAddressPreviouslySpent(dest)) { return true; } - if (IsLegacy()) { - LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan(); - assert(spk_man != nullptr); + + if (LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan()) { for (const auto& keyid : GetAffectedKeys(scriptPubKey, *spk_man)) { WitnessV0KeyHash wpkh_dest(keyid); if (IsAddressPreviouslySpent(wpkh_dest)) { @@ -1360,13 +1371,13 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c } -void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { +void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) { // Do not flush the wallet here for performance reasons WalletBatch batch(GetDatabase(), false); RecursiveUpdateTxState(&batch, tx_hash, try_updating_state); } -void CWallet::RecursiveUpdateTxState(WalletBatch* batch, const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { +void CWallet::RecursiveUpdateTxState(WalletBatch* batch, const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) { std::set<uint256> todo; std::set<uint256> done; @@ -1619,7 +1630,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; } @@ -1767,14 +1780,14 @@ bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const in return spk_man->ImportPrivKeys(privkey_map, timestamp); } -bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) +bool CWallet::ImportPubKeys(const std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const int64_t timestamp) { auto spk_man = GetLegacyScriptPubKeyMan(); if (!spk_man) { return false; } LOCK(spk_man->cs_KeyStore); - return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool, internal, timestamp); + return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool, timestamp); } bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) @@ -1908,14 +1921,14 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)}; if (matches_block.has_value()) { if (*matches_block) { - LogPrint(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (filter matched)\n", block_height, block_hash.ToString()); + LogDebug(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (filter matched)\n", block_height, block_hash.ToString()); } else { result.last_scanned_block = block_hash; result.last_scanned_height = block_height; fetch_block = false; } } else { - LogPrint(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.ToString()); + LogDebug(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.ToString()); } } @@ -2172,7 +2185,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, return false; } -TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed, bool finalize) const +std::optional<PSBTError> CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed, bool finalize) const { if (n_signed) { *n_signed = 0; @@ -2205,9 +2218,9 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp // Fill in information from ScriptPubKeyMans for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) { int n_signed_this_spkm = 0; - TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize); - if (res != TransactionError::OK) { - return res; + const auto error{spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize)}; + if (error) { + return error; } if (n_signed) { @@ -2219,11 +2232,11 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp // 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 TransactionError::OK; + return {}; } SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const @@ -2303,7 +2316,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. @@ -2923,7 +2936,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: // @@ -2936,15 +2949,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) @@ -2956,7 +2978,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", ""); @@ -3388,6 +3410,14 @@ void CWallet::postInitProcess() bool CWallet::BackupWallet(const std::string& strDest) const { + if (m_chain) { + CBlockLocator loc; + WITH_LOCK(cs_wallet, chain().findBlock(m_last_block_processed, FoundBlock().locator(loc))); + if (!loc.IsNull()) { + WalletBatch batch(GetDatabase()); + batch.WriteBestBlock(loc); + } + } return GetDatabase().Backup(strDest); } @@ -3543,7 +3573,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; } @@ -3573,7 +3604,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; } @@ -3602,6 +3634,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(); @@ -3618,13 +3660,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(); @@ -3737,10 +3788,11 @@ void CWallet::SetupDescriptorScriptPubKeyMans() const std::string& desc_str = desc_val.getValStr(); FlatSigningProvider keys; std::string desc_error; - std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, desc_error, false); - if (desc == nullptr) { + auto descs = Parse(desc_str, keys, desc_error, false); + if (descs.empty()) { throw std::runtime_error(std::string(__func__) + ": Invalid descriptor \"" + desc_str + "\" (" + desc_error + ")"); } + auto& desc = descs.at(0); if (!desc->GetOutputType()) { continue; } @@ -3811,11 +3863,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 @@ -3992,7 +4040,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")); @@ -4011,7 +4059,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")); @@ -4279,12 +4327,12 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error, // Parse the descriptor FlatSigningProvider keys; std::string parse_err; - std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true); - assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor - assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor + std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, parse_err, /* require_checksum */ true); + assert(descs.size() == 1); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor or a multipath descriptors + assert(!descs.at(0)->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor // Add to the wallet - WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); + WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0); data->watchonly_wallet->AddWalletDescriptor(w_desc, keys, "", false); } @@ -4316,12 +4364,12 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error, // Parse the descriptor FlatSigningProvider keys; std::string parse_err; - std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true); - assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor - assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor + std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, parse_err, /* require_checksum */ true); + assert(descs.size() == 1); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor or a multipath descriptors + assert(!descs.at(0)->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor // Add to the wallet - WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); + WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0); data->solvable_wallet->AddWalletDescriptor(w_desc, keys, "", false); } @@ -4346,11 +4394,29 @@ 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")}; + } + + // Flush chain state before unloading wallet + CBlockLocator locator; + WITH_LOCK(wallet->cs_wallet, context.chain->findBlock(wallet->GetLastBlockHash(), FoundBlock().locator(locator))); + if (!locator.IsNull()) wallet->chainStateFlushed(ChainstateRole::NORMAL, locator); + 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. @@ -4359,6 +4425,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) { @@ -4373,6 +4440,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(); @@ -4481,7 +4550,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 6a998fa398..d3a7208b15 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -58,7 +58,9 @@ class Coin; class SigningProvider; enum class MemPoolRemovalReason; enum class SigningResult; -enum class TransactionError; +namespace common { +enum class PSBTError; +} // namespace common namespace interfaces { class Wallet; } @@ -81,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); @@ -659,7 +658,7 @@ public: * @param[in] finalize whether to create the final scriptSig or scriptWitness if possible * return error */ - TransactionError FillPSBT(PartiallySignedTransaction& psbtx, + std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type = SIGHASH_DEFAULT, bool sign = true, @@ -684,7 +683,7 @@ public: bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool ImportPubKeys(const std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** Updates wallet birth time if 'time' is below it */ @@ -928,9 +927,9 @@ public: /** Prepends the wallet name in logging output to ease debugging in multi-wallet use cases */ template <typename... Params> - void WalletLogPrintf(const char* fmt, Params... parameters) const + void WalletLogPrintf(util::ConstevalFormatString<sizeof...(Params)> wallet_fmt, const Params&... params) const { - LogPrintf(("%s " + std::string{fmt}).c_str(), GetDisplayName(), parameters...); + LogInfo("%s %s", GetDisplayName(), tfm::format(wallet_fmt, params...)); }; /** Upgrade the wallet */ @@ -961,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..597a4ef9a4 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -3,7 +3,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <wallet/walletdb.h> @@ -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); @@ -1236,19 +1247,19 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) static bool RunWithinTxn(WalletBatch& batch, std::string_view process_desc, const std::function<bool(WalletBatch&)>& func) { if (!batch.TxnBegin()) { - LogPrint(BCLog::WALLETDB, "Error: cannot create db txn for %s\n", process_desc); + LogDebug(BCLog::WALLETDB, "Error: cannot create db txn for %s\n", process_desc); return false; } // Run procedure if (!func(batch)) { - LogPrint(BCLog::WALLETDB, "Error: %s failed\n", process_desc); + LogDebug(BCLog::WALLETDB, "Error: %s failed\n", process_desc); batch.TxnAbort(); return false; } if (!batch.TxnCommit()) { - LogPrint(BCLog::WALLETDB, "Error: cannot commit db txn for %s\n", process_desc); + LogDebug(BCLog::WALLETDB, "Error: cannot commit db txn for %s\n", process_desc); return false; } 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/wallettool.cpp b/src/wallet/wallettool.cpp index 10785ad354..b78985264a 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -2,7 +2,7 @@ // 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 <bitcoin-build-config.h> // IWYU pragma: keep #include <wallet/wallettool.h> diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index 0de2617d45..53e65d0194 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -94,8 +94,8 @@ WalletDescriptor GenerateWalletDescriptor(const CExtPubKey& master_key, const Ou // Make the descriptor FlatSigningProvider keys; std::string error; - std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false); - WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); + std::vector<std::unique_ptr<Descriptor>> desc = Parse(desc_str, keys, error, false); + WalletDescriptor w_desc(std::move(desc.at(0)), creation_time, 0, 0, 0); return w_desc; } diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index 38926c1eb8..ef9d93eb07 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -96,10 +96,14 @@ public: { std::string error; FlatSigningProvider keys; - descriptor = Parse(str, keys, error, true); - if (!descriptor) { + auto descs = Parse(str, keys, error, true); + if (descs.empty()) { throw std::ios_base::failure("Invalid descriptor: " + error); } + if (descs.size() > 1) { + throw std::ios_base::failure("Can't load a multipath descriptor from databases"); + } + descriptor = std::move(descs.at(0)); id = DescriptorID(*descriptor); } @@ -111,7 +115,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/warnings.cpp b/src/warnings.cpp deleted file mode 100644 index 38c0554cf2..0000000000 --- a/src/warnings.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <config/bitcoin-config.h> // IWYU pragma: keep - -#include <warnings.h> - -#include <common/system.h> -#include <sync.h> -#include <util/translation.h> - -#include <optional> -#include <vector> - -static GlobalMutex g_warnings_mutex; -static bilingual_str g_misc_warnings GUARDED_BY(g_warnings_mutex); -static bool fLargeWorkInvalidChainFound GUARDED_BY(g_warnings_mutex) = false; -static std::optional<bilingual_str> g_timeoffset_warning GUARDED_BY(g_warnings_mutex){}; - -void SetMiscWarning(const bilingual_str& warning) -{ - LOCK(g_warnings_mutex); - g_misc_warnings = warning; -} - -void SetfLargeWorkInvalidChainFound(bool flag) -{ - LOCK(g_warnings_mutex); - fLargeWorkInvalidChainFound = flag; -} - -void SetMedianTimeOffsetWarning(std::optional<bilingual_str> warning) -{ - LOCK(g_warnings_mutex); - g_timeoffset_warning = warning; -} - -std::vector<bilingual_str> GetWarnings() -{ - std::vector<bilingual_str> warnings; - - LOCK(g_warnings_mutex); - - // Pre-release build warning - if (!CLIENT_VERSION_IS_RELEASE) { - warnings.emplace_back(_("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications")); - } - - // Misc warnings like out of disk space and clock is wrong - if (!g_misc_warnings.empty()) { - warnings.emplace_back(g_misc_warnings); - } - - if (fLargeWorkInvalidChainFound) { - warnings.emplace_back(_("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.")); - } - - if (g_timeoffset_warning) { - warnings.emplace_back(g_timeoffset_warning.value()); - } - - return warnings; -} diff --git a/src/warnings.h b/src/warnings.h deleted file mode 100644 index 79dc2ffabf..0000000000 --- a/src/warnings.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_WARNINGS_H -#define BITCOIN_WARNINGS_H - -#include <optional> -#include <string> -#include <vector> - -struct bilingual_str; - -void SetMiscWarning(const bilingual_str& warning); -void SetfLargeWorkInvalidChainFound(bool flag); -/** Pass std::nullopt to disable the warning */ -void SetMedianTimeOffsetWarning(std::optional<bilingual_str> warning); -/** Return potential problems detected by the node. */ -std::vector<bilingual_str> GetWarnings(); - -#endif // BITCOIN_WARNINGS_H diff --git a/src/zmq/CMakeLists.txt b/src/zmq/CMakeLists.txt new file mode 100644 index 0000000000..8ecb236b46 --- /dev/null +++ b/src/zmq/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +add_library(bitcoin_zmq STATIC EXCLUDE_FROM_ALL + zmqabstractnotifier.cpp + zmqnotificationinterface.cpp + zmqpublishnotifier.cpp + zmqrpc.cpp + zmqutil.cpp +) +target_compile_definitions(bitcoin_zmq + INTERFACE + ENABLE_ZMQ=1 + PRIVATE + $<$<AND:$<PLATFORM_ID:Windows>,$<CXX_COMPILER_ID:GNU>>:ZMQ_STATIC> +) +target_link_libraries(bitcoin_zmq + PRIVATE + core_interface + univalue + $<TARGET_NAME_IF_EXISTS:libzmq> + $<TARGET_NAME_IF_EXISTS:PkgConfig::libzmq> +) diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 536e471053..0039f55698 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() { @@ -90,9 +88,9 @@ bool CZMQNotificationInterface::Initialize() { int major = 0, minor = 0, patch = 0; zmq_version(&major, &minor, &patch); - LogPrint(BCLog::ZMQ, "version %d.%d.%d\n", major, minor, patch); + LogDebug(BCLog::ZMQ, "version %d.%d.%d\n", major, minor, patch); - LogPrint(BCLog::ZMQ, "Initialize notification interface\n"); + LogDebug(BCLog::ZMQ, "Initialize notification interface\n"); assert(!pcontext); pcontext = zmq_ctx_new(); @@ -105,9 +103,9 @@ bool CZMQNotificationInterface::Initialize() for (auto& notifier : notifiers) { if (notifier->Initialize(pcontext)) { - LogPrint(BCLog::ZMQ, "Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress()); + LogDebug(BCLog::ZMQ, "Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress()); } else { - LogPrint(BCLog::ZMQ, "Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress()); + LogDebug(BCLog::ZMQ, "Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress()); return false; } } @@ -118,11 +116,11 @@ bool CZMQNotificationInterface::Initialize() // Called during shutdown sequence void CZMQNotificationInterface::Shutdown() { - LogPrint(BCLog::ZMQ, "Shutdown notification interface\n"); + LogDebug(BCLog::ZMQ, "Shutdown notification interface\n"); if (pcontext) { for (auto& notifier : notifiers) { - LogPrint(BCLog::ZMQ, "Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress()); + LogDebug(BCLog::ZMQ, "Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress()); notifier->Shutdown(); } zmq_ctx_term(pcontext); diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 608870c489..c0a04d28a6 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -118,7 +118,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext) return false; } - LogPrint(BCLog::ZMQ, "Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark); + LogDebug(BCLog::ZMQ, "Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark); int rc = zmq_setsockopt(psocket, ZMQ_SNDHWM, &outbound_message_high_water_mark, sizeof(outbound_message_high_water_mark)); if (rc != 0) @@ -159,8 +159,8 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext) } else { - LogPrint(BCLog::ZMQ, "Reusing socket for address %s\n", address); - LogPrint(BCLog::ZMQ, "Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark); + LogDebug(BCLog::ZMQ, "Reusing socket for address %s\n", address); + LogDebug(BCLog::ZMQ, "Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark); psocket = i->second->psocket; mapPublishNotifiers.insert(std::make_pair(address, this)); @@ -191,7 +191,7 @@ void CZMQAbstractPublishNotifier::Shutdown() if (count == 1) { - LogPrint(BCLog::ZMQ, "Close socket at address %s\n", address); + LogDebug(BCLog::ZMQ, "Close socket at address %s\n", address); int linger = 0; zmq_setsockopt(psocket, ZMQ_LINGER, &linger, sizeof(linger)); zmq_close(psocket); @@ -220,7 +220,7 @@ bool CZMQAbstractPublishNotifier::SendZmqMessage(const char *command, const void bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint(BCLog::ZMQ, "Publish hashblock %s to %s\n", hash.GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish hashblock %s to %s\n", hash.GetHex(), this->address); uint8_t data[32]; for (unsigned int i = 0; i < 32; i++) { data[31 - i] = hash.begin()[i]; @@ -231,7 +231,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "Publish hashtx %s to %s\n", hash.GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish hashtx %s to %s\n", hash.GetHex(), this->address); uint8_t data[32]; for (unsigned int i = 0; i < 32; i++) { data[31 - i] = hash.begin()[i]; @@ -241,7 +241,7 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { - LogPrint(BCLog::ZMQ, "Publish rawblock %s to %s\n", pindex->GetBlockHash().GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish rawblock %s to %s\n", pindex->GetBlockHash().GetHex(), this->address); std::vector<uint8_t> block{}; if (!m_get_block_by_index(block, *pindex)) { @@ -255,7 +255,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "Publish rawtx %s to %s\n", hash.GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish rawtx %s to %s\n", hash.GetHex(), this->address); DataStream ss; ss << TX_WITH_WITNESS(transaction); return SendZmqMessage(MSG_RAWTX, &(*ss.begin()), ss.size()); @@ -277,27 +277,27 @@ static bool SendSequenceMsg(CZMQAbstractPublishNotifier& notifier, uint256 hash, bool CZMQPublishSequenceNotifier::NotifyBlockConnect(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint(BCLog::ZMQ, "Publish sequence block connect %s to %s\n", hash.GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish sequence block connect %s to %s\n", hash.GetHex(), this->address); return SendSequenceMsg(*this, hash, /* Block (C)onnect */ 'C'); } bool CZMQPublishSequenceNotifier::NotifyBlockDisconnect(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint(BCLog::ZMQ, "Publish sequence block disconnect %s to %s\n", hash.GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish sequence block disconnect %s to %s\n", hash.GetHex(), this->address); return SendSequenceMsg(*this, hash, /* Block (D)isconnect */ 'D'); } bool CZMQPublishSequenceNotifier::NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "Publish hashtx mempool acceptance %s to %s\n", hash.GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish hashtx mempool acceptance %s to %s\n", hash.GetHex(), this->address); return SendSequenceMsg(*this, hash, /* Mempool (A)cceptance */ 'A', mempool_sequence); } bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "Publish hashtx mempool removal %s to %s\n", hash.GetHex(), this->address); + LogDebug(BCLog::ZMQ, "Publish hashtx mempool removal %s to %s\n", hash.GetHex(), this->address); return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence); } diff --git a/src/zmq/zmqutil.cpp b/src/zmq/zmqutil.cpp index 3c6d1b9ab5..842928ed1e 100644 --- a/src/zmq/zmqutil.cpp +++ b/src/zmq/zmqutil.cpp @@ -12,5 +12,5 @@ void zmqError(const std::string& str) { - LogPrint(BCLog::ZMQ, "Error: %s, msg: %s\n", str, zmq_strerror(errno)); + LogDebug(BCLog::ZMQ, "Error: %s, msg: %s\n", str, zmq_strerror(errno)); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000..3a5998697d --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +function(create_test_config) + set(abs_top_srcdir ${PROJECT_SOURCE_DIR}) + set(abs_top_builddir ${PROJECT_BINARY_DIR}) + set(EXEEXT ${CMAKE_EXECUTABLE_SUFFIX}) + + macro(set_configure_variable var conf_var) + if(${var}) + set(${conf_var}_TRUE "") + else() + set(${conf_var}_TRUE "#") + endif() + endmacro() + + set_configure_variable(ENABLE_WALLET ENABLE_WALLET) + set_configure_variable(WITH_SQLITE USE_SQLITE) + set_configure_variable(WITH_BDB USE_BDB) + set_configure_variable(BUILD_CLI BUILD_BITCOIN_CLI) + set_configure_variable(BUILD_UTIL BUILD_BITCOIN_UTIL) + set_configure_variable(BUILD_WALLET_TOOL BUILD_BITCOIN_WALLET) + set_configure_variable(BUILD_DAEMON BUILD_BITCOIND) + set_configure_variable(BUILD_FUZZ_BINARY ENABLE_FUZZ_BINARY) + set_configure_variable(WITH_ZMQ ENABLE_ZMQ) + set_configure_variable(ENABLE_EXTERNAL_SIGNER ENABLE_EXTERNAL_SIGNER) + set_configure_variable(WITH_USDT ENABLE_USDT_TRACEPOINTS) + + configure_file(config.ini.in config.ini USE_SOURCE_PERMISSIONS @ONLY) +endfunction() + +create_test_config() + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/functional) +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/fuzz) +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/util) + +file(GLOB_RECURSE functional_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} functional/*) +foreach(script ${functional_tests} fuzz/test_runner.py util/rpcauth-test.py util/test_runner.py) + if(CMAKE_HOST_WIN32) + set(symlink) + else() + set(symlink SYMBOLIC) + endif() + file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/${script} ${CMAKE_CURRENT_BINARY_DIR}/${script} COPY_ON_ERROR ${symlink}) +endforeach() +unset(functional_tests) diff --git a/test/README.md b/test/README.md index 0d1e06c0ad..74adc644b8 100644 --- a/test/README.md +++ b/test/README.md @@ -13,13 +13,15 @@ interfaces. - [util](/test/util) which tests the utilities (bitcoin-util, bitcoin-tx, ...). - [lint](/test/lint/) which perform various static analysis checks. -The util tests are run as part of `make check` target. The fuzz tests, functional +The util tests are run as part of `ctest` invocation. The fuzz tests, functional tests and lint scripts can be run as explained in the sections below. # Running tests locally Before tests can be run locally, Bitcoin Core must be built. See the [building instructions](/doc#building) for help. +The following examples assume that the build directory is named `build`. + ## Fuzz tests See [/doc/fuzzing.md](/doc/fuzzing.md) @@ -45,19 +47,19 @@ set PYTHONUTF8=1 Individual tests can be run by directly calling the test script, e.g.: ``` -test/functional/feature_rbf.py +build/test/functional/feature_rbf.py ``` or can be run through the test_runner harness, eg: ``` -test/functional/test_runner.py feature_rbf.py +build/test/functional/test_runner.py feature_rbf.py ``` You can run any combination (incl. duplicates) of tests by calling: ``` -test/functional/test_runner.py <testname1> <testname2> <testname3> ... +build/test/functional/test_runner.py <testname1> <testname2> <testname3> ... ``` Wildcard test names can be passed, if the paths are coherent and the test runner @@ -65,34 +67,34 @@ is called from a `bash` shell or similar that does the globbing. For example, to run all the wallet tests: ``` -test/functional/test_runner.py test/functional/wallet* -functional/test_runner.py functional/wallet* (called from the test/ directory) -test_runner.py wallet* (called from the test/functional/ directory) +build/test/functional/test_runner.py test/functional/wallet* +functional/test_runner.py functional/wallet* # (called from the build/test/ directory) +test_runner.py wallet* # (called from the build/test/functional/ directory) ``` but not ``` -test/functional/test_runner.py wallet* +build/test/functional/test_runner.py wallet* ``` Combinations of wildcards can be passed: ``` -test/functional/test_runner.py ./test/functional/tool* test/functional/mempool* +build/test/functional/test_runner.py ./test/functional/tool* test/functional/mempool* test_runner.py tool* mempool* ``` Run the regression test suite with: ``` -test/functional/test_runner.py +build/test/functional/test_runner.py ``` Run all possible tests with ``` -test/functional/test_runner.py --extended +build/test/functional/test_runner.py --extended ``` In order to run backwards compatibility tests, first run: @@ -107,7 +109,7 @@ By default, up to 4 tests will be run in parallel by test_runner. To specify how many jobs to run, append `--jobs=n` The individual tests and the test_runner harness have many command-line -options. Run `test/functional/test_runner.py -h` to see them all. +options. Run `build/test/functional/test_runner.py -h` to see them all. #### Speed up test runs with a RAM disk @@ -130,7 +132,7 @@ For example running the test suite with `--jobs=100` might need a 4 GiB RAM disk To use, run the test suite specifying the RAM disk as the `cachedir` and `tmpdir`: ```bash -test/functional/test_runner.py --cachedir=/mnt/tmp/cache --tmpdir=/mnt/tmp +build/test/functional/test_runner.py --cachedir=/mnt/tmp/cache --tmpdir=/mnt/tmp ``` Once finished with the tests and the disk, and to free the RAM, simply unmount the disk: @@ -151,7 +153,7 @@ Configure the RAM disk size, expressed as the number of blocks, at the end of th (`4096 MiB * 2048 blocks/MiB = 8388608 blocks` for 4 GiB). To run the tests using the RAM disk: ```bash -test/functional/test_runner.py --cachedir=/Volumes/ramdisk/cache --tmpdir=/Volumes/ramdisk/tmp +build/test/functional/test_runner.py --cachedir=/Volumes/ramdisk/cache --tmpdir=/Volumes/ramdisk/tmp ``` To unmount: @@ -193,14 +195,14 @@ pkill -9 bitcoind ##### Data directory cache A pre-mined blockchain with 200 blocks is generated the first time a -functional test is run and is stored in test/cache. This speeds up +functional test is run and is stored in build/test/cache. This speeds up test startup times since new blockchains don't need to be generated for each test. However, the cache may get into a bad state, in which case tests will fail. If this happens, remove the cache directory (and make sure bitcoind processes are stopped as above): ```bash -rm -rf test/cache +rm -rf build/test/cache killall bitcoind ``` @@ -236,7 +238,7 @@ aggregate log by running the `combine_logs.py` script. The output can be plain text, colorized text or html. For example: ``` -test/functional/combine_logs.py -c <test data directory> | less -r +build/test/functional/combine_logs.py -c <test data directory> | less -r ``` will pipe the colorized logs from the test into less. @@ -297,7 +299,7 @@ See this link for considerations: https://www.kernel.org/doc/Documentation/secur Often while debugging RPC calls in functional tests, the test might time out before the process can return a response. Use `--timeout-factor 0` to disable all RPC timeouts for that particular -functional test. Ex: `test/functional/wallet_hd.py --timeout-factor 0`. +functional test. Ex: `build/test/functional/wallet_hd.py --timeout-factor 0`. ##### Profiling @@ -321,7 +323,7 @@ For ways to generate more granular profiles, see the README in ### Util tests -Util tests can be run locally by running `test/util/test_runner.py`. +Util tests can be run locally by running `build/test/util/test_runner.py`. Use the `-v` option for verbose output. ### Lint tests diff --git a/test/functional/.gitignore b/test/functional/.gitignore index cb41d94423..0d20b6487c 100644 --- a/test/functional/.gitignore +++ b/test/functional/.gitignore @@ -1,2 +1 @@ *.pyc -cache diff --git a/test/functional/README.md b/test/functional/README.md index a4994f2e7c..a34bf1827c 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -10,7 +10,8 @@ that file and modify to fit your needs. #### Coverage -Running `test/functional/test_runner.py` with the `--coverage` argument tracks which RPCs are +Assuming the build directory is `build`, +running `build/test/functional/test_runner.py` with the `--coverage` argument tracks which RPCs are called by the tests and prints a report of uncovered RPCs in the summary. This can be used (along with the `--extended` argument) to find out which RPCs we don't have test cases for. 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..d2d7202d86 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): @@ -263,6 +263,17 @@ def getDisabledOpcodeTemplate(opcode): 'valid_in_block' : True }) +class NonStandardAndInvalid(BadTxTemplate): + """A non-standard transaction which is also consensus-invalid should return the consensus error.""" + reject_reason = "mandatory-script-verify-flag-failed (OP_RETURN was encountered)" + expect_disconnect = True + valid_in_block = False + + def get_tx(self): + return create_tx_with_script( + self.spend_tx, 0, script_sig=b'\x00' * 3 + b'\xab\x6a', + amount=(self.spend_avail // 2)) + # Disabled opcode tx templates (CVE-2010-5137) DisabledOpcodeTemplates = [getDisabledOpcodeTemplate(opcode) for opcode in [ OP_CAT, 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 658eea0a0e..2995ece42f 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -8,33 +8,31 @@ 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 - """ +import time from shutil import rmtree from dataclasses import dataclass -from test_framework.messages import tx_from_hex +from test_framework.blocktools import ( + create_block, + create_coinbase +) +from test_framework.messages import ( + CBlockHeader, + from_hex, + msg_headers, + tx_from_hex +) +from test_framework.p2p import ( + P2PInterface, +) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( + assert_approx, assert_equal, assert_raises_rpc_error, + sha256sum_file, + try_rpc, ) from test_framework.wallet import ( getnewdestination, @@ -51,18 +49,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): @@ -70,23 +69,23 @@ class AssumeutxoTest(BitcoinTestFramework): with open(valid_snapshot_path, 'rb') as f: valid_snapshot_contents = f.read() bad_snapshot_path = valid_snapshot_path + '.mod' + node = self.nodes[1] - def expected_error(log_msg="", rpc_details=""): - with self.nodes[1].assert_debug_log([log_msg]): - assert_raises_rpc_error(-32603, f"Unable to load UTXO snapshot{rpc_details}", self.nodes[1].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 bad_magic = 0xf00f00f000 with open(bad_snapshot_path, 'wb') as f: f.write(bad_magic.to_bytes(5, "big") + valid_snapshot_contents[5:]) - 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.", self.nodes[1].loadtxoutset, bad_snapshot_path) + 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.", self.nodes[1].loadtxoutset, bad_snapshot_path) + 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) self.log.info(" - snapshot file with mismatching network magic") invalid_magics = [ @@ -101,59 +100,56 @@ class AssumeutxoTest(BitcoinTestFramework): with open(bad_snapshot_path, 'wb') as f: f.write(valid_snapshot_contents[:7] + magic.to_bytes(4, 'big') + valid_snapshot_contents[11:]) if real: - assert_raises_rpc_error(parsing_error_code, f"Unable to parse metadata: The network of the snapshot ({name}) does not match the network of this node (regtest).", self.nodes[1].loadtxoutset, bad_snapshot_path) + assert_raises_rpc_error(parsing_error_code, f"Unable to parse metadata: The network of the snapshot ({name}) does not match the network of this node (regtest).", node.loadtxoutset, bad_snapshot_path) else: - assert_raises_rpc_error(parsing_error_code, "Unable to parse metadata: This snapshot has been created for an unrecognized network. This could be a custom signet, a new testnet or possibly caused by data corruption.", self.nodes[1].loadtxoutset, bad_snapshot_path) + assert_raises_rpc_error(parsing_error_code, "Unable to parse metadata: This snapshot has been created for an unrecognized network. This could be a custom signet, a new testnet or possibly caused by data corruption.", node.loadtxoutset, bad_snapshot_path) 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:]) - error_details = f", assumeutxo block hash in snapshot metadata not recognized (hash: {bad_block_hash}, height: {bogus_height}). The following snapshot heights are available: 110, 299." - expected_error(rpc_details=error_details) + 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}). 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:]: - assert_raises_rpc_error(-32603, "The base block header (3bb7ce5eba0be48939b7a521ac1ba9316afee2c7bada3a0cca24188e6d7d96c0) must appear in the headers chain. Make sure all headers are syncing, and call this RPC again.", - node.loadtxoutset, - valid_snapshot_path) + msg = "Unable to load UTXO snapshot: The base block header (3bb7ce5eba0be48939b7a521ac1ba9316afee2c7bada3a0cca24188e6d7d96c0) must appear in the headers chain. Make sure all headers are syncing, and call loadtxoutset again." + assert_raises_rpc_error(-32603, msg, node.loadtxoutset, valid_snapshot_path) def test_invalid_chainstate_scenarios(self): self.log.info("Test different scenarios of invalid snapshot chainstate in datadir") @@ -185,8 +181,8 @@ class AssumeutxoTest(BitcoinTestFramework): assert tx['txid'] in node.getrawmempool() # Attempt to load the snapshot on Node 2 and expect it to fail - with node.assert_debug_log(expected_msgs=["[snapshot] can't activate a snapshot when mempool not empty"]): - assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", node.loadtxoutset, dump_output_path) + msg = "Unable to load UTXO snapshot: Can't activate a snapshot when mempool not empty" + assert_raises_rpc_error(-32603, msg, node.loadtxoutset, dump_output_path) self.restart_node(2, extra_args=self.extra_args[2]) @@ -199,10 +195,136 @@ 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) - self.restart_node(0, extra_args=self.extra_args[0]) + 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.") + node = self.nodes[0] + # We are testing the case where the base block is invalidated itself + # and also the case where one of its parents is invalidated. + for height in [SNAPSHOT_BASE_HEIGHT, SNAPSHOT_BASE_HEIGHT - 1]: + block_hash = node.getblockhash(height) + node.invalidateblock(block_hash) + assert_equal(node.getblockcount(), height - 1) + msg = "Unable to load UTXO snapshot: The base block header (3bb7ce5eba0be48939b7a521ac1ba9316afee2c7bada3a0cca24188e6d7d96c0) is part of an invalid chain." + 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 test_sync_from_assumeutxo_node(self, snapshot): + """ + This test verifies that: + 1. An IBD node can sync headers from an AssumeUTXO node at any time. + 2. IBD nodes do not request historical blocks from AssumeUTXO nodes while they are syncing the background-chain. + 3. The assumeUTXO node dynamically adjusts the network services it offers according to its state. + 4. IBD nodes can fully sync from AssumeUTXO nodes after they finish the background-chain sync. + """ + self.log.info("Testing IBD-sync from assumeUTXO node") + # Node2 starts clean and loads the snapshot. + # Node3 starts clean and seeks to sync-up from snapshot_node. + miner = self.nodes[0] + snapshot_node = self.nodes[2] + ibd_node = self.nodes[3] + + # Start test fresh by cleaning up node directories + for node in (snapshot_node, ibd_node): + self.stop_node(node.index) + rmtree(node.chain_path) + self.start_node(node.index, extra_args=self.extra_args[node.index]) + + # Sync-up headers chain on snapshot_node to load snapshot + headers_provider_conn = snapshot_node.add_p2p_connection(P2PInterface()) + headers_provider_conn.wait_for_getheaders() + msg = msg_headers() + for block_num in range(1, miner.getblockcount()+1): + msg.headers.append(from_hex(CBlockHeader(), miner.getblockheader(miner.getblockhash(block_num), verbose=False))) + headers_provider_conn.send_message(msg) + + # Ensure headers arrived + default_value = {'status': ''} # No status + headers_tip_hash = miner.getbestblockhash() + self.wait_until(lambda: next(filter(lambda x: x['hash'] == headers_tip_hash, snapshot_node.getchaintips()), default_value)['status'] == "headers-only") + snapshot_node.disconnect_p2ps() + + # Load snapshot + snapshot_node.loadtxoutset(snapshot['path']) + + # Connect nodes and verify the ibd_node can sync-up the headers-chain from the snapshot_node + self.connect_nodes(ibd_node.index, snapshot_node.index) + snapshot_block_hash = snapshot['base_hash'] + self.wait_until(lambda: next(filter(lambda x: x['hash'] == snapshot_block_hash, ibd_node.getchaintips()), default_value)['status'] == "headers-only") + + # Once the headers-chain is synced, the ibd_node must avoid requesting historical blocks from the snapshot_node. + # If it does request such blocks, the snapshot_node will ignore requests it cannot fulfill, causing the ibd_node + # to stall. This stall could last for up to 10 min, ultimately resulting in an abrupt disconnection due to the + # ibd_node's perceived unresponsiveness. + time.sleep(3) # Sleep here because we can't detect when a node avoids requesting blocks from other peer. + assert_equal(len(ibd_node.getpeerinfo()[0]['inflight']), 0) + + # Now disconnect nodes and finish background chain sync + self.disconnect_nodes(ibd_node.index, snapshot_node.index) + self.connect_nodes(snapshot_node.index, miner.index) + self.sync_blocks(nodes=(miner, snapshot_node)) + # Check the base snapshot block was stored and ensure node signals full-node service support + self.wait_until(lambda: not try_rpc(-1, "Block not available (not fully downloaded)", snapshot_node.getblock, snapshot_block_hash)) + self.wait_until(lambda: 'NETWORK' in snapshot_node.getnetworkinfo()['localservicesnames']) + + # Now that the snapshot_node is synced, verify the ibd_node can sync from it + self.connect_nodes(snapshot_node.index, ibd_node.index) + assert 'NETWORK' in ibd_node.getpeerinfo()[0]['servicesnames'] + self.sync_blocks(nodes=(ibd_node, snapshot_node)) + + def assert_only_network_limited_service(self, node): + node_services = node.getnetworkinfo()['localservicesnames'] + assert 'NETWORK' not in node_services + assert 'NETWORK_LIMITED' in node_services def run_test(self): """ @@ -215,6 +337,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) @@ -251,7 +374,12 @@ class AssumeutxoTest(BitcoinTestFramework): assert_equal(n1.getblockcount(), START_HEIGHT) self.log.info(f"Creating a UTXO snapshot at height {SNAPSHOT_BASE_HEIGHT}") - dump_output = n0.dumptxoutset('utxos.dat') + dump_output = n0.dumptxoutset('utxos.dat', "latest") + + 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']) @@ -265,17 +393,22 @@ 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: assert_equal(n.getblockchaininfo()["headers"], SNAPSHOT_BASE_HEIGHT) - assert_equal( - dump_output['txoutset_hash'], - "a4bf3407ccb2cc0145c49ebba8fa91199f8a3903daf0883875941497d2493c27") - assert_equal(dump_output["nchaintx"], blocks[SNAPSHOT_BASE_HEIGHT].chain_tx) assert_equal(n0.getblockchaininfo()["blocks"], SNAPSHOT_BASE_HEIGHT) + def check_dump_output(output): + assert_equal( + output['txoutset_hash'], + "a4bf3407ccb2cc0145c49ebba8fa91199f8a3903daf0883875941497d2493c27") + assert_equal(output["nchaintx"], blocks[SNAPSHOT_BASE_HEIGHT].chain_tx) + + check_dump_output(dump_output) + # Mine more blocks on top of the snapshot that n1 hasn't yet seen. This # will allow us to test n1's sync-to-tip on top of a snapshot. self.generate(n0, nblocks=100, sync_fun=self.no_op) @@ -285,37 +418,120 @@ class AssumeutxoTest(BitcoinTestFramework): assert_equal(n0.getblockchaininfo()["blocks"], FINAL_HEIGHT) + self.log.info(f"Check that dumptxoutset works for past block heights") + # rollback defaults to the snapshot base height + dump_output2 = n0.dumptxoutset('utxos2.dat', "rollback") + check_dump_output(dump_output2) + assert_equal(sha256sum_file(dump_output['path']), sha256sum_file(dump_output2['path'])) + + # Rollback with specific height + dump_output3 = n0.dumptxoutset('utxos3.dat', rollback=SNAPSHOT_BASE_HEIGHT) + check_dump_output(dump_output3) + assert_equal(sha256sum_file(dump_output['path']), sha256sum_file(dump_output3['path'])) + + # Specified height that is not a snapshot height + prev_snap_height = SNAPSHOT_BASE_HEIGHT - 1 + dump_output4 = n0.dumptxoutset(path='utxos4.dat', rollback=prev_snap_height) + assert_equal( + dump_output4['txoutset_hash'], + "8a1db0d6e958ce0d7c963bc6fc91ead596c027129bacec68acc40351037b09d7") + assert sha256sum_file(dump_output['path']) != sha256sum_file(dump_output4['path']) + + # Use a hash instead of a height + prev_snap_hash = n0.getblockhash(prev_snap_height) + dump_output5 = n0.dumptxoutset('utxos5.dat', rollback=prev_snap_hash) + assert_equal(sha256sum_file(dump_output4['path']), sha256sum_file(dump_output5['path'])) + + # TODO: This is a hack to set m_best_header to the correct value after + # dumptxoutset/reconsiderblock. Otherwise the wrong error messages are + # returned in following tests. It can be removed once this bug is + # fixed. See also https://github.com/bitcoin/bitcoin/issues/26245 + self.restart_node(0, ["-reindex"]) + + # Ensure n0 is back at the tip + assert_equal(n0.getblockchaininfo()["blocks"], FINAL_HEIGHT) + self.test_snapshot_with_less_work(dump_output['path']) self.test_invalid_mempool_state(dump_output['path']) self.test_invalid_snapshot_scenarios(dump_output['path']) 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']) + + # Prune-node sanity check + assert 'NETWORK' not in n1.getnetworkinfo()['localservicesnames'] 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) + self.log.info("Confirm that local services remain unchanged") + # Since n1 is a pruned node, the 'NETWORK' service flag must always be unset. + self.assert_only_network_limited_service(n1) + + self.log.info("Check that UTXO-querying RPCs operate on snapshot chainstate") + snapshot_hash = loaded['tip_hash'] + snapshot_num_coins = loaded['coins_loaded'] + # coinstatsindex might be not caught up yet and is not relevant for this test, so don't use it + utxo_info = n1.gettxoutsetinfo(use_index=False) + assert_equal(utxo_info['txouts'], snapshot_num_coins) + assert_equal(utxo_info['height'], SNAPSHOT_BASE_HEIGHT) + assert_equal(utxo_info['bestblock'], snapshot_hash) + + # find coinbase output at snapshot height on node0 and scan for it on node1, + # where the block is not available, but the snapshot was loaded successfully + coinbase_tx = n0.getblock(snapshot_hash, verbosity=2)['tx'][0] + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", n1.getblock, snapshot_hash) + coinbase_output_descriptor = coinbase_tx['vout'][0]['scriptPubKey']['desc'] + scan_result = n1.scantxoutset('start', [coinbase_output_descriptor]) + assert_equal(scan_result['success'], True) + assert_equal(scan_result['txouts'], snapshot_num_coins) + assert_equal(scan_result['height'], SNAPSHOT_BASE_HEIGHT) + assert_equal(scan_result['bestblock'], snapshot_hash) + scan_utxos = [(coin['txid'], coin['vout']) for coin in scan_result['unspents']] + assert (coinbase_tx['txid'], 0) in scan_utxos + + txout_result = n1.gettxout(coinbase_tx['txid'], 0) + assert_equal(txout_result['scriptPubKey']['desc'], coinbase_output_descriptor) + def check_tx_counts(final: bool) -> None: """Check nTx and nChainTx intermediate values right after loading the snapshot, and final values after the snapshot is validated.""" for height, block in blocks.items(): tx = n1.getblockheader(block.hash)["nTx"] - chain_tx = n1.getchaintxstats(nblocks=1, blockhash=block.hash)["txcount"] + stats = n1.getchaintxstats(nblocks=1, blockhash=block.hash) + chain_tx = stats.get("txcount", None) + window_tx_count = stats.get("window_tx_count", None) + tx_rate = stats.get("txrate", None) + window_interval = stats.get("window_interval") # Intermediate nTx of the starting block should be set, but nTx of # later blocks should be 0 before they are downloaded. + # The window_tx_count of one block is equal to the blocks tx count. + # If the window tx count is unknown, the value is missing. + # The tx_rate is calculated from window_tx_count and window_interval + # when possible. if final or height == START_HEIGHT: assert_equal(tx, block.tx) + assert_equal(window_tx_count, tx) + if window_interval > 0: + assert_approx(tx_rate, window_tx_count / window_interval, vspan=0.1) + else: + assert_equal(tx_rate, None) else: assert_equal(tx, 0) + assert_equal(window_tx_count, None) # Intermediate nChainTx of the starting block and snapshot block - # should be set, but others should be 0 until they are downloaded. + # should be set, but others should be None until they are downloaded. if final or height in (START_HEIGHT, SNAPSHOT_BASE_HEIGHT): assert_equal(chain_tx, block.chain_tx) else: - assert_equal(chain_tx, 0) + assert_equal(chain_tx, None) check_tx_counts(final=False) @@ -341,7 +557,7 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info("Submit a spending transaction for a snapshot chainstate coin to the mempool") # spend the coinbase output of the first block that is not available on node1 spend_coin_blockhash = n1.getblockhash(START_HEIGHT + 1) - assert_raises_rpc_error(-1, "Block not found on disk", n1.getblock, spend_coin_blockhash) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", n1.getblock, spend_coin_blockhash) prev_tx = n0.getblock(spend_coin_blockhash, 3)['tx'][0] prevout = {"txid": prev_tx['txid'], "vout": 0, "scriptPubKey": prev_tx['vout'][0]['scriptPubKey']['hex']} privkey = n0.get_deterministic_priv_key().key @@ -360,6 +576,9 @@ class AssumeutxoTest(BitcoinTestFramework): self.restart_node(1, extra_args=[ f"-stopatheight={PAUSE_HEIGHT}", *self.extra_args[1]]) + # Upon restart during snapshot tip sync, the node must remain in 'limited' mode. + self.assert_only_network_limited_service(n1) + # Finally connect the nodes and let them sync. # # Set `wait_for_connect=False` to avoid a race between performing connection @@ -376,6 +595,9 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info("Restarted node before snapshot validation completed, reloading...") self.restart_node(1, extra_args=self.extra_args[1]) + # Upon restart, the node must remain in 'limited' mode + self.assert_only_network_limited_service(n1) + # Send snapshot block to n1 out of order. This makes the test less # realistic because normally the snapshot block is one of the last # blocks downloaded, but its useful to test because it triggers more @@ -394,6 +616,10 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info("Ensuring background validation completes") self.wait_until(lambda: len(n1.getchainstates()['chainstates']) == 1) + # Since n1 is a pruned node, it will not signal NODE_NETWORK after + # completing the background sync. + self.assert_only_network_limited_service(n1) + # Ensure indexes have synced. completed_idx_state = { 'basic block filter index': COMPLETE_IDX, @@ -424,12 +650,18 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info("-- Testing all indexes + reindex") assert_equal(n2.getblockcount(), START_HEIGHT) + assert 'NETWORK' in n2.getnetworkinfo()['localservicesnames'] # sanity check self.log.info(f"Loading snapshot into third node from {dump_output['path']}") loaded = n2.loadtxoutset(dump_output['path']) assert_equal(loaded['coins_loaded'], SNAPSHOT_BASE_HEIGHT) assert_equal(loaded['base_height'], SNAPSHOT_BASE_HEIGHT) + # Even though n2 is a full node, it will unset the 'NETWORK' service flag during snapshot loading. + # This indicates other peers that the node will temporarily not provide historical blocks. + self.log.info("Check node2 updated the local services during snapshot load") + self.assert_only_network_limited_service(n2) + for reindex_arg in ['-reindex=1', '-reindex-chainstate=1']: self.log.info(f"Check that restarting with {reindex_arg} will delete the snapshot chainstate") self.restart_node(2, extra_args=[reindex_arg, *self.extra_args[2]]) @@ -450,16 +682,24 @@ class AssumeutxoTest(BitcoinTestFramework): assert_equal(snapshot['validated'], False) self.log.info("Check that loading the snapshot again will fail because there is already an active snapshot.") - with n2.assert_debug_log(expected_msgs=["[snapshot] can't activate a snapshot-based chainstate more than once"]): - assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", n2.loadtxoutset, dump_output['path']) + msg = "Unable to load UTXO snapshot: Can't activate a snapshot-based chainstate more than once" + assert_raises_rpc_error(-32603, msg, n2.loadtxoutset, dump_output['path']) + + # Upon restart, the node must stay in 'limited' mode until the background + # chain sync completes. + self.restart_node(2, extra_args=self.extra_args[2]) + self.assert_only_network_limited_service(n2) 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) + # Once background chain sync completes, the full node must start offering historical blocks again. + self.wait_until(lambda: {'NETWORK', 'NETWORK_LIMITED'}.issubset(n2.getnetworkinfo()['localservicesnames'])) + completed_idx_state = { 'basic block filter index': COMPLETE_IDX, 'coinstatsindex': COMPLETE_IDX, @@ -492,6 +732,11 @@ 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']) + + # The following test cleans node2 and node3 chain directories. + self.test_sync_from_assumeutxo_node(snapshot=dump_output) + @dataclass class Block: hash: str @@ -499,4 +744,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..32ad3ad271 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -139,8 +139,8 @@ class AssumeValidTest(BitcoinTestFramework): height += 1 # Start node1 and node2 with assumevalid so they accept a block with a bad signature. - self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)]) - self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)]) + self.start_node(1, extra_args=["-assumevalid=" + block102.hash]) + self.start_node(2, extra_args=["-assumevalid=" + block102.hash]) p2p0 = self.nodes[0].add_p2p_connection(BaseNode()) p2p0.send_header_for_blocks(self.blocks[0:2000]) @@ -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 8768d4040d..2d61987e94 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -78,8 +78,8 @@ class BIP68Test(BitcoinTestFramework): self.log.info("Activating BIP68 (and 112/113)") self.activateCSV() - self.log.info("Verifying nVersion=2 transactions are standard.") - self.log.info("Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).") + self.log.info("Verifying version=2 transactions are standard.") + self.log.info("Note that version=2 transactions are always standard (independent of BIP68 activation status).") self.test_version2_relay() self.log.info("Passed") @@ -107,7 +107,7 @@ class BIP68Test(BitcoinTestFramework): # This transaction will enable sequence-locks, so this transaction should # fail tx2 = CTransaction() - tx2.nVersion = 2 + tx2.version = 2 sequence_value = sequence_value & 0x7fffffff tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)] tx2.wit.vtxinwit = [CTxInWitness()] @@ -119,7 +119,7 @@ class BIP68Test(BitcoinTestFramework): # Setting the version back down to 1 should disable the sequence lock, # so this should be accepted. - tx2.nVersion = 1 + tx2.version = 1 self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2.serialize().hex()) @@ -159,7 +159,7 @@ class BIP68Test(BitcoinTestFramework): using_sequence_locks = False tx = CTransaction() - tx.nVersion = 2 + tx.version = 2 value = 0 for j in range(num_inputs): sequence_value = 0xfffffffe # this disables sequence locks @@ -228,7 +228,7 @@ class BIP68Test(BitcoinTestFramework): # Anyone-can-spend mempool tx. # Sequence lock of 0 should pass. tx2 = CTransaction() - tx2.nVersion = 2 + tx2.version = 2 tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] self.wallet.sign_tx(tx=tx2) @@ -246,7 +246,7 @@ class BIP68Test(BitcoinTestFramework): sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG tx = CTransaction() - tx.nVersion = 2 + tx.version = 2 tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)] tx.wit.vtxinwit = [CTxInWitness()] tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] @@ -360,7 +360,7 @@ class BIP68Test(BitcoinTestFramework): # Make an anyone-can-spend transaction tx2 = CTransaction() - tx2.nVersion = 1 + tx2.version = 1 tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] @@ -376,7 +376,7 @@ class BIP68Test(BitcoinTestFramework): sequence_value = 100 # 100 block relative locktime tx3 = CTransaction() - tx3.nVersion = 2 + tx3.version = 2 tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)] tx3.wit.vtxinwit = [CTxInWitness()] tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] @@ -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..43bf61c174 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -88,6 +88,7 @@ class FullBlockTest(BitcoinTestFramework): self.extra_args = [[ '-acceptnonstdtxn=1', # This is a consensus block test, we don't care about tx policy '-testactivationheight=bip34@2', + '-par=1', # Until https://github.com/bitcoin/bitcoin/issues/30960 is fixed ]] def run_test(self): @@ -1326,8 +1327,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 +1341,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 +1368,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 +1441,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..9824bf9715 --- /dev/null +++ b/test/functional/feature_blocksxor.py @@ -0,0 +1,68 @@ +#!/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).""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_node import ( + ErrorMatch, + NULL_BLK_XOR_KEY, +) +from test_framework.util import ( + assert_equal, + assert_greater_than, + 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_vsize=20000) + 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 = node.read_xor_key() + 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") + node.blocks_key_path.unlink() + 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) + self.log.info("Check that blocks XOR key is recreated") + assert_equal(node.read_xor_key(), NULL_BLK_XOR_KEY) + + +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 d6c1567e64..b4392e6002 100755 --- a/test/functional/feature_coinstatsindex.py +++ b/test/functional/feature_coinstatsindex.py @@ -242,6 +242,9 @@ class CoinStatsIndexTest(BitcoinTestFramework): res12 = index_node.gettxoutsetinfo('muhash') assert_equal(res12, res10) + self.log.info("Test obtaining info for a non-existent block hash") + assert_raises_rpc_error(-5, "Block not found", index_node.gettxoutsetinfo, hash_type="none", hash_or_height="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", use_index=True) + def _test_use_index_option(self): self.log.info("Test use_index option for nodes running the index") @@ -321,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..44c7edf962 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -153,6 +153,13 @@ class ConfArgsTest(BitcoinTestFramework): expected_msg='Error: Error parsing command line arguments: Can not set -proxy with no value. Please specify value with -proxy=value.', extra_args=['-proxy'], ) + # Provide a value different from 1 to the -wallet negated option + if self.is_wallet_compiled(): + for value in [0, 'not_a_boolean']: + self.nodes[0].assert_start_raises_init_error( + expected_msg="Error: Invalid value detected for '-wallet' or '-nowallet'. '-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets", + extra_args=[f'-nowallet={value}'], + ) def test_log_buffer(self): self.stop_node(0) @@ -371,11 +378,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 +429,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 +472,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 bc1f9e8f2f..df02bcc6ad 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -110,7 +110,7 @@ class BIP68_112_113Test(BitcoinTestFramework): def create_bip112special(self, input, txversion): tx = self.create_self_transfer_from_utxo(input) - tx.nVersion = txversion + tx.version = txversion self.miniwallet.sign_tx(tx) tx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig))) tx.rehash() @@ -118,7 +118,7 @@ class BIP68_112_113Test(BitcoinTestFramework): def create_bip112emptystack(self, input, txversion): tx = self.create_self_transfer_from_utxo(input) - tx.nVersion = txversion + tx.version = txversion self.miniwallet.sign_tx(tx) tx.vin[0].scriptSig = CScript([OP_CHECKSEQUENCEVERIFY] + list(CScript(tx.vin[0].scriptSig))) tx.rehash() @@ -136,7 +136,7 @@ class BIP68_112_113Test(BitcoinTestFramework): for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)): locktime = relative_locktime(sdf, srhb, stf, srlb) tx = self.create_self_transfer_from_utxo(bip68inputs[i]) - tx.nVersion = txversion + tx.version = txversion tx.vin[0].nSequence = locktime + locktime_delta self.miniwallet.sign_tx(tx) txs.append({'tx': tx, 'sdf': sdf, 'stf': stf}) @@ -154,7 +154,7 @@ class BIP68_112_113Test(BitcoinTestFramework): tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta else: # vary nSequence instead, OP_CSV is fixed tx.vin[0].nSequence = locktime + locktime_delta - tx.nVersion = txversion + tx.version = txversion self.miniwallet.sign_tx(tx) if varyOP_CSV: tx.vin[0].scriptSig = CScript([locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig))) @@ -257,10 +257,10 @@ class BIP68_112_113Test(BitcoinTestFramework): # BIP113 test transaction will be modified before each use to put in appropriate block time bip113tx_v1 = self.create_self_transfer_from_utxo(bip113input) bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE - bip113tx_v1.nVersion = 1 + bip113tx_v1.version = 1 bip113tx_v2 = self.create_self_transfer_from_utxo(bip113input) bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE - bip113tx_v2.nVersion = 2 + bip113tx_v2.version = 2 # For BIP68 test all 16 relative sequence locktimes bip68txs_v1 = self.create_bip68txs(bip68inputs, 1) @@ -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..974d8268a2 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test fee estimation code.""" from copy import deepcopy -from decimal import Decimal +from decimal import Decimal, ROUND_DOWN import os import random import time @@ -40,7 +40,7 @@ def small_txpuzzle_randfee( # Exponentially distributed from 1-128 * fee_increment rand_fee = float(fee_increment) * (1.1892 ** random.randint(0, 28)) # Total fee ranges from min_fee to min_fee + 127*fee_increment - fee = min_fee - fee_increment + satoshi_round(rand_fee) + fee = min_fee - fee_increment + satoshi_round(rand_fee, rounding=ROUND_DOWN) utxos_to_spend = [] total_in = Decimal("0.00000000") while total_in <= (amount + fee) and len(conflist) > 0: @@ -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,41 @@ 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) + self.sync_blocks() + 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 +463,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 +480,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 new file mode 100755 index 0000000000..f723f7f31e --- /dev/null +++ b/test/functional/feature_framework_miniwallet.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 MiniWallet.""" +import random +import string + +from test_framework.blocktools import COINBASE_MATURITY +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, +) +from test_framework.wallet import ( + MiniWallet, + MiniWalletMode, +) + + +class FeatureFrameworkMiniWalletTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def test_tx_padding(self): + """Verify that MiniWallet's transaction padding (`target_vsize` parameter) + works accurately with all modes.""" + for mode_name, wallet in self.wallets: + self.log.info(f"Test tx padding with MiniWallet mode {mode_name}...") + utxo = wallet.get_utxo(mark_as_spent=False) + for target_vsize in [250, 500, 1250, 2500, 5000, 12500, 25000, 50000, 1000000, + 248, 501, 1085, 3343, 5805, 12289, 25509, 55855, 999998]: + tx = wallet.create_self_transfer(utxo_to_spend=utxo, target_vsize=target_vsize)["tx"] + assert_equal(tx.get_vsize(), target_vsize) + + 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 = [ + ("ADDRESS_OP_TRUE", MiniWallet(node, mode=MiniWalletMode.ADDRESS_OP_TRUE)), + ("RAW_OP_TRUE", MiniWallet(node, mode=MiniWalletMode.RAW_OP_TRUE)), + ("RAW_P2PK", MiniWallet(node, mode=MiniWalletMode.RAW_P2PK)), + ] + for _, wallet in self.wallets: + self.generate(wallet, 10) + self.generate(wallet, COINBASE_MATURITY) + + self.test_tx_padding() + self.test_wallet_tagging() + + +if __name__ == '__main__': + FeatureFrameworkMiniWalletTest(__file__).main() diff --git a/test/functional/feature_framework_unit_tests.py b/test/functional/feature_framework_unit_tests.py index f03f084bed..14d83f8a70 100755 --- a/test/functional/feature_framework_unit_tests.py +++ b/test/functional/feature_framework_unit_tests.py @@ -27,6 +27,7 @@ TEST_FRAMEWORK_MODULES = [ "crypto.ripemd160", "crypto.secp256k1", "script", + "script_util", "segwit_addr", "wallet_util", ] 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..34228f6f38 100755 --- a/test/functional/feature_minchainwork.py +++ b/test/functional/feature_minchainwork.py @@ -110,9 +110,9 @@ class MinimumChainWorkTest(BitcoinTestFramework): self.stop_node(0) self.nodes[0].assert_start_raises_init_error( ["-minimumchainwork=test"], - expected_msg='Error: Invalid non-hex (test) minimum chain work value specified', + expected_msg='Error: Invalid minimum work specified (test), must be up to 64 hex digits', ) 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 f0f32a61ab..1ebfe82da5 100755 --- a/test/functional/feature_reindex.py +++ b/test/functional/feature_reindex.py @@ -12,7 +12,10 @@ 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, + util_xor, +) class ReindexTest(BitcoinTestFramework): @@ -39,9 +42,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 = self.nodes[0].read_xor_key() + 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 +60,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([ @@ -73,6 +78,25 @@ class ReindexTest(BitcoinTestFramework): # All blocks should be accepted and processed. assert_equal(self.nodes[0].getblockcount(), 12) + def continue_reindex_after_shutdown(self): + node = self.nodes[0] + self.generate(node, 1500) + + # Restart node with reindex and stop reindex as soon as it starts reindexing + self.log.info("Restarting node while reindexing..") + node.stop_node() + with node.busy_wait_for_debug_log([b'initload thread start']): + node.start(['-blockfilterindex', '-reindex']) + node.wait_for_rpc_connection(wait_for_import=False) + node.stop_node() + + # Start node without the reindex flag and verify it does not wipe the indexes data again + db_path = node.chain_path / 'indexes' / 'blockfilter' / 'basic' / 'db' + with node.assert_debug_log(expected_msgs=[f'Opening LevelDB in {db_path}'], unexpected_msgs=[f'Wiping LevelDB in {db_path}']): + node.start(['-blockfilterindex']) + node.wait_for_rpc_connection(wait_for_import=False) + node.stop_node() + def run_test(self): self.reindex(False) self.reindex(True) @@ -80,7 +104,8 @@ class ReindexTest(BitcoinTestFramework): self.reindex(True) self.out_of_order() + self.continue_reindex_after_shutdown() 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 0214e781de..a7294944bf 100755 --- a/test/functional/feature_settings.py +++ b/test/functional/feature_settings.py @@ -13,11 +13,32 @@ from test_framework.util import assert_equal class SettingsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.wallet_names = [] + def test_wallet_settings(self, settings_path): + if not self.is_wallet_compiled(): + return + + self.log.info("Testing wallet settings..") + node = self.nodes[0] + # Create wallet to use it during tests + self.start_node(0) + node.createwallet(wallet_name='w1') + self.stop_node(0) + + # Verify wallet settings can only be strings. Either names or paths. Not booleans, nums nor anything else. + for wallets_data in [[10], [True], [[]], [{}], ["w1", 10], ["w1", False]]: + with settings_path.open("w") as fp: + json.dump({"wallet": wallets_data}, fp) + node.assert_start_raises_init_error(expected_msg="Error: Invalid value detected for '-wallet' or '-nowallet'. '-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets", + extra_args=[f'-settings={settings_path}']) + def run_test(self): node, = self.nodes settings = node.chain_path / "settings.json" @@ -25,7 +46,7 @@ class SettingsTest(BitcoinTestFramework): # Assert default settings file was created self.stop_node(0) - default_settings = {"_warning_": "This file is automatically generated and updated by Bitcoin Core. Please do not edit this file while the node is running, as any changes might be ignored or overwritten."} + default_settings = {"_warning_": f"This file is automatically generated and updated by {self.config['environment']['PACKAGE_NAME']}. Please do not edit this file while the node is running, as any changes might be ignored or overwritten."} with settings.open() as fp: assert_equal(json.load(fp), default_settings) @@ -86,6 +107,8 @@ class SettingsTest(BitcoinTestFramework): self.start_node(0, extra_args=[f"-settings={altsettings}"]) self.stop_node(0) + self.test_wallet_settings(settings) + 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 e7d65b4539..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": @@ -1408,10 +1408,10 @@ class TaprootTest(BitcoinTestFramework): left = done while left: - # Construct CTransaction with random nVersion, nLocktime + # Construct CTransaction with random version, nLocktime tx = CTransaction() - tx.nVersion = random.choice([1, 2, random.randint(-0x80000000, 0x7fffffff)]) - min_sequence = (tx.nVersion != 1 and tx.nVersion != 0) * 0x80000000 # The minimum sequence number to disable relative locktime + tx.version = random.choice([1, 2, random.getrandbits(32)]) + min_sequence = (tx.version != 1 and tx.version != 0) * 0x80000000 # The minimum sequence number to disable relative locktime if random.choice([True, False]): tx.nLockTime = random.randrange(LOCKTIME_THRESHOLD, self.lastblocktime - 7200) # all absolute locktimes in the past else: @@ -1502,8 +1502,8 @@ class TaprootTest(BitcoinTestFramework): is_standard_tx = ( fail_input is None # Must be valid to be standard and (all(utxo.spender.is_standard for utxo in input_utxos)) # All inputs must be standard - and tx.nVersion >= 1 # The tx version must be standard - and tx.nVersion <= 2) + and tx.version >= 1 # The tx version must be standard + and tx.version <= 2) tx.rehash() msg = ','.join(utxo.spender.comment + ("*" if n == fail_input else "") for n, utxo in enumerate(input_utxos)) if is_standard_tx: @@ -1530,7 +1530,7 @@ class TaprootTest(BitcoinTestFramework): # Deterministically mine coins to OP_TRUE in block 1 assert_equal(self.nodes[0].getblockcount(), 0) coinbase = CTransaction() - coinbase.nVersion = 1 + coinbase.version = 1 coinbase.vin = [CTxIn(COutPoint(0, 0xffffffff), CScript([OP_1, OP_1]), SEQUENCE_FINAL)] coinbase.vout = [CTxOut(5000000000, CScript([OP_1]))] coinbase.nLockTime = 0 @@ -1622,7 +1622,7 @@ class TaprootTest(BitcoinTestFramework): for i, spk in enumerate(old_spks + tap_spks): val = 42000000 * (i + 7) tx = CTransaction() - tx.nVersion = 1 + tx.version = 1 tx.vin = [CTxIn(COutPoint(lasttxid, i & 1), CScript([]), SEQUENCE_FINAL)] tx.vout = [CTxOut(val, spk), CTxOut(amount - val, CScript([OP_1]))] if i & 1: @@ -1679,7 +1679,7 @@ class TaprootTest(BitcoinTestFramework): # Construct a deterministic transaction spending all outputs created above. tx = CTransaction() - tx.nVersion = 2 + tx.version = 2 tx.vin = [] inputs = [] input_spks = [tap_spks[0], tap_spks[1], old_spks[0], tap_spks[2], tap_spks[5], old_spks[2], tap_spks[6], tap_spks[3], tap_spks[4]] @@ -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 83bb5121e5..7194c8ece4 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -8,6 +8,7 @@ from decimal import Decimal import re from test_framework.blocktools import COINBASE_MATURITY +from test_framework.netutil import test_ipv6_local from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -15,6 +16,7 @@ from test_framework.util import ( assert_raises_process_error, assert_raises_rpc_error, get_auth_cookie, + rpc_port, ) import time @@ -28,7 +30,12 @@ JSON_PARSING_ERROR = 'error: Error parsing JSON: foo' BLOCKS_VALUE_OF_ZERO = 'error: the first argument (number of blocks to generate, default: 1) must be an integer value greater than zero' TOO_MANY_ARGS = 'error: too many arguments (maximum 2 for nblocks and maxtries)' WALLET_NOT_LOADED = 'Requested wallet does not exist or is not loaded' -WALLET_NOT_SPECIFIED = 'Wallet file not specified' +WALLET_NOT_SPECIFIED = ( + "Multiple wallets are loaded. Please select which wallet to use by requesting the RPC " + "through the /wallet/<walletname> URI path. Or for the CLI, specify the \"-rpcwallet=<walletname>\" " + "option before the command (run \"bitcoin-cli -h\" for help or \"bitcoin-cli listwallets\" to see " + "which wallets are currently loaded)." +) def cli_get_info_string_to_dict(cli_get_info_string): @@ -107,6 +114,53 @@ class TestBitcoinCli(BitcoinTestFramework): self.log.info("Test connecting to a non-existing server") assert_raises_process_error(1, "Could not connect to the server", self.nodes[0].cli('-rpcport=1').echo) + self.log.info("Test handling of invalid ports in rpcconnect") + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: 127.0.0.1:notaport", self.nodes[0].cli("-rpcconnect=127.0.0.1:notaport").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: 127.0.0.1:-1", self.nodes[0].cli("-rpcconnect=127.0.0.1:-1").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: 127.0.0.1:0", self.nodes[0].cli("-rpcconnect=127.0.0.1:0").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: 127.0.0.1:65536", self.nodes[0].cli("-rpcconnect=127.0.0.1:65536").echo) + + self.log.info("Checking for IPv6") + have_ipv6 = test_ipv6_local() + if not have_ipv6: + self.log.info("Skipping IPv6 tests") + + if have_ipv6: + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: [::1]:notaport", self.nodes[0].cli("-rpcconnect=[::1]:notaport").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: [::1]:-1", self.nodes[0].cli("-rpcconnect=[::1]:-1").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: [::1]:0", self.nodes[0].cli("-rpcconnect=[::1]:0").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcconnect: [::1]:65536", self.nodes[0].cli("-rpcconnect=[::1]:65536").echo) + + self.log.info("Test handling of invalid ports in rpcport") + assert_raises_process_error(1, "Invalid port provided in -rpcport: notaport", self.nodes[0].cli("-rpcport=notaport").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcport: -1", self.nodes[0].cli("-rpcport=-1").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcport: 0", self.nodes[0].cli("-rpcport=0").echo) + assert_raises_process_error(1, "Invalid port provided in -rpcport: 65536", self.nodes[0].cli("-rpcport=65536").echo) + + self.log.info("Test port usage preferences") + node_rpc_port = rpc_port(self.nodes[0].index) + # Prevent bitcoin-cli from using existing rpcport in conf + conf_rpcport = "rpcport=" + str(node_rpc_port) + self.nodes[0].replace_in_config([(conf_rpcport, "#" + conf_rpcport)]) + # prefer rpcport over rpcconnect + assert_raises_process_error(1, "Could not connect to the server 127.0.0.1:1", self.nodes[0].cli(f"-rpcconnect=127.0.0.1:{node_rpc_port}", "-rpcport=1").echo) + if have_ipv6: + assert_raises_process_error(1, "Could not connect to the server ::1:1", self.nodes[0].cli(f"-rpcconnect=[::1]:{node_rpc_port}", "-rpcport=1").echo) + + assert_equal(BLOCKS, self.nodes[0].cli("-rpcconnect=127.0.0.1:18999", f'-rpcport={node_rpc_port}').getblockcount()) + if have_ipv6: + assert_equal(BLOCKS, self.nodes[0].cli("-rpcconnect=[::1]:18999", f'-rpcport={node_rpc_port}').getblockcount()) + + # prefer rpcconnect port over default + assert_equal(BLOCKS, self.nodes[0].cli(f"-rpcconnect=127.0.0.1:{node_rpc_port}").getblockcount()) + if have_ipv6: + assert_equal(BLOCKS, self.nodes[0].cli(f"-rpcconnect=[::1]:{node_rpc_port}").getblockcount()) + + # prefer rpcport over default + assert_equal(BLOCKS, self.nodes[0].cli(f'-rpcport={node_rpc_port}').getblockcount()) + # Re-enable rpcport in conf if present + self.nodes[0].replace_in_config([("#" + conf_rpcport, conf_rpcport)]) + self.log.info("Test connecting with non-existing RPC cookie file") assert_raises_process_error(1, "Could not locate RPC credentials", self.nodes[0].cli('-rpccookiefile=does-not-exist', '-rpcpassword=').echo) @@ -282,6 +336,10 @@ class TestBitcoinCli(BitcoinTestFramework): n4 = 10 blocks = self.nodes[0].getblockcount() + self.log.info('Test -generate -rpcwallet=<filename> raise RPC error') + wallet2_path = f'-rpcwallet={self.nodes[0].wallets_path / wallets[2] / self.wallet_data_filename}' + assert_raises_rpc_error(-18, WALLET_NOT_LOADED, self.nodes[0].cli(wallet2_path, '-generate').echo) + self.log.info('Test -generate -rpcwallet with no args') generate = self.nodes[0].cli(rpcwallet2, '-generate').send_cli() assert_equal(set(generate.keys()), {'address', 'blocks'}) @@ -332,6 +390,9 @@ class TestBitcoinCli(BitcoinTestFramework): assert_raises_process_error(1, "Could not connect to the server", self.nodes[0].cli('-rpcwait', '-rpcwaittimeout=5').echo) assert_greater_than_or_equal(time.time(), start_time + 5) + self.log.info("Test that only one of -addrinfo, -generate, -getinfo, -netinfo may be specified at a time") + assert_raises_process_error(1, "Only one of -getinfo, -netinfo may be specified", self.nodes[0].cli('-getinfo', '-netinfo').send_cli) + 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 b08ca42796..9074f0a2d9 100755 --- a/test/functional/interface_rpc.py +++ b/test/functional/interface_rpc.py @@ -14,7 +14,6 @@ from typing import Optional import subprocess -RPC_INVALID_ADDRESS_OR_KEY = -5 RPC_INVALID_PARAMETER = -8 RPC_METHOD_NOT_FOUND = -32601 RPC_INVALID_REQUEST = -32600 @@ -247,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..f684848aed 100755 --- a/test/functional/interface_usdt_coinselection.py +++ b/test/functional/interface_usdt_coinselection.py @@ -181,7 +181,7 @@ class CoinSelectionTracepointTest(BitcoinTestFramework): # 5. aps_create_tx_internal (type 4) wallet.sendtoaddress(wallet.getnewaddress(), 10) events = self.get_tracepoints([1, 2, 3, 1, 4]) - success, use_aps, algo, waste, change_pos = self.determine_selection_from_usdt(events) + success, use_aps, _algo, _waste, change_pos = self.determine_selection_from_usdt(events) assert_equal(success, True) assert_greater_than(change_pos, -1) @@ -190,7 +190,7 @@ class CoinSelectionTracepointTest(BitcoinTestFramework): # 1. normal_create_tx_internal (type 2) assert_raises_rpc_error(-6, "Insufficient funds", wallet.sendtoaddress, wallet.getnewaddress(), 102 * 50) events = self.get_tracepoints([2]) - success, use_aps, algo, waste, change_pos = self.determine_selection_from_usdt(events) + success, use_aps, _algo, _waste, change_pos = self.determine_selection_from_usdt(events) assert_equal(success, False) self.log.info("Explicitly enabling APS results in 2 tracepoints") @@ -200,7 +200,7 @@ class CoinSelectionTracepointTest(BitcoinTestFramework): wallet.setwalletflag("avoid_reuse") wallet.sendtoaddress(address=wallet.getnewaddress(), amount=10, avoid_reuse=True) events = self.get_tracepoints([1, 2]) - success, use_aps, algo, waste, change_pos = self.determine_selection_from_usdt(events) + success, use_aps, _algo, _waste, change_pos = self.determine_selection_from_usdt(events) assert_equal(success, True) assert_equal(use_aps, None) @@ -213,7 +213,7 @@ class CoinSelectionTracepointTest(BitcoinTestFramework): # 5. aps_create_tx_internal (type 4) wallet.sendtoaddress(address=wallet.getnewaddress(), amount=wallet.getbalance(), subtractfeefromamount=True, avoid_reuse=False) events = self.get_tracepoints([1, 2, 3, 1, 4]) - success, use_aps, algo, waste, change_pos = self.determine_selection_from_usdt(events) + success, use_aps, _algo, _waste, change_pos = self.determine_selection_from_usdt(events) assert_equal(success, True) assert_equal(change_pos, -1) @@ -223,7 +223,7 @@ class CoinSelectionTracepointTest(BitcoinTestFramework): # 2. normal_create_tx_internal (type 2) wallet.sendtoaddress(address=wallet.getnewaddress(), amount=wallet.getbalance(), subtractfeefromamount=True) events = self.get_tracepoints([1, 2]) - success, use_aps, algo, waste, change_pos = self.determine_selection_from_usdt(events) + success, use_aps, _algo, _waste, change_pos = self.determine_selection_from_usdt(events) assert_equal(success, True) assert_equal(change_pos, -1) @@ -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..8a98a452de 100755 --- a/test/functional/interface_usdt_validation.py +++ b/test/functional/interface_usdt_validation.py @@ -8,6 +8,7 @@ """ import ctypes +import time # Test will be skipped if we don't have bcc installed try: @@ -105,10 +106,12 @@ class ValidationTracepointTest(BitcoinTestFramework): handle_blockconnected) self.log.info(f"mine {BLOCKS_EXPECTED} blocks") - block_hashes = self.generatetoaddress( - self.nodes[0], BLOCKS_EXPECTED, ADDRESS_BCRT1_UNSPENDABLE) - for block_hash in block_hashes: - expected_blocks[block_hash] = self.nodes[0].getblock(block_hash, 2) + generatetoaddress_duration = dict() + for _ in range(BLOCKS_EXPECTED): + start = time.time() + hash = self.generatetoaddress(self.nodes[0], 1, ADDRESS_BCRT1_UNSPENDABLE)[0] + generatetoaddress_duration[hash] = (time.time() - start) * 1e9 # in nanoseconds + expected_blocks[hash] = self.nodes[0].getblock(hash, 2) bpf.perf_buffer_poll(timeout=200) @@ -123,6 +126,10 @@ class ValidationTracepointTest(BitcoinTestFramework): assert_equal(0, event.sigops) # no sigops in coinbase tx # only plausibility checks assert event.duration > 0 + # generatetoaddress (mining and connecting) takes longer than + # connecting the block. In case the duration unit is off, we'll + # detect it with this assert. + assert event.duration < generatetoaddress_duration[block_hash] del expected_blocks[block_hash] assert_equal(BLOCKS_EXPECTED, len(events)) assert_equal(0, len(expected_blocks)) @@ -131,4 +138,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 b00be5f4f0..4d08575255 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -18,6 +18,7 @@ from test_framework.messages import ( CTxInWitness, CTxOut, MAX_BLOCK_WEIGHT, + WITNESS_SCALE_FACTOR, MAX_MONEY, SEQUENCE_FINAL, tx_from_hex, @@ -36,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, ) @@ -53,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 @@ -228,7 +231,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): self.log.info('A really large transaction') tx = tx_from_hex(raw_tx_reference) - tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_WEIGHT // 4 / len(tx.vin[0].serialize())) + tx.vin = [tx.vin[0]] * math.ceil((MAX_BLOCK_WEIGHT // WITNESS_SCALE_FACTOR) / len(tx.vin[0].serialize())) self.check_mempool_result( result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}], rawtxs=[tx.serialize().hex()], @@ -287,7 +290,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): self.log.info('Some nonstandard transactions') tx = tx_from_hex(raw_tx_reference) - tx.nVersion = 3 # A version currently non-standard + tx.version = 4 # A version currently non-standard self.check_mempool_result( result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}], rawtxs=[tx.serialize().hex()], @@ -388,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) @@ -408,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 d46924f4ce..a29c103c3f 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -55,12 +55,12 @@ class MempoolLimitTest(BitcoinTestFramework): self.generate(node, 1) # tx_A needs to be RBF'd, set minfee at set size - A_weight = 1000 + A_vsize = 250 mempoolmin_feerate = node.getmempoolinfo()["mempoolminfee"] tx_A = self.wallet.send_self_transfer( from_node=node, - fee=(mempoolmin_feerate / 1000) * (A_weight // 4) + Decimal('0.000001'), - target_weight=A_weight, + fee_rate=mempoolmin_feerate, + target_vsize=A_vsize, utxo_to_spend=rbf_utxo, confirmed_only=True ) @@ -68,16 +68,16 @@ class MempoolLimitTest(BitcoinTestFramework): # RBF's tx_A, is not yet submitted tx_B = self.wallet.create_self_transfer( fee=tx_A["fee"] * 4, - target_weight=A_weight, + target_vsize=A_vsize, utxo_to_spend=rbf_utxo, confirmed_only=True ) # Spends tx_B's output, too big for cpfp carveout (because that would also increase the descendant limit by 1) - non_cpfp_carveout_weight = 40001 # EXTRA_DESCENDANT_TX_SIZE_LIMIT + 1 + non_cpfp_carveout_vsize = 10001 # EXTRA_DESCENDANT_TX_SIZE_LIMIT + 1 tx_C = self.wallet.create_self_transfer( - target_weight=non_cpfp_carveout_weight, - fee = (mempoolmin_feerate / 1000) * (non_cpfp_carveout_weight // 4) + Decimal('0.000001'), + target_vsize=non_cpfp_carveout_vsize, + fee_rate=mempoolmin_feerate, utxo_to_spend=tx_B["new_utxo"], confirmed_only=True ) @@ -103,14 +103,14 @@ class MempoolLimitTest(BitcoinTestFramework): # UTXOs to be spent by the ultimate child transaction parent_utxos = [] - evicted_weight = 8000 + evicted_vsize = 2000 # Mempool transaction which is evicted due to being at the "bottom" of the mempool when the # mempool overflows and evicts by descendant score. It's important that the eviction doesn't # happen in the middle of package evaluation, as it can invalidate the coins cache. mempool_evicted_tx = self.wallet.send_self_transfer( from_node=node, - fee=(mempoolmin_feerate / 1000) * (evicted_weight // 4) + Decimal('0.000001'), - target_weight=evicted_weight, + fee_rate=mempoolmin_feerate, + target_vsize=evicted_vsize, confirmed_only=True ) # Already in mempool when package is submitted. @@ -132,14 +132,16 @@ class MempoolLimitTest(BitcoinTestFramework): # Series of parents that don't need CPFP and are submitted individually. Each one is large and # high feerate, which means they should trigger eviction but not be evicted. - parent_weight = 100000 + parent_vsize = 25000 num_big_parents = 3 - assert_greater_than(parent_weight * num_big_parents, current_info["maxmempool"] - current_info["bytes"]) - parent_fee = (100 * mempoolmin_feerate / 1000) * (parent_weight // 4) + # Need to be large enough to trigger eviction + # (note that the mempool usage of a tx is about three times its vsize) + assert_greater_than(parent_vsize * num_big_parents * 3, current_info["maxmempool"] - current_info["bytes"]) + parent_feerate = 100 * mempoolmin_feerate big_parent_txids = [] for i in range(num_big_parents): - parent = self.wallet.create_self_transfer(fee=parent_fee, target_weight=parent_weight, confirmed_only=True) + parent = self.wallet.create_self_transfer(fee_rate=parent_feerate, target_vsize=parent_vsize, confirmed_only=True) parent_utxos.append(parent["new_utxo"]) package_hex.append(parent["hex"]) big_parent_txids.append(parent["txid"]) @@ -311,21 +313,24 @@ class MempoolLimitTest(BitcoinTestFramework): entry = node.getmempoolentry(txid) worst_feerate_btcvb = min(worst_feerate_btcvb, entry["fees"]["descendant"] / entry["descendantsize"]) # Needs to be large enough to trigger eviction - target_weight_each = 200000 - assert_greater_than(target_weight_each * 2, node.getmempoolinfo()["maxmempool"] - node.getmempoolinfo()["bytes"]) + # (note that the mempool usage of a tx is about three times its vsize) + target_vsize_each = 50000 + assert_greater_than(target_vsize_each * 2 * 3, node.getmempoolinfo()["maxmempool"] - node.getmempoolinfo()["bytes"]) # Should be a true CPFP: parent's feerate is just below mempool min feerate - parent_fee = (mempoolmin_feerate / 1000) * (target_weight_each // 4) - Decimal("0.00001") + parent_feerate = mempoolmin_feerate - Decimal("0.000001") # 0.1 sats/vbyte below min feerate # Parent + child is above mempool minimum feerate - child_fee = (worst_feerate_btcvb) * (target_weight_each // 4) - Decimal("0.00001") + child_feerate = (worst_feerate_btcvb * 1000) - Decimal("0.000001") # 0.1 sats/vbyte below worst feerate # However, when eviction is triggered, these transactions should be at the bottom. # This assertion assumes parent and child are the same size. miniwallet.rescan_utxos() - tx_parent_just_below = miniwallet.create_self_transfer(fee=parent_fee, target_weight=target_weight_each) - tx_child_just_above = miniwallet.create_self_transfer(utxo_to_spend=tx_parent_just_below["new_utxo"], fee=child_fee, target_weight=target_weight_each) + tx_parent_just_below = miniwallet.create_self_transfer(fee_rate=parent_feerate, target_vsize=target_vsize_each) + tx_child_just_above = miniwallet.create_self_transfer(utxo_to_spend=tx_parent_just_below["new_utxo"], fee_rate=child_feerate, target_vsize=target_vsize_each) # This package ranks below the lowest descendant package in the mempool - assert_greater_than(worst_feerate_btcvb, (parent_fee + child_fee) / (tx_parent_just_below["tx"].get_vsize() + tx_child_just_above["tx"].get_vsize())) - assert_greater_than(mempoolmin_feerate, (parent_fee) / (tx_parent_just_below["tx"].get_vsize())) - assert_greater_than((parent_fee + child_fee) / (tx_parent_just_below["tx"].get_vsize() + tx_child_just_above["tx"].get_vsize()), mempoolmin_feerate / 1000) + package_fee = tx_parent_just_below["fee"] + tx_child_just_above["fee"] + package_vsize = tx_parent_just_below["tx"].get_vsize() + tx_child_just_above["tx"].get_vsize() + assert_greater_than(worst_feerate_btcvb, package_fee / package_vsize) + assert_greater_than(mempoolmin_feerate, tx_parent_just_below["fee"] / (tx_parent_just_below["tx"].get_vsize())) + assert_greater_than(package_fee / package_vsize, mempoolmin_feerate / 1000) res = node.submitpackage([tx_parent_just_below["hex"], tx_child_just_above["hex"]]) for wtxid in [tx_parent_just_below["wtxid"], tx_child_just_above["wtxid"]]: assert_equal(res["tx-results"][wtxid]["error"], "mempool full") @@ -340,4 +345,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..3290ff43c4 100755 --- a/test/functional/mempool_package_limits.py +++ b/test/functional/mempool_package_limits.py @@ -4,9 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test logic for limiting mempool and package ancestors/descendants.""" from test_framework.blocktools import COINBASE_MATURITY -from test_framework.messages import ( - WITNESS_SCALE_FACTOR, -) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -290,19 +287,18 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): parent_utxos = [] target_vsize = 30_000 high_fee = 10 * target_vsize # 10 sats/vB - target_weight = target_vsize * WITNESS_SCALE_FACTOR self.log.info("Check that in-mempool and in-package ancestor size limits are calculated properly in packages") # Mempool transactions A and B for _ in range(2): - bulked_tx = self.wallet.create_self_transfer(target_weight=target_weight) + bulked_tx = self.wallet.create_self_transfer(target_vsize=target_vsize) self.wallet.sendrawtransaction(from_node=node, tx_hex=bulked_tx["hex"]) parent_utxos.append(bulked_tx["new_utxo"]) # Package transaction C - pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=high_fee, target_weight=target_weight) + pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=high_fee, target_vsize=target_vsize) # Package transaction D - pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_weight=target_weight) + pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_vsize=target_vsize) assert_equal(2, node.getmempoolinfo()["size"]) return [pc_tx["hex"], pd_tx["hex"]] @@ -321,20 +317,19 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): node = self.nodes[0] target_vsize = 21_000 high_fee = 10 * target_vsize # 10 sats/vB - target_weight = target_vsize * WITNESS_SCALE_FACTOR self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages") # Top parent in mempool, Ma - ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_weight=target_weight) + ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_vsize=target_vsize) self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"]) package_hex = [] for j in range(2): # Two legs (left and right) # Mempool transaction (Mb and Mc) - mempool_tx = self.wallet.create_self_transfer(utxo_to_spend=ma_tx["new_utxos"][j], target_weight=target_weight) + mempool_tx = self.wallet.create_self_transfer(utxo_to_spend=ma_tx["new_utxos"][j], target_vsize=target_vsize) self.wallet.sendrawtransaction(from_node=node, tx_hex=mempool_tx["hex"]) # Package transaction (Pd and Pe) - package_tx = self.wallet.create_self_transfer(utxo_to_spend=mempool_tx["new_utxo"], target_weight=target_weight) + package_tx = self.wallet.create_self_transfer(utxo_to_spend=mempool_tx["new_utxo"], target_vsize=target_vsize) package_hex.append(package_tx["hex"]) assert_equal(3, node.getmempoolinfo()["size"]) @@ -343,4 +338,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 new file mode 100755 index 0000000000..a5b8fa5f87 --- /dev/null +++ b/test/functional/mempool_package_rbf.py @@ -0,0 +1,599 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from decimal import Decimal + +from test_framework.messages import ( + COIN, + MAX_BIP125_RBF_SEQUENCE, +) +from test_framework.test_framework import BitcoinTestFramework +from test_framework.mempool_util import fill_mempool +from test_framework.util import ( + assert_greater_than_or_equal, + assert_equal, +) +from test_framework.wallet import ( + DEFAULT_FEE, + MiniWallet, +) + +MAX_REPLACEMENT_CANDIDATES = 100 + +# Value high enough to cause evictions in each subtest +# for typical cases +DEFAULT_CHILD_FEE = DEFAULT_FEE * 4 + +class PackageRBFTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 2 + self.setup_clean_chain = True + # Required for fill_mempool() + self.extra_args = [[ + "-datacarriersize=100000", + "-maxmempool=5", + ]] * self.num_nodes + + def assert_mempool_contents(self, expected=None): + """Assert that all transactions in expected are in the mempool, + and no additional ones exist. + """ + if not expected: + expected = [] + mempool = self.nodes[0].getrawmempool(verbose=False) + assert_equal(len(mempool), len(expected)) + for tx in expected: + assert tx.rehash() in mempool + + def create_simple_package(self, parent_coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE, heavy_child=False): + """Create a 1 parent 1 child package using the coin passed in as the parent's input. The + parent has 1 output, used to fund 1 child transaction. + All transactions signal BIP125 replaceability, but nSequence changes based on self.ctr. This + prevents identical txids between packages when the parents spend the same coin and have the + same fee (i.e. 0sat). + + returns tuple (hex serialized txns, CTransaction objects) + """ + self.ctr += 1 + # Use fee_rate=0 because create_self_transfer will use the default fee_rate value otherwise. + # Passing in fee>0 overrides fee_rate, so this still works for non-zero parent_fee. + parent_result = self.wallet.create_self_transfer( + fee=parent_fee, + utxo_to_spend=parent_coin, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + num_child_outputs = 10 if heavy_child else 1 + child_result = self.wallet.create_self_transfer_multi( + utxos_to_spend=[parent_result["new_utxo"]], + num_outputs=num_child_outputs, + fee_per_output=int(child_fee * COIN // num_child_outputs), + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + package_hex = [parent_result["hex"], child_result["hex"]] + package_txns = [parent_result["tx"], child_result["tx"]] + return package_hex, package_txns + + def run_test(self): + # Counter used to count the number of times we constructed packages. Since we're constructing parent transactions with the same + # coins (to create conflicts), and perhaps giving them the same fee, we might accidentally just create the same transaction again. + # To prevent this, set nSequences to MAX_BIP125_RBF_SEQUENCE - self.ctr. + self.ctr = 0 + + self.log.info("Generate blocks to create UTXOs") + self.wallet = MiniWallet(self.nodes[0]) + + # Make more than enough coins for the sum of all tests, + # otherwise a wallet rescan is needed later + self.generate(self.wallet, 300) + self.coins = self.wallet.get_utxos(mark_as_spent=False) + + self.test_package_rbf_basic() + self.test_package_rbf_singleton() + self.test_package_rbf_additional_fees() + self.test_package_rbf_max_conflicts() + self.test_too_numerous_ancestors() + self.test_package_rbf_with_wrong_pkg_size() + self.test_insufficient_feerate() + self.test_wrong_conflict_cluster_size_linear() + self.test_wrong_conflict_cluster_size_parents_child() + self.test_wrong_conflict_cluster_size_parent_children() + self.test_0fee_package_rbf() + self.test_child_conflicts_parent_mempool_ancestor() + + def test_package_rbf_basic(self): + self.log.info("Test that a child can pay to replace its parents' conflicts of cluster size 2") + node = self.nodes[0] + # Reuse the same coins so that the transactions conflict with one another. + parent_coin = self.coins.pop() + package_hex1, package_txns1 = self.create_simple_package(parent_coin, DEFAULT_FEE, DEFAULT_FEE) + package_hex2, package_txns2 = self.create_simple_package(parent_coin, DEFAULT_FEE, DEFAULT_CHILD_FEE) + node.submitpackage(package_hex1) + self.assert_mempool_contents(expected=package_txns1) + + # Make sure 2nd node gets set up for basic package RBF + self.sync_all() + + # Test run rejected because conflicts are not allowed in subpackage evaluation + testres = node.testmempoolaccept(package_hex2) + assert_equal(testres[0]["reject-reason"], "bip125-replacement-disallowed") + + # But accepted during normal submission + submitres = node.submitpackage(package_hex2) + assert_equal(set(submitres["replaced-transactions"]), set([tx.rehash() for tx in package_txns1])) + self.assert_mempool_contents(expected=package_txns2) + + # Make sure 2nd node gets a basic package RBF over p2p + self.sync_all() + + self.generate(node, 1) + + def test_package_rbf_singleton(self): + self.log.info("Test child can pay to replace a parent's single conflicted tx") + node = self.nodes[0] + + # Make singleton tx to conflict with in next batch + singleton_coin = self.coins.pop() + singleton_tx = self.wallet.create_self_transfer(utxo_to_spend=singleton_coin) + node.sendrawtransaction(singleton_tx["hex"]) + self.assert_mempool_contents(expected=[singleton_tx["tx"]]) + + package_hex, package_txns = self.create_simple_package(singleton_coin, DEFAULT_FEE, singleton_tx["fee"] * 2) + + submitres = node.submitpackage(package_hex) + assert_equal(submitres["replaced-transactions"], [singleton_tx["tx"].rehash()]) + self.assert_mempool_contents(expected=package_txns) + + self.generate(node, 1) + + def test_package_rbf_additional_fees(self): + self.log.info("Check Package RBF must increase the absolute fee") + node = self.nodes[0] + coin = self.coins.pop() + + package_hex1, package_txns1 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE, heavy_child=True) + assert_greater_than_or_equal(1000, package_txns1[-1].get_vsize()) + node.submitpackage(package_hex1) + self.assert_mempool_contents(expected=package_txns1) + + PACKAGE_FEE = DEFAULT_FEE + DEFAULT_CHILD_FEE + PACKAGE_FEE_MINUS_ONE = PACKAGE_FEE - Decimal("0.00000001") + + # Package 2 has a higher feerate but lower absolute fee + package_hex2, package_txns2 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE - Decimal("0.00000001")) + pkg_results2 = node.submitpackage(package_hex2) + assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {package_txns2[1].rehash()}, less fees than conflicting txs; {PACKAGE_FEE_MINUS_ONE} < {PACKAGE_FEE}", pkg_results2["package_msg"]) + self.assert_mempool_contents(expected=package_txns1) + + self.log.info("Check replacement pays for incremental bandwidth") + _, 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") + coin = self.coins.pop() + 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) + pkg_results5 = node.submitpackage(package_hex5) + 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): + node = self.nodes[0] + self.log.info("Check Package RBF cannot replace more than MAX_REPLACEMENT_CANDIDATES transactions") + num_coins = 51 + parent_coins = self.coins[:num_coins] + del self.coins[:num_coins] + + # Original transactions: 51 transactions with 1 descendants each -> 102 total transactions + size_two_clusters = [] + for coin in parent_coins: + size_two_clusters.append(self.wallet.send_self_transfer_chain(from_node=node, chain_length=2, utxo_to_spend=coin)) + expected_txns = [txn["tx"] for parent_child_txns in size_two_clusters for txn in parent_child_txns] + assert_equal(len(expected_txns), num_coins * 2) + self.assert_mempool_contents(expected=expected_txns) + + # parent feeerate needs to be high enough for minrelay + # child feerate needs to be large enough to trigger package rbf with a very large parent and + # pay for all evicted fees. maxfeerate turned off for all submissions since child feerate + # is extremely high + parent_fee_per_conflict = 10000 + child_feerate = 10000 * DEFAULT_FEE + + # Conflict against all transactions by double-spending each parent, causing 102 evictions + package_parent = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_coins, fee_per_output=parent_fee_per_conflict) + package_child = self.wallet.create_self_transfer(fee_rate=child_feerate, utxo_to_spend=package_parent["new_utxos"][0]) + + pkg_results = node.submitpackage([package_parent["hex"], package_child["hex"]], maxfeerate=0) + assert_equal(f"package RBF failed: too many potential replacements, rejecting replacement {package_child['tx'].rehash()}; too many potential replacements (102 > 100)\n", pkg_results["package_msg"]) + self.assert_mempool_contents(expected=expected_txns) + + # Make singleton tx to conflict with in next batch + singleton_coin = self.coins.pop() + singleton_tx = self.wallet.create_self_transfer(utxo_to_spend=singleton_coin) + node.sendrawtransaction(singleton_tx["hex"]) + expected_txns.append(singleton_tx["tx"]) + + # Double-spend same set minus last, and double-spend singleton. This hits 101 evictions; should still fail. + # N.B. we can't RBF just a child tx in the clusters, as that would make resulting cluster of size 3. + double_spending_coins = parent_coins[:-1] + [singleton_coin] + package_parent = self.wallet.create_self_transfer_multi(utxos_to_spend=double_spending_coins, fee_per_output=parent_fee_per_conflict) + package_child = self.wallet.create_self_transfer(fee_rate=child_feerate, utxo_to_spend=package_parent["new_utxos"][0]) + pkg_results = node.submitpackage([package_parent["hex"], package_child["hex"]], maxfeerate=0) + assert_equal(f"package RBF failed: too many potential replacements, rejecting replacement {package_child['tx'].rehash()}; too many potential replacements (101 > 100)\n", pkg_results["package_msg"]) + self.assert_mempool_contents(expected=expected_txns) + + # Finally, evict MAX_REPLACEMENT_CANDIDATES + package_parent = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_coins[:-1], fee_per_output=parent_fee_per_conflict) + package_child = self.wallet.create_self_transfer(fee_rate=child_feerate, utxo_to_spend=package_parent["new_utxos"][0]) + pkg_results = node.submitpackage([package_parent["hex"], package_child["hex"]], maxfeerate=0) + assert_equal(pkg_results["package_msg"], "success") + self.assert_mempool_contents(expected=[singleton_tx["tx"], size_two_clusters[-1][0]["tx"], size_two_clusters[-1][1]["tx"], package_parent["tx"], package_child["tx"]] ) + + self.generate(node, 1) + + def test_too_numerous_ancestors(self): + self.log.info("Test that package RBF doesn't work with packages larger than 2 due to ancestors") + node = self.nodes[0] + coin = self.coins.pop() + + package_hex1, package_txns1 = self.create_simple_package(coin, DEFAULT_FEE, DEFAULT_CHILD_FEE) + node.submitpackage(package_hex1) + self.assert_mempool_contents(expected=package_txns1) + + # Double-spends the original package + self.ctr += 1 + parent_result1 = self.wallet.create_self_transfer( + fee=DEFAULT_FEE, + utxo_to_spend=coin, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + coin2 = self.coins.pop() + + # Added to make package too large for package RBF; + # it will enter mempool individually + self.ctr += 1 + parent_result2 = self.wallet.create_self_transfer( + fee=DEFAULT_FEE, + utxo_to_spend=coin2, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + # Child that spends both, violating cluster size rule due + # to in-mempool ancestry + self.ctr += 1 + child_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_CHILD_FEE * COIN), + utxos_to_spend=[parent_result1["new_utxo"], parent_result2["new_utxo"]], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + package_hex2 = [parent_result1["hex"], parent_result2["hex"], child_result["hex"]] + package_txns2_succeed = [parent_result2["tx"]] + + pkg_result = node.submitpackage(package_hex2) + assert_equal(pkg_result["package_msg"], 'package RBF failed: new transaction cannot have mempool ancestors') + self.assert_mempool_contents(expected=package_txns1 + package_txns2_succeed) + self.generate(node, 1) + + def test_wrong_conflict_cluster_size_linear(self): + self.log.info("Test that conflicting with a cluster not sized two is rejected: linear chain") + node = self.nodes[0] + + # Coins we will conflict with + coin1 = self.coins.pop() + coin2 = self.coins.pop() + coin3 = self.coins.pop() + + # Three transactions chained; package RBF against any of these + # should be rejected + self.ctr += 1 + parent_result = self.wallet.create_self_transfer( + fee=DEFAULT_FEE, + utxo_to_spend=coin1, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + self.ctr += 1 + child_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_FEE * COIN), + utxos_to_spend=[parent_result["new_utxo"], coin2], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + self.ctr += 1 + grandchild_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_FEE * COIN), + utxos_to_spend=[child_result["new_utxos"][0], coin3], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + expected_txns = [parent_result["tx"], child_result["tx"], grandchild_result["tx"]] + for tx in expected_txns: + node.sendrawtransaction(tx.serialize().hex()) + self.assert_mempool_contents(expected=expected_txns) + + # Now make conflicting packages for each coin + package_hex1, _package_txns1 = self.create_simple_package(coin1, DEFAULT_FEE, DEFAULT_CHILD_FEE) + + package_result = node.submitpackage(package_hex1) + assert_equal(f"package RBF failed: {parent_result['tx'].rehash()} has 2 descendants, max 1 allowed", package_result["package_msg"]) + + package_hex2, _package_txns2 = self.create_simple_package(coin2, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex2) + assert_equal(f"package RBF failed: {child_result['tx'].rehash()} has both ancestor and descendant, exceeding cluster limit of 2", package_result["package_msg"]) + + package_hex3, _package_txns3 = self.create_simple_package(coin3, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex3) + assert_equal(f"package RBF failed: {grandchild_result['tx'].rehash()} has 2 ancestors, max 1 allowed", package_result["package_msg"]) + + # Check that replacements were actually rejected + self.assert_mempool_contents(expected=expected_txns) + self.generate(node, 1) + + def test_wrong_conflict_cluster_size_parents_child(self): + self.log.info("Test that conflicting with a cluster not sized two is rejected: two parents one child") + node = self.nodes[0] + + # Coins we will conflict with + coin1 = self.coins.pop() + coin2 = self.coins.pop() + coin3 = self.coins.pop() + + self.ctr += 1 + parent1_result = self.wallet.create_self_transfer( + fee=DEFAULT_FEE, + utxo_to_spend=coin1, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + self.ctr += 1 + parent2_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_FEE * COIN), + utxos_to_spend=[coin2], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + self.ctr += 1 + child_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_FEE * COIN), + utxos_to_spend=[parent1_result["new_utxo"], parent2_result["new_utxos"][0], coin3], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + expected_txns = [parent1_result["tx"], parent2_result["tx"], child_result["tx"]] + for tx in expected_txns: + node.sendrawtransaction(tx.serialize().hex()) + self.assert_mempool_contents(expected=expected_txns) + + # Now make conflicting packages for each coin + package_hex1, _package_txns1 = self.create_simple_package(coin1, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex1) + assert_equal(f"package RBF failed: {parent1_result['tx'].rehash()} is not the only parent of child {child_result['tx'].rehash()}", package_result["package_msg"]) + + package_hex2, _package_txns2 = self.create_simple_package(coin2, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex2) + assert_equal(f"package RBF failed: {parent2_result['tx'].rehash()} is not the only parent of child {child_result['tx'].rehash()}", package_result["package_msg"]) + + package_hex3, _package_txns3 = self.create_simple_package(coin3, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex3) + assert_equal(f"package RBF failed: {child_result['tx'].rehash()} has 2 ancestors, max 1 allowed", package_result["package_msg"]) + + # Check that replacements were actually rejected + self.assert_mempool_contents(expected=expected_txns) + self.generate(node, 1) + + def test_wrong_conflict_cluster_size_parent_children(self): + self.log.info("Test that conflicting with a cluster not sized two is rejected: one parent two children") + node = self.nodes[0] + + # Coins we will conflict with + coin1 = self.coins.pop() + coin2 = self.coins.pop() + coin3 = self.coins.pop() + + self.ctr += 1 + parent_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_FEE * COIN), + num_outputs=2, + utxos_to_spend=[coin1], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + self.ctr += 1 + child1_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_FEE * COIN), + utxos_to_spend=[parent_result["new_utxos"][0], coin2], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + self.ctr += 1 + child2_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_FEE * COIN), + utxos_to_spend=[parent_result["new_utxos"][1], coin3], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + # Submit them to mempool + expected_txns = [parent_result["tx"], child1_result["tx"], child2_result["tx"]] + for tx in expected_txns: + node.sendrawtransaction(tx.serialize().hex()) + self.assert_mempool_contents(expected=expected_txns) + + # Now make conflicting packages for each coin + package_hex1, _package_txns1 = self.create_simple_package(coin1, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex1) + assert_equal(f"package RBF failed: {parent_result['tx'].rehash()} has 2 descendants, max 1 allowed", package_result["package_msg"]) + + package_hex2, _package_txns2 = self.create_simple_package(coin2, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex2) + assert_equal(f"package RBF failed: {child1_result['tx'].rehash()} is not the only child of parent {parent_result['tx'].rehash()}", package_result["package_msg"]) + + package_hex3, _package_txns3 = self.create_simple_package(coin3, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_result = node.submitpackage(package_hex3) + assert_equal(f"package RBF failed: {child2_result['tx'].rehash()} is not the only child of parent {parent_result['tx'].rehash()}", package_result["package_msg"]) + + # Check that replacements were actually rejected + self.assert_mempool_contents(expected=expected_txns) + self.generate(node, 1) + + def test_package_rbf_with_wrong_pkg_size(self): + self.log.info("Test that package RBF doesn't work with packages larger than 2 due to pkg size") + node = self.nodes[0] + coin1 = self.coins.pop() + coin2 = self.coins.pop() + + # Two packages to require multiple direct conflicts, easier to set up illicit pkg size + package_hex1, package_txns1 = self.create_simple_package(coin1, DEFAULT_FEE, DEFAULT_CHILD_FEE) + package_hex2, package_txns2 = self.create_simple_package(coin2, DEFAULT_FEE, DEFAULT_CHILD_FEE) + + node.submitpackage(package_hex1) + node.submitpackage(package_hex2) + + self.assert_mempool_contents(expected=package_txns1 + package_txns2) + assert_equal(len(node.getrawmempool()), 4) + + # Double-spends the first package + self.ctr += 1 + parent_result1 = self.wallet.create_self_transfer( + fee=DEFAULT_FEE, + utxo_to_spend=coin1, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + # Double-spends the second package + self.ctr += 1 + parent_result2 = self.wallet.create_self_transfer( + fee=DEFAULT_FEE, + utxo_to_spend=coin2, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + # Child that spends both, violating cluster size rule due + # to pkg size + self.ctr += 1 + child_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_CHILD_FEE * COIN), + utxos_to_spend=[parent_result1["new_utxo"], parent_result2["new_utxo"]], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + package_hex3 = [parent_result1["hex"], parent_result2["hex"], child_result["hex"]] + + pkg_result = node.submitpackage(package_hex3) + assert_equal(pkg_result["package_msg"], 'package RBF failed: package must be 1-parent-1-child') + self.assert_mempool_contents(expected=package_txns1 + package_txns2) + self.generate(node, 1) + + def test_insufficient_feerate(self): + self.log.info("Check Package RBF must beat feerate of direct conflict") + node = self.nodes[0] + coin = self.coins.pop() + + # Non-cpfp structure + package_hex1, package_txns1 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE, child_fee=DEFAULT_FEE) + node.submitpackage(package_hex1) + self.assert_mempool_contents(expected=package_txns1) + + # Package 2 feerate is below the feerate of directly conflicted parent, so it fails even though + # total fees are higher than the original package + package_hex2, _package_txns2 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE - Decimal("0.00000001"), child_fee=DEFAULT_CHILD_FEE) + pkg_results2 = node.submitpackage(package_hex2) + assert_equal(pkg_results2["package_msg"], 'package RBF failed: insufficient feerate: does not improve feerate diagram') + self.assert_mempool_contents(expected=package_txns1) + self.generate(node, 1) + + def test_0fee_package_rbf(self): + self.log.info("Test package RBF: TRUC 0-fee parent + high-fee child replaces parent's conflicts") + node = self.nodes[0] + # Reuse the same coins so that the transactions conflict with one another. + self.wallet.rescan_utxos() + parent_coin = self.wallet.get_utxo(confirmed_only=True) + + # package1 pays default fee on both transactions + parent1 = self.wallet.create_self_transfer(utxo_to_spend=parent_coin, version=3) + child1 = self.wallet.create_self_transfer(utxo_to_spend=parent1["new_utxo"], version=3) + package_hex1 = [parent1["hex"], child1["hex"]] + fees_package1 = parent1["fee"] + child1["fee"] + submitres1 = node.submitpackage(package_hex1) + assert_equal(submitres1["package_msg"], "success") + self.assert_mempool_contents([parent1["tx"], child1["tx"]]) + + # package2 has a 0-fee parent (conflicting with package1) and very high fee child + parent2 = self.wallet.create_self_transfer(utxo_to_spend=parent_coin, fee=0, fee_rate=0, version=3) + child2 = self.wallet.create_self_transfer(utxo_to_spend=parent2["new_utxo"], fee=fees_package1*10, version=3) + package_hex2 = [parent2["hex"], child2["hex"]] + + submitres2 = node.submitpackage(package_hex2) + assert_equal(submitres2["package_msg"], "success") + assert_equal(set(submitres2["replaced-transactions"]), set([parent1["txid"], child1["txid"]])) + self.assert_mempool_contents([parent2["tx"], child2["tx"]]) + + self.generate(node, 1) + + def test_child_conflicts_parent_mempool_ancestor(self): + fill_mempool(self, self.nodes[0], tx_sync_fun=self.no_op) + # Reset coins since we filled the mempool with current coins + self.coins = self.wallet.get_utxos(mark_as_spent=False, confirmed_only=True) + + self.log.info("Test that package RBF doesn't have issues with mempool<->package conflicts via inconsistency") + node = self.nodes[0] + coin = self.coins.pop() + + self.ctr += 1 + grandparent_result = self.wallet.create_self_transfer( + fee=DEFAULT_FEE, + utxo_to_spend=coin, + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + node.sendrawtransaction(grandparent_result["hex"]) + + # Now make package of two descendants that looks + # like a cpfp where the parent can't get in on its own + self.ctr += 1 + parent_result = self.wallet.create_self_transfer( + fee_rate=Decimal('0.00001000'), + utxo_to_spend=grandparent_result["new_utxo"], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + # Last tx double-spends grandparent's coin, + # which is not inside the current package + self.ctr += 1 + child_result = self.wallet.create_self_transfer_multi( + fee_per_output=int(DEFAULT_CHILD_FEE * COIN), + utxos_to_spend=[parent_result["new_utxo"], coin], + sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, + ) + + pkg_result = node.submitpackage([parent_result["hex"], child_result["hex"]]) + assert_equal(pkg_result["package_msg"], 'package RBF failed: new transaction cannot have mempool ancestors') + mempool_info = node.getrawmempool() + assert grandparent_result["txid"] in mempool_info + assert parent_result["txid"] not in mempool_info + assert child_result["txid"] not in mempool_info + +if __name__ == "__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..47df0c614a 100755 --- a/test/functional/mempool_sigoplimit.py +++ b/test/functional/mempool_sigoplimit.py @@ -154,7 +154,7 @@ class BytesPerSigOpTest(BitcoinTestFramework): return (tx_utxo, tx) tx_parent_utxo, tx_parent = create_bare_multisig_tx() - tx_child_utxo, tx_child = create_bare_multisig_tx(tx_parent_utxo) + _tx_child_utxo, tx_child = create_bare_multisig_tx(tx_parent_utxo) # Separately, the parent tx is ok parent_individual_testres = self.nodes[0].testmempoolaccept([tx_parent.serialize().hex()])[0] @@ -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_accept_v3.py b/test/functional/mempool_truc.py index 6b0ba0812b..54a258215d 100755 --- a/test/functional/mempool_accept_v3.py +++ b/test/functional/mempool_truc.py @@ -6,7 +6,6 @@ from decimal import Decimal from test_framework.messages import ( MAX_BIP125_RBF_SEQUENCE, - WITNESS_SCALE_FACTOR, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -22,7 +21,8 @@ from test_framework.wallet import ( ) MAX_REPLACEMENT_CANDIDATES = 100 -V3_MAX_VSIZE = 10000 +TRUC_MAX_VSIZE = 10000 +TRUC_CHILD_MAX_VSIZE = 1000 def cleanup(extra_args=None): def decorator(func): @@ -39,10 +39,10 @@ def cleanup(extra_args=None): return wrapper return decorator -class MempoolAcceptV3(BitcoinTestFramework): +class MempoolTRUC(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [["-acceptnonstdtxn=1"]] + self.extra_args = [[]] self.setup_clean_chain = True def check_mempool(self, txids): @@ -51,64 +51,65 @@ class MempoolAcceptV3(BitcoinTestFramework): assert_equal(len(txids), len(mempool_contents)) assert all([txid in txids for txid in mempool_contents]) - @cleanup(extra_args=["-datacarriersize=20000", "-acceptnonstdtxn=1"]) - def test_v3_max_vsize(self): + @cleanup(extra_args=["-datacarriersize=20000"]) + def test_truc_max_vsize(self): node = self.nodes[0] - self.log.info("Test v3-specific maximum transaction vsize") - tx_v3_heavy = self.wallet.create_self_transfer(target_weight=(V3_MAX_VSIZE + 1) * WITNESS_SCALE_FACTOR, version=3) - assert_greater_than_or_equal(tx_v3_heavy["tx"].get_vsize(), V3_MAX_VSIZE) - expected_error_heavy = f"v3-rule-violation, v3 tx {tx_v3_heavy['txid']} (wtxid={tx_v3_heavy['wtxid']}) is too big" + self.log.info("Test TRUC-specific maximum transaction vsize") + tx_v3_heavy = self.wallet.create_self_transfer(target_vsize=TRUC_MAX_VSIZE + 1, version=3) + assert_greater_than_or_equal(tx_v3_heavy["tx"].get_vsize(), TRUC_MAX_VSIZE) + expected_error_heavy = f"TRUC-violation, version=3 tx {tx_v3_heavy['txid']} (wtxid={tx_v3_heavy['wtxid']}) is too big" assert_raises_rpc_error(-26, expected_error_heavy, node.sendrawtransaction, tx_v3_heavy["hex"]) self.check_mempool([]) - # Ensure we are hitting the v3-specific limit and not something else - tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_weight=(V3_MAX_VSIZE + 1) * WITNESS_SCALE_FACTOR, version=2) + # Ensure we are hitting the TRUC-specific limit and not something else + tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_vsize=TRUC_MAX_VSIZE + 1, version=2) self.check_mempool([tx_v2_heavy["txid"]]) - @cleanup(extra_args=["-datacarriersize=1000", "-acceptnonstdtxn=1"]) - def test_v3_acceptance(self): + @cleanup(extra_args=["-datacarriersize=1000"]) + def test_truc_acceptance(self): node = self.nodes[0] - self.log.info("Test a child of a v3 transaction cannot be more than 1000vB") + self.log.info("Test a child of a TRUC transaction cannot be more than 1000vB") tx_v3_parent_normal = self.wallet.send_self_transfer(from_node=node, version=3) self.check_mempool([tx_v3_parent_normal["txid"]]) tx_v3_child_heavy = self.wallet.create_self_transfer( utxo_to_spend=tx_v3_parent_normal["new_utxo"], - target_weight=4004, + target_vsize=TRUC_CHILD_MAX_VSIZE + 1, version=3 ) - assert_greater_than_or_equal(tx_v3_child_heavy["tx"].get_vsize(), 1000) - expected_error_child_heavy = f"v3-rule-violation, v3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big" + assert_greater_than_or_equal(tx_v3_child_heavy["tx"].get_vsize(), TRUC_CHILD_MAX_VSIZE) + expected_error_child_heavy = f"TRUC-violation, version=3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big" assert_raises_rpc_error(-26, expected_error_child_heavy, node.sendrawtransaction, tx_v3_child_heavy["hex"]) self.check_mempool([tx_v3_parent_normal["txid"]]) # tx has no descendants assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 1) - self.log.info("Test that, during replacements, only the new transaction counts for v3 descendant limit") + self.log.info("Test that, during replacements, only the new transaction counts for TRUC descendant limit") tx_v3_child_almost_heavy = self.wallet.send_self_transfer( from_node=node, fee_rate=DEFAULT_FEE, utxo_to_spend=tx_v3_parent_normal["new_utxo"], - target_weight=3987, + target_vsize=TRUC_CHILD_MAX_VSIZE - 3, version=3 ) - assert_greater_than_or_equal(1000, tx_v3_child_almost_heavy["tx"].get_vsize()) + assert_greater_than_or_equal(TRUC_CHILD_MAX_VSIZE, tx_v3_child_almost_heavy["tx"].get_vsize()) self.check_mempool([tx_v3_parent_normal["txid"], tx_v3_child_almost_heavy["txid"]]) assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 2) tx_v3_child_almost_heavy_rbf = self.wallet.send_self_transfer( from_node=node, fee_rate=DEFAULT_FEE * 2, utxo_to_spend=tx_v3_parent_normal["new_utxo"], - target_weight=3500, + target_vsize=875, version=3 ) - assert_greater_than_or_equal(tx_v3_child_almost_heavy["tx"].get_vsize() + tx_v3_child_almost_heavy_rbf["tx"].get_vsize(), 1000) + assert_greater_than_or_equal(tx_v3_child_almost_heavy["tx"].get_vsize() + tx_v3_child_almost_heavy_rbf["tx"].get_vsize(), + TRUC_CHILD_MAX_VSIZE) self.check_mempool([tx_v3_parent_normal["txid"], tx_v3_child_almost_heavy_rbf["txid"]]) assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 2) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) - def test_v3_replacement(self): + @cleanup(extra_args=None) + def test_truc_replacement(self): node = self.nodes[0] - self.log.info("Test v3 transactions may be replaced by v3 transactions") + self.log.info("Test TRUC transactions may be replaced by TRUC transactions") utxo_v3_bip125 = self.wallet.get_utxo() tx_v3_bip125 = self.wallet.send_self_transfer( from_node=node, @@ -127,7 +128,7 @@ class MempoolAcceptV3(BitcoinTestFramework): ) self.check_mempool([tx_v3_bip125_rbf["txid"]]) - self.log.info("Test v3 transactions may be replaced by V2 transactions") + self.log.info("Test TRUC transactions may be replaced by non-TRUC (BIP125) transactions") tx_v3_bip125_rbf_v2 = self.wallet.send_self_transfer( from_node=node, fee_rate=DEFAULT_FEE * 3, @@ -136,7 +137,7 @@ class MempoolAcceptV3(BitcoinTestFramework): ) self.check_mempool([tx_v3_bip125_rbf_v2["txid"]]) - self.log.info("Test that replacements cannot cause violation of inherited v3") + self.log.info("Test that replacements cannot cause violation of inherited TRUC") utxo_v3_parent = self.wallet.get_utxo() tx_v3_parent = self.wallet.send_self_transfer( from_node=node, @@ -157,15 +158,15 @@ class MempoolAcceptV3(BitcoinTestFramework): utxo_to_spend=tx_v3_parent["new_utxo"], version=2 ) - expected_error_v2_v3 = f"v3-rule-violation, non-v3 tx {tx_v3_child_rbf_v2['txid']} (wtxid={tx_v3_child_rbf_v2['wtxid']}) cannot spend from v3 tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']})" + expected_error_v2_v3 = f"TRUC-violation, non-version=3 tx {tx_v3_child_rbf_v2['txid']} (wtxid={tx_v3_child_rbf_v2['wtxid']}) cannot spend from version=3 tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']})" assert_raises_rpc_error(-26, expected_error_v2_v3, node.sendrawtransaction, tx_v3_child_rbf_v2["hex"]) self.check_mempool([tx_v3_bip125_rbf_v2["txid"], tx_v3_parent["txid"], tx_v3_child["txid"]]) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) - def test_v3_bip125(self): + @cleanup(extra_args=["-mempoolfullrbf=0"]) + def test_truc_bip125(self): node = self.nodes[0] - self.log.info("Test v3 transactions that don't signal BIP125 are replaceable") + self.log.info("Test TRUC transactions that don't signal BIP125 are replaceable") assert_equal(node.getmempoolinfo()["fullrbf"], False) utxo_v3_no_bip125 = self.wallet.get_utxo() tx_v3_no_bip125 = self.wallet.send_self_transfer( @@ -186,10 +187,10 @@ class MempoolAcceptV3(BitcoinTestFramework): ) self.check_mempool([tx_v3_no_bip125_rbf["txid"]]) - @cleanup(extra_args=["-datacarriersize=40000", "-acceptnonstdtxn=1"]) - def test_v3_reorg(self): + @cleanup(extra_args=["-datacarriersize=40000"]) + def test_truc_reorg(self): node = self.nodes[0] - self.log.info("Test that, during a reorg, v3 rules are not enforced") + self.log.info("Test that, during a reorg, TRUC rules are not enforced") tx_v2_block = self.wallet.send_self_transfer(from_node=node, version=2) tx_v3_block = self.wallet.send_self_transfer(from_node=node, version=3) tx_v3_block2 = self.wallet.send_self_transfer(from_node=node, version=3) @@ -199,8 +200,8 @@ class MempoolAcceptV3(BitcoinTestFramework): self.check_mempool([]) tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2) tx_v3_from_v2 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v2_block["new_utxo"], version=3) - tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_weight=5000, version=3) - assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], 1000) + tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_vsize=1250, version=3) + assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], TRUC_CHILD_MAX_VSIZE) self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) node.invalidateblock(block[0]) self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) @@ -208,31 +209,31 @@ class MempoolAcceptV3(BitcoinTestFramework): node.reconsiderblock(block[0]) - @cleanup(extra_args=["-limitdescendantsize=10", "-datacarriersize=40000", "-acceptnonstdtxn=1"]) + @cleanup(extra_args=["-limitdescendantsize=10", "-datacarriersize=40000"]) def test_nondefault_package_limits(self): """ - Max standard tx size + v3 rules imply the ancestor/descendant rules (at their default + Max standard tx size + TRUC rules imply the ancestor/descendant rules (at their default values), but those checks must not be skipped. Ensure both sets of checks are done by changing the ancestor/descendant limit configurations. """ node = self.nodes[0] - self.log.info("Test that a decreased limitdescendantsize also applies to v3 child") - parent_target_weight = 9990 * WITNESS_SCALE_FACTOR - child_target_weight = 500 * WITNESS_SCALE_FACTOR + self.log.info("Test that a decreased limitdescendantsize also applies to TRUC child") + parent_target_vsize = 9990 + child_target_vsize = 500 tx_v3_parent_large1 = self.wallet.send_self_transfer( from_node=node, - target_weight=parent_target_weight, + target_vsize=parent_target_vsize, version=3 ) tx_v3_child_large1 = self.wallet.create_self_transfer( utxo_to_spend=tx_v3_parent_large1["new_utxo"], - target_weight=child_target_weight, + target_vsize=child_target_vsize, version=3 ) # Parent and child are within v3 limits, but parent's 10kvB descendant limit is exceeded - assert_greater_than_or_equal(V3_MAX_VSIZE, tx_v3_parent_large1["tx"].get_vsize()) - assert_greater_than_or_equal(1000, tx_v3_child_large1["tx"].get_vsize()) + assert_greater_than_or_equal(TRUC_MAX_VSIZE, tx_v3_parent_large1["tx"].get_vsize()) + assert_greater_than_or_equal(TRUC_CHILD_MAX_VSIZE, tx_v3_child_large1["tx"].get_vsize()) assert_greater_than(tx_v3_parent_large1["tx"].get_vsize() + tx_v3_child_large1["tx"].get_vsize(), 10000) assert_raises_rpc_error(-26, f"too-long-mempool-chain, exceeds descendant size limit for tx {tx_v3_parent_large1['txid']}", node.sendrawtransaction, tx_v3_child_large1["hex"]) @@ -241,38 +242,38 @@ class MempoolAcceptV3(BitcoinTestFramework): self.generate(node, 1) self.log.info("Test that a decreased limitancestorsize also applies to v3 parent") - self.restart_node(0, extra_args=["-limitancestorsize=10", "-datacarriersize=40000", "-acceptnonstdtxn=1"]) + self.restart_node(0, extra_args=["-limitancestorsize=10", "-datacarriersize=40000"]) tx_v3_parent_large2 = self.wallet.send_self_transfer( from_node=node, - target_weight=parent_target_weight, + target_vsize=parent_target_vsize, version=3 ) tx_v3_child_large2 = self.wallet.create_self_transfer( utxo_to_spend=tx_v3_parent_large2["new_utxo"], - target_weight=child_target_weight, + target_vsize=child_target_vsize, version=3 ) - # Parent and child are within v3 limits - assert_greater_than_or_equal(V3_MAX_VSIZE, tx_v3_parent_large2["tx"].get_vsize()) - assert_greater_than_or_equal(1000, tx_v3_child_large2["tx"].get_vsize()) + # Parent and child are within TRUC limits + assert_greater_than_or_equal(TRUC_MAX_VSIZE, tx_v3_parent_large2["tx"].get_vsize()) + assert_greater_than_or_equal(TRUC_CHILD_MAX_VSIZE, tx_v3_child_large2["tx"].get_vsize()) assert_greater_than(tx_v3_parent_large2["tx"].get_vsize() + tx_v3_child_large2["tx"].get_vsize(), 10000) assert_raises_rpc_error(-26, f"too-long-mempool-chain, exceeds ancestor size limit", node.sendrawtransaction, tx_v3_child_large2["hex"]) self.check_mempool([tx_v3_parent_large2["txid"]]) - @cleanup(extra_args=["-datacarriersize=1000", "-acceptnonstdtxn=1"]) - def test_v3_ancestors_package(self): - self.log.info("Test that v3 ancestor limits are checked within the package") + @cleanup(extra_args=["-datacarriersize=1000"]) + def test_truc_ancestors_package(self): + self.log.info("Test that TRUC ancestor limits are checked within the package") node = self.nodes[0] tx_v3_parent_normal = self.wallet.create_self_transfer( fee_rate=0, - target_weight=4004, + target_vsize=1001, version=3 ) tx_v3_parent_2_normal = self.wallet.create_self_transfer( fee_rate=0, - target_weight=4004, + target_vsize=1001, version=3 ) tx_v3_child_multiparent = self.wallet.create_self_transfer_multi( @@ -282,41 +283,41 @@ class MempoolAcceptV3(BitcoinTestFramework): ) tx_v3_child_heavy = self.wallet.create_self_transfer_multi( utxos_to_spend=[tx_v3_parent_normal["new_utxo"]], - target_weight=4004, + target_vsize=TRUC_CHILD_MAX_VSIZE + 1, fee_per_output=10000, version=3 ) self.check_mempool([]) result = node.submitpackage([tx_v3_parent_normal["hex"], tx_v3_parent_2_normal["hex"], tx_v3_child_multiparent["hex"]]) - assert_equal(result['package_msg'], f"v3-violation, tx {tx_v3_child_multiparent['txid']} (wtxid={tx_v3_child_multiparent['wtxid']}) would have too many ancestors") + assert_equal(result['package_msg'], f"TRUC-violation, tx {tx_v3_child_multiparent['txid']} (wtxid={tx_v3_child_multiparent['wtxid']}) would have too many ancestors") self.check_mempool([]) self.check_mempool([]) result = node.submitpackage([tx_v3_parent_normal["hex"], tx_v3_child_heavy["hex"]]) - # tx_v3_child_heavy is heavy based on weight, not sigops. - assert_equal(result['package_msg'], f"v3-violation, v3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big: {tx_v3_child_heavy['tx'].get_vsize()} > 1000 virtual bytes") + # tx_v3_child_heavy is heavy based on vsize, not sigops. + assert_equal(result['package_msg'], f"TRUC-violation, version=3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big: {tx_v3_child_heavy['tx'].get_vsize()} > 1000 virtual bytes") self.check_mempool([]) tx_v3_parent = self.wallet.create_self_transfer(version=3) tx_v3_child = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent["new_utxo"], version=3) tx_v3_grandchild = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_child["new_utxo"], version=3) result = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child["hex"], tx_v3_grandchild["hex"]]) - assert all([txresult["package-error"] == f"v3-violation, tx {tx_v3_grandchild['txid']} (wtxid={tx_v3_grandchild['wtxid']}) would have too many ancestors" for txresult in result]) + assert all([txresult["package-error"] == f"TRUC-violation, tx {tx_v3_grandchild['txid']} (wtxid={tx_v3_grandchild['wtxid']}) would have too many ancestors" for txresult in result]) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) - def test_v3_ancestors_package_and_mempool(self): + @cleanup(extra_args=None) + def test_truc_ancestors_package_and_mempool(self): """ - A v3 transaction in a package cannot have 2 v3 parents. + A TRUC transaction in a package cannot have 2 TRUC parents. Test that if we have a transaction graph A -> B -> C, where A, B, C are - all v3 transactions, that we cannot use submitpackage to get the + all TRUC transactions, that we cannot use submitpackage to get the transactions all into the mempool. Verify, in particular, that if A is already in the mempool, then submitpackage(B, C) will fail. """ node = self.nodes[0] - self.log.info("Test that v3 ancestor limits include transactions within the package and all in-mempool ancestors") + self.log.info("Test that TRUC ancestor limits include transactions within the package and all in-mempool ancestors") # This is our transaction "A": tx_in_mempool = self.wallet.send_self_transfer(from_node=node, version=3) @@ -331,17 +332,17 @@ class MempoolAcceptV3(BitcoinTestFramework): # submitpackage(B, C) should fail result = node.submitpackage([tx_0fee_parent["hex"], tx_child_violator["hex"]]) - assert_equal(result['package_msg'], f"v3-violation, tx {tx_child_violator['txid']} (wtxid={tx_child_violator['wtxid']}) would have too many ancestors") + assert_equal(result['package_msg'], f"TRUC-violation, tx {tx_child_violator['txid']} (wtxid={tx_child_violator['wtxid']}) would have too many ancestors") self.check_mempool([tx_in_mempool["txid"]]) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) + @cleanup(extra_args=None) def test_sibling_eviction_package(self): """ When a transaction has a mempool sibling, it may be eligible for sibling eviction. However, this option is only available in single transaction acceptance. It doesn't work in a multi-testmempoolaccept (where RBF is disabled) or when doing package CPFP. """ - self.log.info("Test v3 sibling eviction in submitpackage and multi-testmempoolaccept") + self.log.info("Test TRUC sibling eviction in submitpackage and multi-testmempoolaccept") node = self.nodes[0] # Add a parent + child to mempool tx_mempool_parent = self.wallet.send_self_transfer_multi( @@ -384,17 +385,17 @@ class MempoolAcceptV3(BitcoinTestFramework): # Fails with another non-related transaction via testmempoolaccept tx_unrelated = self.wallet.create_self_transfer(version=3) result_test_unrelated = node.testmempoolaccept([tx_sibling_1["hex"], tx_unrelated["hex"]]) - assert_equal(result_test_unrelated[0]["reject-reason"], "v3-rule-violation") + assert_equal(result_test_unrelated[0]["reject-reason"], "TRUC-violation") # Fails in a package via testmempoolaccept result_test_1p1c = node.testmempoolaccept([tx_sibling_1["hex"], tx_has_mempool_uncle["hex"]]) - assert_equal(result_test_1p1c[0]["reject-reason"], "v3-rule-violation") + assert_equal(result_test_1p1c[0]["reject-reason"], "TRUC-violation") # Allowed when tx is submitted in a package and evaluated individually. # Note that the child failed since it would be the 3rd generation. result_package_indiv = node.submitpackage([tx_sibling_1["hex"], tx_has_mempool_uncle["hex"]]) self.check_mempool([tx_mempool_parent["txid"], tx_sibling_1["txid"]]) - expected_error_gen3 = f"v3-rule-violation, tx {tx_has_mempool_uncle['txid']} (wtxid={tx_has_mempool_uncle['wtxid']}) would have too many ancestors" + expected_error_gen3 = f"TRUC-violation, tx {tx_has_mempool_uncle['txid']} (wtxid={tx_has_mempool_uncle['wtxid']}) would have too many ancestors" assert_equal(result_package_indiv["tx-results"][tx_has_mempool_uncle['wtxid']]['error'], expected_error_gen3) @@ -402,21 +403,21 @@ class MempoolAcceptV3(BitcoinTestFramework): node.submitpackage([tx_mempool_parent["hex"], tx_sibling_2["hex"]]) self.check_mempool([tx_mempool_parent["txid"], tx_sibling_2["txid"]]) - # Child cannot pay for sibling eviction for parent, as it violates v3 topology limits + # Child cannot pay for sibling eviction for parent, as it violates TRUC topology limits result_package_cpfp = node.submitpackage([tx_sibling_3["hex"], tx_bumps_parent_with_sibling["hex"]]) self.check_mempool([tx_mempool_parent["txid"], tx_sibling_2["txid"]]) - expected_error_cpfp = f"v3-rule-violation, tx {tx_mempool_parent['txid']} (wtxid={tx_mempool_parent['wtxid']}) would exceed descendant count limit" + expected_error_cpfp = f"TRUC-violation, tx {tx_mempool_parent['txid']} (wtxid={tx_mempool_parent['wtxid']}) would exceed descendant count limit" assert_equal(result_package_cpfp["tx-results"][tx_sibling_3['wtxid']]['error'], expected_error_cpfp) - @cleanup(extra_args=["-datacarriersize=1000", "-acceptnonstdtxn=1"]) - def test_v3_package_inheritance(self): - self.log.info("Test that v3 inheritance is checked within package") + @cleanup(extra_args=["-datacarriersize=1000"]) + def test_truc_package_inheritance(self): + self.log.info("Test that TRUC inheritance is checked within package") node = self.nodes[0] tx_v3_parent = self.wallet.create_self_transfer( fee_rate=0, - target_weight=4004, + target_vsize=1001, version=3 ) tx_v2_child = self.wallet.create_self_transfer_multi( @@ -426,14 +427,14 @@ class MempoolAcceptV3(BitcoinTestFramework): ) self.check_mempool([]) result = node.submitpackage([tx_v3_parent["hex"], tx_v2_child["hex"]]) - assert_equal(result['package_msg'], f"v3-violation, non-v3 tx {tx_v2_child['txid']} (wtxid={tx_v2_child['wtxid']}) cannot spend from v3 tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']})") + assert_equal(result['package_msg'], f"TRUC-violation, non-version=3 tx {tx_v2_child['txid']} (wtxid={tx_v2_child['wtxid']}) cannot spend from version=3 tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']})") self.check_mempool([]) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) - def test_v3_in_testmempoolaccept(self): + @cleanup(extra_args=None) + def test_truc_in_testmempoolaccept(self): node = self.nodes[0] - self.log.info("Test that v3 inheritance is accurately assessed in testmempoolaccept") + self.log.info("Test that TRUC inheritance is accurately assessed in testmempoolaccept") tx_v2 = self.wallet.create_self_transfer(version=2) tx_v2_from_v2 = self.wallet.create_self_transfer(utxo_to_spend=tx_v2["new_utxo"], version=2) tx_v3_from_v2 = self.wallet.create_self_transfer(utxo_to_spend=tx_v2["new_utxo"], version=3) @@ -447,11 +448,11 @@ class MempoolAcceptV3(BitcoinTestFramework): assert all([result["allowed"] for result in test_accept_v2_and_v3]) test_accept_v3_from_v2 = node.testmempoolaccept([tx_v2["hex"], tx_v3_from_v2["hex"]]) - expected_error_v3_from_v2 = f"v3-violation, v3 tx {tx_v3_from_v2['txid']} (wtxid={tx_v3_from_v2['wtxid']}) cannot spend from non-v3 tx {tx_v2['txid']} (wtxid={tx_v2['wtxid']})" + expected_error_v3_from_v2 = f"TRUC-violation, version=3 tx {tx_v3_from_v2['txid']} (wtxid={tx_v3_from_v2['wtxid']}) cannot spend from non-version=3 tx {tx_v2['txid']} (wtxid={tx_v2['wtxid']})" assert all([result["package-error"] == expected_error_v3_from_v2 for result in test_accept_v3_from_v2]) test_accept_v2_from_v3 = node.testmempoolaccept([tx_v3["hex"], tx_v2_from_v3["hex"]]) - expected_error_v2_from_v3 = f"v3-violation, non-v3 tx {tx_v2_from_v3['txid']} (wtxid={tx_v2_from_v3['wtxid']}) cannot spend from v3 tx {tx_v3['txid']} (wtxid={tx_v3['wtxid']})" + expected_error_v2_from_v3 = f"TRUC-violation, non-version=3 tx {tx_v2_from_v3['txid']} (wtxid={tx_v2_from_v3['wtxid']}) cannot spend from version=3 tx {tx_v3['txid']} (wtxid={tx_v3['wtxid']})" assert all([result["package-error"] == expected_error_v2_from_v3 for result in test_accept_v2_from_v3]) test_accept_pairs = node.testmempoolaccept([tx_v2["hex"], tx_v3["hex"], tx_v2_from_v2["hex"], tx_v3_from_v3["hex"]]) @@ -463,26 +464,26 @@ class MempoolAcceptV3(BitcoinTestFramework): tx_v3_child_1 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent["new_utxos"][0], version=3) tx_v3_child_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent["new_utxos"][1], version=3) test_accept_2children = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child_1["hex"], tx_v3_child_2["hex"]]) - expected_error_2children = f"v3-violation, tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']}) would exceed descendant count limit" + expected_error_2children = f"TRUC-violation, tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']}) would exceed descendant count limit" assert all([result["package-error"] == expected_error_2children for result in test_accept_2children]) - # Extra v3 transaction does not get incorrectly marked as extra descendant + # Extra TRUC transaction does not get incorrectly marked as extra descendant test_accept_1child_with_exra = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child_1["hex"], tx_v3_independent["hex"]]) assert all([result["allowed"] for result in test_accept_1child_with_exra]) - # Extra v3 transaction does not make us ignore the extra descendant + # Extra TRUC transaction does not make us ignore the extra descendant test_accept_2children_with_exra = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child_1["hex"], tx_v3_child_2["hex"], tx_v3_independent["hex"]]) - expected_error_extra = f"v3-violation, tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']}) would exceed descendant count limit" + expected_error_extra = f"TRUC-violation, tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']}) would exceed descendant count limit" assert all([result["package-error"] == expected_error_extra for result in test_accept_2children_with_exra]) # Same result if the parent is already in mempool node.sendrawtransaction(tx_v3_parent["hex"]) test_accept_2children_with_in_mempool_parent = node.testmempoolaccept([tx_v3_child_1["hex"], tx_v3_child_2["hex"]]) assert all([result["package-error"] == expected_error_extra for result in test_accept_2children_with_in_mempool_parent]) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) + @cleanup(extra_args=None) def test_reorg_2child_rbf(self): node = self.nodes[0] - self.log.info("Test that children of a v3 transaction can be replaced individually, even if there are multiple due to reorg") + self.log.info("Test that children of a TRUC transaction can be replaced individually, even if there are multiple due to reorg") ancestor_tx = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2, version=3) self.check_mempool([ancestor_tx["txid"]]) @@ -510,9 +511,9 @@ class MempoolAcceptV3(BitcoinTestFramework): self.check_mempool([ancestor_tx["txid"], child_1_conflict["txid"], child_2["txid"]]) assert_equal(node.getmempoolentry(ancestor_tx["txid"])["descendantcount"], 3) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) - def test_v3_sibling_eviction(self): - self.log.info("Test sibling eviction for v3") + @cleanup(extra_args=None) + def test_truc_sibling_eviction(self): + self.log.info("Test sibling eviction for TRUC") node = self.nodes[0] tx_v3_parent = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2, version=3) # This is the sibling to replace @@ -583,7 +584,7 @@ class MempoolAcceptV3(BitcoinTestFramework): node.sendrawtransaction(tx_v3_child_3["hex"]) self.check_mempool(txids_v2_100 + [tx_v3_parent["txid"], tx_v3_child_3["txid"]]) - @cleanup(extra_args=["-acceptnonstdtxn=1"]) + @cleanup(extra_args=None) def test_reorg_sibling_eviction_1p2c(self): node = self.nodes[0] self.log.info("Test that sibling eviction is not allowed when multiple siblings exist") @@ -609,7 +610,7 @@ class MempoolAcceptV3(BitcoinTestFramework): utxo_to_spend=tx_with_multi_children["new_utxos"][2], fee_rate=DEFAULT_FEE*50 ) - expected_error_2siblings = f"v3-rule-violation, tx {tx_with_multi_children['txid']} (wtxid={tx_with_multi_children['wtxid']}) would exceed descendant count limit" + expected_error_2siblings = f"TRUC-violation, tx {tx_with_multi_children['txid']} (wtxid={tx_with_multi_children['wtxid']}) would exceed descendant count limit" assert_raises_rpc_error(-26, expected_error_2siblings, node.sendrawtransaction, tx_with_sibling3["hex"]) # However, an RBF (with conflicting inputs) is possible even if the resulting cluster size exceeds 2 @@ -627,21 +628,21 @@ class MempoolAcceptV3(BitcoinTestFramework): node = self.nodes[0] self.wallet = MiniWallet(node) self.generate(self.wallet, 120) - self.test_v3_max_vsize() - self.test_v3_acceptance() - self.test_v3_replacement() - self.test_v3_bip125() - self.test_v3_reorg() + self.test_truc_max_vsize() + self.test_truc_acceptance() + self.test_truc_replacement() + self.test_truc_bip125() + self.test_truc_reorg() self.test_nondefault_package_limits() - self.test_v3_ancestors_package() - self.test_v3_ancestors_package_and_mempool() + self.test_truc_ancestors_package() + self.test_truc_ancestors_package_and_mempool() self.test_sibling_eviction_package() - self.test_v3_package_inheritance() - self.test_v3_in_testmempoolaccept() + self.test_truc_package_inheritance() + self.test_truc_in_testmempoolaccept() self.test_reorg_2child_rbf() - self.test_v3_sibling_eviction() + self.test_truc_sibling_eviction() self.test_reorg_sibling_eviction_1p2c() if __name__ == "__main__": - MempoolAcceptV3().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..aca71933ec 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -28,12 +28,16 @@ from test_framework.p2p import P2PDataStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + assert_greater_than_or_equal, assert_raises_rpc_error, get_fee, ) from test_framework.wallet import MiniWallet +DIFFICULTY_ADJUSTMENT_INTERVAL = 144 +MAX_FUTURE_BLOCK_TIME = 2 * 3600 +MAX_TIMEWARP = 600 VERSIONBITS_TOP_BITS = 0x20000000 VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28 DEFAULT_BLOCK_MIN_TX_FEE = 1000 # default `-blockmintxfee` setting [sat/kvB] @@ -115,6 +119,55 @@ class MiningTest(BitcoinTestFramework): assert tx_below_min_feerate['txid'] not in block_template_txids assert tx_below_min_feerate['txid'] not in block_txids + def test_timewarp(self): + self.log.info("Test timewarp attack mitigation (BIP94)") + node = self.nodes[0] + + self.log.info("Mine until the last block of the retarget period") + blockchain_info = self.nodes[0].getblockchaininfo() + n = DIFFICULTY_ADJUSTMENT_INTERVAL - blockchain_info['blocks'] % DIFFICULTY_ADJUSTMENT_INTERVAL - 2 + t = blockchain_info['time'] + + for _ in range(n): + t += 600 + self.nodes[0].setmocktime(t) + self.generate(self.wallet, 1, sync_fun=self.no_op) + + self.log.info("Create block two hours in the future") + self.nodes[0].setmocktime(t + MAX_FUTURE_BLOCK_TIME) + self.generate(self.wallet, 1, sync_fun=self.no_op) + assert_equal(node.getblock(node.getbestblockhash())['time'], t + MAX_FUTURE_BLOCK_TIME) + + self.log.info("First block template of retarget period can't use wall clock time") + self.nodes[0].setmocktime(t) + # The template will have an adjusted timestamp, which we then modify + tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS) + assert_greater_than_or_equal(tmpl['curtime'], t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP) + + block = CBlock() + block.nVersion = tmpl["version"] + block.hashPrevBlock = int(tmpl["previousblockhash"], 16) + block.nTime = tmpl["curtime"] + block.nBits = int(tmpl["bits"], 16) + block.nNonce = 0 + block.vtx = [create_coinbase(height=int(tmpl["height"]))] + block.solve() + assert_template(node, block, None) + + bad_block = copy.deepcopy(block) + bad_block.nTime = t + bad_block.solve() + assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex())) + + self.log.info("Test timewarp protection boundary") + bad_block.nTime = t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP - 1 + bad_block.solve() + assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex())) + + bad_block.nTime = t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP + bad_block.solve() + node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex()) + def run_test(self): node = self.nodes[0] self.wallet = MiniWallet(node) @@ -322,7 +375,8 @@ class MiningTest(BitcoinTestFramework): assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate') # valid self.test_blockmintxfee_parameter() + self.test_timewarp() 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..cdc4e1691d 100755 --- a/test/functional/p2p_1p1c_network.py +++ b/test/functional/p2p_1p1c_network.py @@ -49,9 +49,6 @@ class PackageRelayTest(BitcoinTestFramework): def raise_network_minfee(self): fill_mempool(self, self.nodes[0]) - self.log.debug("Wait for the network to sync mempools") - self.sync_mempools() - self.log.debug("Check that all nodes' mempool minimum feerates are above min relay feerate") for node in self.nodes: assert_equal(node.getmempoolinfo()['minrelaytxfee'], FEERATE_1SAT_VB) @@ -107,7 +104,7 @@ class PackageRelayTest(BitcoinTestFramework): # 3: 2-parent-1-child package. Both parents are above mempool min feerate. No package submission happens. # We require packages to be child-with-unconfirmed-parents and only allow 1-parent-1-child packages. - package_hex_3, parent_31, parent_32, child_3 = self.create_package_2p1c(self.wallet) + package_hex_3, parent_31, _parent_32, child_3 = self.create_package_2p1c(self.wallet) # 4: parent + child package where the child spends 2 different outputs from the parent. package_hex_4, parent_4, child_4 = self.create_package_2outs(self.wallet) @@ -163,4 +160,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 b23ec1028b..56a9e6a84e 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -142,7 +142,8 @@ class AddrTest(BitcoinTestFramework): msg = self.setup_addr_msg(1010) with self.nodes[0].assert_debug_log(['addr message size = 1010']): - addr_source.send_and_ping(msg) + addr_source.send_message(msg) + addr_source.wait_for_disconnect() self.nodes[0].disconnect_p2ps() @@ -440,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 ea114e7d70..d5ded926d3 100755 --- a/test/functional/p2p_addrv2_relay.py +++ b/test/functional/p2p_addrv2_relay.py @@ -86,11 +86,6 @@ class AddrTest(BitcoinTestFramework): addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) msg = msg_addrv2() - self.log.info('Send too-large addrv2 message') - msg.addrs = ADDRS * 101 - with self.nodes[0].assert_debug_log(['addrv2 message size = 1010']): - addr_source.send_and_ping(msg) - self.log.info('Check that addrv2 message content is relayed and added to addrman') addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver()) msg.addrs = ADDRS @@ -106,6 +101,13 @@ class AddrTest(BitcoinTestFramework): assert addr_receiver.addrv2_received_and_checked assert_equal(len(self.nodes[0].getnodeaddresses(count=0, network="i2p")), 0) + self.log.info('Send too-large addrv2 message') + msg.addrs = ADDRS * 101 + with self.nodes[0].assert_debug_log(['addrv2 message size = 1010']): + addr_source.send_message(msg) + addr_source.wait_for_disconnect() + + 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 dd19fe9333..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,6 +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) + 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..6e7b4b399e 100755 --- a/test/functional/p2p_headers_sync_with_minchainwork.py +++ b/test/functional/p2p_headers_sync_with_minchainwork.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-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. """Test that we reject low difficulty headers to prevent our block tree from filling up with useless bloat""" @@ -21,6 +21,8 @@ from test_framework.blocktools import ( from test_framework.util import assert_equal +import time + NODE1_BLOCKS_REQUIRED = 15 NODE2_BLOCKS_REQUIRED = 2047 @@ -48,6 +50,10 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): self.connect_nodes(0, 2) self.connect_nodes(0, 3) + def mocktime_all(self, time): + for n in self.nodes: + n.setmocktime(time) + def test_chains_sync_when_long_enough(self): self.log.info("Generate blocks on the node with no required chainwork, and verify nodes 1 and 2 have no new headers in their headers tree") with self.nodes[1].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[3].assert_debug_log(expected_msgs=["Synchronizing blockheaders, height: 14"]): @@ -149,7 +155,9 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): self.reconnect_all() + self.mocktime_all(int(time.time())) # Temporarily hold time to avoid internal timeouts self.sync_blocks(timeout=300) # Ensure tips eventually agree + self.mocktime_all(0) def run_test(self): @@ -162,4 +170,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..fa07873929 100755 --- a/test/functional/p2p_ibd_stalling.py +++ b/test/functional/p2p_ibd_stalling.py @@ -73,6 +73,7 @@ class P2PIBDStallingTest(BitcoinTestFramework): peers = [] self.log.info("Check that a staller does not get disconnected if the 1024 block lookahead buffer is filled") + self.mocktime = int(time.time()) + 1 for id in range(NUM_PEERS): peers.append(node.add_outbound_p2p_connection(P2PStaller(stall_block), p2p_idx=id, connection_type="outbound-full-relay")) peers[-1].block_store = block_dict @@ -85,7 +86,7 @@ class P2PIBDStallingTest(BitcoinTestFramework): self.all_sync_send_with_ping(peers) # If there was a peer marked for stalling, it would get disconnected - self.mocktime = int(time.time()) + 3 + self.mocktime += 3 node.setmocktime(self.mocktime) self.all_sync_send_with_ping(peers) assert_equal(node.num_test_p2p_connections(), NUM_PEERS) @@ -162,4 +163,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 adcbb4fd05..507393fb70 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -260,7 +260,9 @@ class InvalidMessagesTest(BitcoinTestFramework): msg_type = msg.msgtype.decode('ascii') self.log.info("Test {} message of size {} is logged as misbehaving".format(msg_type, size)) with self.nodes[0].assert_debug_log(['Misbehaving', '{} message size = {}'.format(msg_type, size)]): - self.nodes[0].add_p2p_connection(P2PInterface()).send_and_ping(msg) + conn = self.nodes[0].add_p2p_connection(P2PInterface()) + conn.send_message(msg) + conn.wait_for_disconnect() self.nodes[0].disconnect_p2ps() def test_oversized_inv_msg(self): @@ -321,7 +323,8 @@ class InvalidMessagesTest(BitcoinTestFramework): # delete arbitrary block header somewhere in the middle to break link del block_headers[random.randrange(1, len(block_headers)-1)] with self.nodes[0].assert_debug_log(expected_msgs=MISBEHAVING_NONCONTINUOUS_HEADERS_MSGS): - peer.send_and_ping(msg_headers(block_headers)) + peer.send_message(msg_headers(block_headers)) + peer.wait_for_disconnect() self.nodes[0].disconnect_p2ps() def test_resource_exhaustion(self): @@ -353,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..ee8c6c16ca 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -165,7 +165,7 @@ class InvalidTxRequestTest(BitcoinTestFramework): node.p2ps[0].send_txs_and_test([rejected_parent], node, success=False) self.log.info('Test that a peer disconnection causes erase its transactions from the orphan pool') - with node.assert_debug_log(['Erased 100 orphan transaction(s) from peer=25']): + with node.assert_debug_log(['Erased 100 orphan transaction(s) from peer=26']): self.reconnect_p2p(num_connections=1) self.log.info('Test that a transaction in the orphan pool is included in a new tip block causes erase this transaction from the orphan pool') @@ -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 737edaf5bf..4a790168da 100755 --- a/test/functional/p2p_mutated_blocks.py +++ b/test/functional/p2p_mutated_blocks.py @@ -55,7 +55,7 @@ class MutatedBlocksTest(BitcoinTestFramework): # Create mutated version of the block by changing the transaction # version on the self-transfer. mutated_block = copy.deepcopy(block) - mutated_block.vtx[1].nVersion = 4 + mutated_block.vtx[1].version = 4 # Announce the new block via a compact block through the honest relayer cmpctblock = HeaderAndShortIDs() @@ -104,13 +104,12 @@ class MutatedBlocksTest(BitcoinTestFramework): block_missing_prev.hashPrevBlock = 123 block_missing_prev.solve() - # Attacker gets a DoS score of 10, not immediately disconnected, so we do it 10 times to get to 100 - for _ in range(10): - assert_equal(len(self.nodes[0].getpeerinfo()), 2) - with self.nodes[0].assert_debug_log(expected_msgs=["AcceptBlock FAILED (prev-blk-not-found)"]): - attacker.send_message(msg_block(block_missing_prev)) + # Check that non-connecting block causes disconnect + assert_equal(len(self.nodes[0].getpeerinfo()), 2) + with self.nodes[0].assert_debug_log(expected_msgs=["AcceptBlock FAILED (prev-blk-not-found)"]): + attacker.send_message(msg_block(block_missing_prev)) attacker.wait_for_disconnect(timeout=5) 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..7788be6adb 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -102,10 +102,10 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): tip_height = pruned_node.getblockcount() limit_buffer = 2 # Prevent races by waiting for the tip to arrive first - self.wait_until(lambda: not try_rpc(-1, "Block not found", full_node.getblock, pruned_node.getbestblockhash())) + self.wait_until(lambda: not try_rpc(-1, "Block not available (not fully downloaded)", full_node.getblock, pruned_node.getbestblockhash())) for height in range(start_height_full_node + 1, tip_height + 1): if height <= tip_height - (NODE_NETWORK_LIMITED_MIN_BLOCKS - limit_buffer): - assert_raises_rpc_error(-1, "Block not found on disk", full_node.getblock, pruned_node.getblockhash(height)) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", full_node.getblock, pruned_node.getblockhash(height)) else: full_node.getblock(pruned_node.getblockhash(height)) # just assert it does not throw an exception @@ -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..c37061c307 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -14,8 +14,10 @@ from test_framework.p2p import P2PDataStore from test_framework.test_node import ErrorMatch from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( + append_config, assert_equal, p2p_port, + tor_port, ) from test_framework.wallet import MiniWallet @@ -57,11 +59,14 @@ class P2PPermissionsTests(BitcoinTestFramework): # by modifying the configuration file. ip_port = "127.0.0.1:{}".format(p2p_port(1)) self.nodes[1].replace_in_config([("bind=127.0.0.1", "whitebind=bloomfilter,forcerelay@" + ip_port)]) + # Explicitly bind the tor port to prevent collisions with the default tor port + append_config(self.nodes[1].datadir_path, [f"bind=127.0.0.1:{tor_port(self.nodes[1].index)}=onion"]) self.checkpermission( ["-whitelist=noban@127.0.0.1"], # Check parameter interaction forcerelay should activate relay ["noban", "bloomfilter", "forcerelay", "relay", "download"]) self.nodes[1].replace_in_config([("whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1")]) + self.nodes[1].replace_in_config([(f"bind=127.0.0.1:{tor_port(self.nodes[1].index)}=onion", "")]) self.checkpermission( # legacy whitelistrelay should be ignored @@ -119,14 +124,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 +155,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_seednode.py b/test/functional/p2p_seednode.py new file mode 100755 index 0000000000..6c510a6a0b --- /dev/null +++ b/test/functional/p2p_seednode.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019-2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" +Test seednode interaction with the AddrMan +""" +import random +import time + +from test_framework.test_framework import BitcoinTestFramework + +ADD_NEXT_SEEDNODE = 10 + + +class P2PSeedNodes(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.disable_autoconnect = False + + def test_no_seednode(self): + # Check that if no seednode is provided, the node proceeds as usual (without waiting) + with self.nodes[0].assert_debug_log(expected_msgs=[], unexpected_msgs=["Empty addrman, adding seednode", f"Couldn't connect to peers from addrman after {ADD_NEXT_SEEDNODE} seconds. Adding seednode"], timeout=ADD_NEXT_SEEDNODE): + self.restart_node(0) + + def test_seednode_empty_addrman(self): + seed_node = "0.0.0.1" + # Check that the seednode is added to m_addr_fetches on bootstrap on an empty addrman + with self.nodes[0].assert_debug_log(expected_msgs=[f"Empty addrman, adding seednode ({seed_node}) to addrfetch"], timeout=ADD_NEXT_SEEDNODE): + self.restart_node(0, extra_args=[f'-seednode={seed_node}']) + + def test_seednode_addrman_unreachable_peers(self): + seed_node = "0.0.0.2" + node = self.nodes[0] + # Fill the addrman with unreachable nodes + for i in range(10): + ip = f"{random.randrange(128,169)}.{random.randrange(1,255)}.{random.randrange(1,255)}.{random.randrange(1,255)}" + port = 8333 + i + node.addpeeraddress(ip, port) + + # Restart the node so seednode is processed again + with node.assert_debug_log(expected_msgs=[f"Couldn't connect to peers from addrman after {ADD_NEXT_SEEDNODE} seconds. Adding seednode ({seed_node}) to addrfetch"], unexpected_msgs=["Empty addrman, adding seednode"], timeout=ADD_NEXT_SEEDNODE * 1.5): + self.restart_node(0, extra_args=[f'-seednode={seed_node}']) + node.setmocktime(int(time.time()) + ADD_NEXT_SEEDNODE + 1) + + def run_test(self): + self.test_no_seednode() + self.test_seednode_empty_addrman() + self.test_seednode_addrman_unreachable_peers() + + +if __name__ == '__main__': + P2PSeedNodes(__file__).main() + diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index b63c2c7a8d..9be53d2ab8 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -1164,7 +1164,7 @@ class SegWitTest(BitcoinTestFramework): if not self.wit.is_null(): flags |= 1 r = b"" - r += self.nVersion.to_bytes(4, "little", signed=True) + r += self.version.to_bytes(4, "little") if flags: dummy = [] r += ser_vector(dummy) @@ -1975,7 +1975,7 @@ class SegWitTest(BitcoinTestFramework): def serialize_with_bogus_witness(tx): flags = 3 r = b"" - r += tx.nVersion.to_bytes(4, "little", signed=True) + r += tx.version.to_bytes(4, "little") if flags: dummy = [] r += ser_vector(dummy) @@ -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 27a3aa8fb9..db706556d8 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -71,19 +71,13 @@ f. Announce 1 more header that builds on that fork. Expect: no response. Part 5: Test handling of headers that don't connect. -a. Repeat 10 times: +a. Repeat 100 times: 1. Announce a header that doesn't connect. Expect: getheaders message 2. Send headers chain. Expect: getdata for the missing blocks, tip update. -b. Then send 9 more headers that don't connect. +b. Then send 99 more headers that don't connect. Expect: getheaders message each time. -c. Announce a header that does connect. - Expect: no response. -d. Announce 49 headers that don't connect. - Expect: getheaders message each time. -e. Announce one more that doesn't connect. - Expect: disconnect. """ from test_framework.blocktools import create_block, create_coinbase from test_framework.messages import CInv @@ -526,7 +520,8 @@ class SendHeadersTest(BitcoinTestFramework): # First we test that receipt of an unconnecting header doesn't prevent # chain sync. expected_hash = tip - for i in range(10): + NUM_HEADERS = 100 + for i in range(NUM_HEADERS): self.log.debug("Part 5.{}: starting...".format(i)) test_node.last_message.pop("getdata", None) blocks = [] @@ -550,44 +545,27 @@ class SendHeadersTest(BitcoinTestFramework): blocks = [] # Now we test that if we repeatedly don't send connecting headers, we # don't go into an infinite loop trying to get them to connect. - MAX_NUM_UNCONNECTING_HEADERS_MSGS = 10 - for _ in range(MAX_NUM_UNCONNECTING_HEADERS_MSGS + 1): + for _ in range(NUM_HEADERS + 1): blocks.append(create_block(tip, create_coinbase(height), block_time)) blocks[-1].solve() tip = blocks[-1].sha256 block_time += 1 height += 1 - for i in range(1, MAX_NUM_UNCONNECTING_HEADERS_MSGS): - # Send a header that doesn't connect, check that we get a getheaders. + for i in range(1, NUM_HEADERS): + with p2p_lock: + test_node.last_message.pop("getheaders", None) + # Send an empty header as a failed response to the received getheaders + # (from the previous iteration). Otherwise, the new headers will be + # treated as a response instead of as an announcement. + test_node.send_header_for_blocks([]) + # Send the actual unconnecting header, which should trigger a new getheaders. test_node.send_header_for_blocks([blocks[i]]) test_node.wait_for_getheaders(block_hash=expected_hash) - # Next header will connect, should re-set our count: - test_node.send_header_for_blocks([blocks[0]]) - expected_hash = blocks[0].sha256 - - # Remove the first two entries (blocks[1] would connect): - blocks = blocks[2:] - - # Now try to see how many unconnecting headers we can send - # before we get disconnected. Should be 5*MAX_NUM_UNCONNECTING_HEADERS_MSGS - for i in range(5 * MAX_NUM_UNCONNECTING_HEADERS_MSGS - 1): - # Send a header that doesn't connect, check that we get a getheaders. - test_node.send_header_for_blocks([blocks[i % len(blocks)]]) - test_node.wait_for_getheaders(block_hash=expected_hash) - - # Eventually this stops working. - test_node.send_header_for_blocks([blocks[-1]]) - - # Should get disconnected - test_node.wait_for_disconnect() - - self.log.info("Part 5: success!") - # Finally, check that the inv node never received a getdata request, # throughout the test 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..c69d6ff405 100755 --- a/test/functional/p2p_tx_download.py +++ b/test/functional/p2p_tx_download.py @@ -156,9 +156,9 @@ class TxDownloadTest(BitcoinTestFramework): # One of the peers is asked for the tx peer2.wait_until(lambda: sum(p.tx_getdata_count for p in [peer1, peer2]) == 1) with p2p_lock: - peer_expiry, peer_fallback = (peer1, peer2) if peer1.tx_getdata_count == 1 else (peer2, peer1) + _peer_expiry, peer_fallback = (peer1, peer2) if peer1.tx_getdata_count == 1 else (peer2, peer1) assert_equal(peer_fallback.tx_getdata_count, 0) - self.nodes[0].setmocktime(int(time.time()) + GETDATA_TX_INTERVAL + 1) # Wait for request to peer_expiry to expire + self.nodes[0].setmocktime(int(time.time()) + GETDATA_TX_INTERVAL + 1) # Wait for request to _peer_expiry to expire peer_fallback.wait_until(lambda: peer_fallback.tx_getdata_count >= 1, timeout=1) self.restart_node(0) # reset mocktime @@ -250,7 +250,7 @@ class TxDownloadTest(BitcoinTestFramework): def test_rejects_filter_reset(self): self.log.info('Check that rejected tx is not requested again') node = self.nodes[0] - fill_mempool(self, node) + fill_mempool(self, node, tx_sync_fun=self.no_op) self.wallet.rescan_utxos() mempoolminfee = node.getmempoolinfo()['mempoolminfee'] peer = node.add_p2p_connection(TestP2PConn()) @@ -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 f368434895..1430131a97 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -119,7 +119,7 @@ class AcceptBlockTest(BitcoinTestFramework): assert_equal(x['status'], "headers-only") tip_entry_found = True assert tip_entry_found - assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_h1f.hash) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", self.nodes[0].getblock, block_h1f.hash) # 4. Send another two block that build on the fork. block_h2f = create_block(block_h1f.sha256, create_coinbase(2), block_time) @@ -170,9 +170,11 @@ class AcceptBlockTest(BitcoinTestFramework): tip = next_block # Now send the block at height 5 and check that it wasn't accepted (missing header) - test_node.send_and_ping(msg_block(all_blocks[1])) + test_node.send_message(msg_block(all_blocks[1])) + test_node.wait_for_disconnect() assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblock, all_blocks[1].hash) assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblockheader, all_blocks[1].hash) + test_node = self.nodes[0].add_p2p_connection(P2PInterface()) # The block at height 5 should be accepted if we provide the missing header, though headers_message = msg_headers() @@ -189,7 +191,7 @@ class AcceptBlockTest(BitcoinTestFramework): # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead for x in all_blocks[:-1]: self.nodes[0].getblock(x.hash) - assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", self.nodes[0].getblock, all_blocks[-1].hash) # 5. Test handling of unrequested block on the node that didn't process # Should still not be processed (even though it has a child that has more @@ -228,7 +230,7 @@ class AcceptBlockTest(BitcoinTestFramework): assert_equal(self.nodes[0].getblockcount(), 290) self.nodes[0].getblock(all_blocks[286].hash) assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash) - assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[287].hash) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", self.nodes[0].getblock, all_blocks[287].hash) self.log.info("Successfully reorged to longer chain") # 8. Create a chain which is invalid at a height longer than the @@ -258,7 +260,7 @@ class AcceptBlockTest(BitcoinTestFramework): assert_equal(x['status'], "headers-only") tip_entry_found = True assert tip_entry_found - assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_292.hash) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", self.nodes[0].getblock, block_292.hash) test_node.send_message(msg_block(block_289f)) test_node.send_and_ping(msg_block(block_290f)) @@ -294,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..69afd45b9a 100755 --- a/test/functional/rpc_bind.py +++ b/test/functional/rpc_bind.py @@ -45,6 +45,19 @@ class RPCBindTest(BitcoinTestFramework): assert_equal(set(get_bind_addrs(pid)), set(expected)) self.stop_nodes() + def run_invalid_bind_test(self, allow_ips, addresses): + ''' + Attempt to start a node with requested rpcallowip and rpcbind + parameters, expecting that the node will fail. + ''' + self.log.info(f'Invalid bind test for {addresses}') + base_args = ['-disablewallet', '-nolisten'] + if allow_ips: + base_args += ['-rpcallowip=' + x for x in allow_ips] + init_error = 'Error: Invalid port specified in -rpcbind: ' + for addr in addresses: + self.nodes[0].assert_start_raises_init_error(base_args + [f'-rpcbind={addr}'], init_error + f"'{addr}'") + def run_allowip_test(self, allow_ips, rpchost, rpcport): ''' Start a node with rpcallow IP, and request getnetworkinfo @@ -84,6 +97,10 @@ class RPCBindTest(BitcoinTestFramework): if not self.options.run_nonloopback: self._run_loopback_tests() + if self.options.run_ipv4: + self.run_invalid_bind_test(['127.0.0.1'], ['127.0.0.1:notaport', '127.0.0.1:-18443', '127.0.0.1:0', '127.0.0.1:65536']) + if self.options.run_ipv6: + self.run_invalid_bind_test(['[::1]'], ['[::1]:notaport', '[::1]:-18443', '[::1]:0', '[::1]:65536']) if not self.options.run_ipv4 and not self.options.run_ipv6: self._run_nonloopback_tests() @@ -124,4 +141,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..f02e6914ef 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -32,14 +32,16 @@ from test_framework.blocktools import ( TIME_GENESIS_BLOCK, create_block, create_coinbase, + create_tx_with_script, ) from test_framework.messages import ( CBlockHeader, + COIN, from_hex, msg_block, ) from test_framework.p2p import P2PInterface -from test_framework.script import hash256 +from test_framework.script import hash256, OP_TRUE from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -58,7 +60,7 @@ TIME_RANGE_STEP = 600 # ten-minute steps TIME_RANGE_MTP = TIME_GENESIS_BLOCK + (HEIGHT - 6) * TIME_RANGE_STEP TIME_RANGE_TIP = TIME_GENESIS_BLOCK + (HEIGHT - 1) * TIME_RANGE_STEP TIME_RANGE_END = TIME_GENESIS_BLOCK + HEIGHT * TIME_RANGE_STEP -DIFFICULTY_ADJUSTMENT_INTERVAL = 2016 +DIFFICULTY_ADJUSTMENT_INTERVAL = 144 class BlockchainTest(BitcoinTestFramework): @@ -88,6 +90,7 @@ class BlockchainTest(BitcoinTestFramework): self._test_getdifficulty() self._test_getnetworkhashps() self._test_stopatheight() + self._test_waitforblock() # also tests waitfornewblock self._test_waitforblockheight() self._test_getblock() self._test_getdeploymentinfo() @@ -505,6 +508,38 @@ class BlockchainTest(BitcoinTestFramework): self.start_node(0) assert_equal(self.nodes[0].getblockcount(), HEIGHT + 7) + def _test_waitforblock(self): + self.log.info("Test waitforblock and waitfornewblock") + node = self.nodes[0] + + current_height = node.getblock(node.getbestblockhash())['height'] + current_hash = node.getblock(node.getbestblockhash())['hash'] + + self.log.debug("Roll the chain back a few blocks and then reconsider it") + rollback_height = current_height - 100 + rollback_hash = node.getblockhash(rollback_height) + rollback_header = node.getblockheader(rollback_hash) + + node.invalidateblock(rollback_hash) + assert_equal(node.getblockcount(), rollback_height - 1) + + self.log.debug("waitforblock should return the same block after its timeout") + assert_equal(node.waitforblock(blockhash=current_hash, timeout=1)['hash'], rollback_header['previousblockhash']) + + node.reconsiderblock(rollback_hash) + # The chain has probably already been restored by the time reconsiderblock returns, + # but poll anyway. + self.wait_until(lambda: node.waitforblock(blockhash=current_hash, timeout=100)['hash'] == current_hash) + + # roll back again + node.invalidateblock(rollback_hash) + assert_equal(node.getblockcount(), rollback_height - 1) + + node.reconsiderblock(rollback_hash) + # The chain has probably already been restored by the time reconsiderblock returns, + # but poll anyway. + self.wait_until(lambda: node.waitfornewblock(timeout=100)['hash'] == current_hash) + def _test_waitforblockheight(self): self.log.info("Test waitforblockheight") node = self.nodes[0] @@ -556,12 +591,12 @@ class BlockchainTest(BitcoinTestFramework): block = node.getblock(blockhash, verbosity) assert_equal(blockhash, hash256(bytes.fromhex(block[:160]))[::-1].hex()) - def assert_fee_not_in_block(verbosity): - block = node.getblock(blockhash, verbosity) + def assert_fee_not_in_block(hash, verbosity): + block = node.getblock(hash, verbosity) assert 'fee' not in block['tx'][1] - def assert_fee_in_block(verbosity): - block = node.getblock(blockhash, verbosity) + def assert_fee_in_block(hash, verbosity): + block = node.getblock(hash, verbosity) tx = block['tx'][1] assert 'fee' in tx assert_equal(tx['fee'], tx['vsize'] * fee_per_byte) @@ -580,8 +615,8 @@ class BlockchainTest(BitcoinTestFramework): total_vout += vout["value"] assert_equal(total_vin, total_vout + tx["fee"]) - def assert_vin_does_not_contain_prevout(verbosity): - block = node.getblock(blockhash, verbosity) + def assert_vin_does_not_contain_prevout(hash, verbosity): + block = node.getblock(hash, verbosity) tx = block["tx"][1] if isinstance(tx, str): # In verbosity level 1, only the transaction hashes are written @@ -595,16 +630,16 @@ class BlockchainTest(BitcoinTestFramework): assert_hexblock_hashes(False) self.log.info("Test that getblock with verbosity 1 doesn't include fee") - assert_fee_not_in_block(1) - assert_fee_not_in_block(True) + assert_fee_not_in_block(blockhash, 1) + assert_fee_not_in_block(blockhash, True) self.log.info('Test that getblock with verbosity 2 and 3 includes expected fee') - assert_fee_in_block(2) - assert_fee_in_block(3) + assert_fee_in_block(blockhash, 2) + assert_fee_in_block(blockhash, 3) self.log.info("Test that getblock with verbosity 1 and 2 does not include prevout") - assert_vin_does_not_contain_prevout(1) - assert_vin_does_not_contain_prevout(2) + assert_vin_does_not_contain_prevout(blockhash, 1) + assert_vin_does_not_contain_prevout(blockhash, 2) self.log.info("Test that getblock with verbosity 3 includes prevout") assert_vin_contains_prevout(3) @@ -612,7 +647,7 @@ class BlockchainTest(BitcoinTestFramework): self.log.info("Test getblock with invalid verbosity type returns proper error message") assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", node.getblock, blockhash, "2") - self.log.info("Test that getblock with verbosity 2 and 3 still works with pruned Undo data") + self.log.info("Test that getblock doesn't work with deleted Undo data") def move_block_file(old, new): old_path = self.nodes[0].blocks_path / old @@ -622,10 +657,8 @@ class BlockchainTest(BitcoinTestFramework): # Move instead of deleting so we can restore chain state afterwards move_block_file('rev00000.dat', 'rev_wrong') - assert_fee_not_in_block(2) - assert_fee_not_in_block(3) - assert_vin_does_not_contain_prevout(2) - assert_vin_does_not_contain_prevout(3) + assert_raises_rpc_error(-32603, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.", lambda: node.getblock(blockhash, 2)) + assert_raises_rpc_error(-32603, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.", lambda: node.getblock(blockhash, 3)) # Restore chain state move_block_file('rev_wrong', 'rev00000.dat') @@ -633,6 +666,31 @@ class BlockchainTest(BitcoinTestFramework): assert 'previousblockhash' not in node.getblock(node.getblockhash(0)) assert 'nextblockhash' not in node.getblock(node.getbestblockhash()) + self.log.info("Test getblock when only header is known") + current_height = node.getblock(node.getbestblockhash())['height'] + block_time = node.getblock(node.getbestblockhash())['time'] + 1 + block = create_block(int(blockhash, 16), create_coinbase(current_height + 1, nValue=100), block_time) + block.solve() + node.submitheader(block.serialize().hex()) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", lambda: node.getblock(block.hash)) + + self.log.info("Test getblock when block data is available but undo data isn't") + # Submits a block building on the header-only block, so it can't be connected and has no undo data + tx = create_tx_with_script(block.vtx[0], 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN) + block_noundo = create_block(block.sha256, create_coinbase(current_height + 2, nValue=100), block_time + 1, txlist=[tx]) + block_noundo.solve() + node.submitblock(block_noundo.serialize().hex()) + + assert_fee_not_in_block(block_noundo.hash, 2) + assert_fee_not_in_block(block_noundo.hash, 3) + assert_vin_does_not_contain_prevout(block_noundo.hash, 2) + assert_vin_does_not_contain_prevout(block_noundo.hash, 3) + + self.log.info("Test getblock when block is missing") + move_block_file('blk00000.dat', 'blk00000.dat.bak') + assert_raises_rpc_error(-1, "Block not found on disk", node.getblock, blockhash) + move_block_file('blk00000.dat.bak', 'blk00000.dat') + if __name__ == '__main__': - BlockchainTest().main() + BlockchainTest(__file__).main() diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index fdac3623d3..d95820bbf8 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -12,6 +12,7 @@ from test_framework.address import address_to_scriptpubkey from test_framework.descriptors import descsum_create, drop_origins from test_framework.key import ECPubKey from test_framework.messages import COIN +from test_framework.script_util import keys_to_multisig_script from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_raises_rpc_error, @@ -46,7 +47,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): return node.get_wallet_rpc(wallet_name) def run_test(self): - node0, node1, node2 = self.nodes + node0, node1, _node2 = self.nodes self.wallet = MiniWallet(test_node=node0) if self.is_wallet_compiled(): @@ -69,6 +70,16 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): # Check that bech32m is currently not allowed assert_raises_rpc_error(-5, "createmultisig cannot create bech32m multisig addresses", self.nodes[0].createmultisig, 2, self.pub, "bech32m") + self.log.info('Check correct encoding of multisig script for all n (1..20)') + for nkeys in range(1, 20+1): + keys = [self.pub[0]]*nkeys + expected_ms_script = keys_to_multisig_script(keys, k=nkeys) # simply use n-of-n + # note that the 'legacy' address type fails for n values larger than 15 + # due to exceeding the P2SH size limit (520 bytes), so we use 'bech32' instead + # (for the purpose of this encoding test, we don't care about the resulting address) + res = self.nodes[0].createmultisig(nrequired=nkeys, keys=keys, address_type='bech32') + assert_equal(res['redeemScript'], expected_ms_script.hex()) + def check_addmultisigaddress_errors(self): if self.options.descriptors: return @@ -111,7 +122,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): assert_raises_rpc_error(-4, "Unsupported multisig script size for legacy wallet. Upgrade to descriptors to overcome this limitation for p2sh-segwit or bech32 scripts", wallet_multi.addmultisigaddress, 16, pubkeys, '', 'bech32') def do_multisig(self, nkeys, nsigs, output_type, wallet_multi): - node0, node1, node2 = self.nodes + node0, _node1, node2 = self.nodes pub_keys = self.pub[0: nkeys] priv_keys = self.priv[0: nkeys] @@ -246,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..32fdfa350a 100755 --- a/test/functional/rpc_deriveaddresses.py +++ b/test/functional/rpc_deriveaddresses.py @@ -29,6 +29,9 @@ class DeriveaddressesTest(BitcoinTestFramework): assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, [1, 2]), ["bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq"]) assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, 2), [address, "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq"]) + ranged_descriptor = descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/<0;1>/*)") + assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, [1, 2]), [["bcrt1q7c8mdmdktrzs8xgpjmqw90tjn65j5a3yj04m3n", "bcrt1qs6n37uzu0v0qfzf0r0csm0dwa7prc0v5uavgy0"], ["bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq"]]) + assert_raises_rpc_error(-8, "Range should not be specified for an un-ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"), [0, 2]) assert_raises_rpc_error(-8, "Range must be specified for a ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)")) @@ -61,4 +64,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..ad05060210 100755 --- a/test/functional/rpc_dumptxoutset.py +++ b/test/functional/rpc_dumptxoutset.py @@ -19,6 +19,17 @@ class DumptxoutsetTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def check_expected_network(self, node, active): + rev_file = node.blocks_path / "rev00000.dat" + bogus_file = node.blocks_path / "bogus.dat" + rev_file.rename(bogus_file) + assert_raises_rpc_error( + -1, 'Could not roll back to requested height.', node.dumptxoutset, 'utxos.dat', rollback=99) + assert_equal(node.getnetworkinfo()['networkactive'], active) + + # Cleanup + bogus_file.rename(rev_file) + def run_test(self): """Test a trivial usage of the dumptxoutset RPC command.""" node = self.nodes[0] @@ -27,8 +38,8 @@ class DumptxoutsetTest(BitcoinTestFramework): self.generate(node, COINBASE_MATURITY) FILENAME = 'txoutset.dat' - out = node.dumptxoutset(FILENAME) - expected_path = node.datadir_path / self.chain / FILENAME + out = node.dumptxoutset(FILENAME, "latest") + expected_path = node.chain_path / FILENAME assert expected_path.is_file() @@ -43,7 +54,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') @@ -51,11 +62,23 @@ class DumptxoutsetTest(BitcoinTestFramework): # Specifying a path to an existing or invalid file will fail. assert_raises_rpc_error( - -8, '{} already exists'.format(FILENAME), node.dumptxoutset, FILENAME) + -8, '{} already exists'.format(FILENAME), node.dumptxoutset, FILENAME, "latest") invalid_path = node.datadir_path / "invalid" / "path" assert_raises_rpc_error( - -8, "Couldn't open file {}.incomplete for writing".format(invalid_path), node.dumptxoutset, invalid_path) + -8, "Couldn't open file {}.incomplete for writing".format(invalid_path), node.dumptxoutset, invalid_path, "latest") + + self.log.info(f"Test that dumptxoutset with unknown dump type fails") + assert_raises_rpc_error( + -8, 'Invalid snapshot type "bogus" specified. Please specify "rollback" or "latest"', node.dumptxoutset, 'utxos.dat', "bogus") + + self.log.info(f"Test that dumptxoutset failure does not leave the network activity suspended when it was on previously") + self.check_expected_network(node, True) + + self.log.info(f"Test that dumptxoutset failure leaves the network activity suspended when it was off") + node.setnetworkactive(False) + self.check_expected_network(node, False) + node.setnetworkactive(True) 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 20f62079fd..68de900664 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -87,7 +87,7 @@ class RPCGenerateTest(BitcoinTestFramework): txid1 = miniwallet.send_self_transfer(from_node=node)['txid'] utxo1 = miniwallet.get_utxo(txid=txid1) rawtx2 = miniwallet.create_self_transfer(utxo_to_spend=utxo1)['hex'] - assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1]) + assert_raises_rpc_error(-25, 'testBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1]) self.log.info('Fail to generate block with txid not in mempool') missing_txid = '0000000000000000000000000000000000000000000000000000000000000000' @@ -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..62b3d664e0 100755 --- a/test/functional/rpc_getblockfrompeer.py +++ b/test/functional/rpc_getblockfrompeer.py @@ -58,7 +58,7 @@ class GetBlockFromPeerTest(BitcoinTestFramework): self.log.info("Node 0 should only have the header for node 1's block 3") x = next(filter(lambda x: x['hash'] == short_tip, self.nodes[0].getchaintips())) assert_equal(x['status'], "headers-only") - assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, short_tip) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", self.nodes[0].getblock, short_tip) self.log.info("Fetch block from node 1") peers = self.nodes[0].getpeerinfo() @@ -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..002763201a 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -114,7 +114,7 @@ class GetblockstatsTest(BitcoinTestFramework): assert_equal(stats[self.max_stat_pos]['height'], self.start_height + self.max_stat_pos) for i in range(self.max_stat_pos+1): - self.log.info('Checking block %d\n' % (i)) + self.log.info('Checking block %d' % (i)) assert_equal(stats[i], self.expected_stats[i]) # Check selecting block by hash too @@ -182,5 +182,16 @@ class GetblockstatsTest(BitcoinTestFramework): assert_equal(tip_stats["utxo_increase_actual"], 4) assert_equal(tip_stats["utxo_size_inc_actual"], 300) + self.log.info("Test when only header is known") + block = self.generateblock(self.nodes[0], output="raw(55)", transactions=[], submit=False) + self.nodes[0].submitheader(block["hex"]) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", lambda: self.nodes[0].getblockstats(block['hash'])) + + self.log.info('Test when block is missing') + (self.nodes[0].blocks_path / 'blk00000.dat').rename(self.nodes[0].blocks_path / 'blk00000.dat.backup') + assert_raises_rpc_error(-1, 'Block not found on disk', self.nodes[0].getblockstats, hash_or_height=1) + (self.nodes[0].blocks_path / 'blk00000.dat.backup').rename(self.nodes[0].blocks_path / 'blk00000.dat') + + 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..e4e6d6f0f3 100755 --- a/test/functional/rpc_getdescriptorinfo.py +++ b/test/functional/rpc_getdescriptorinfo.py @@ -19,10 +19,15 @@ class DescriptorTest(BitcoinTestFramework): self.extra_args = [["-disablewallet"]] self.wallet_names = [] - def test_desc(self, desc, isrange, issolvable, hasprivatekeys): + def test_desc(self, desc, isrange, issolvable, hasprivatekeys, expanded_descs=None): info = self.nodes[0].getdescriptorinfo(desc) assert_equal(info, self.nodes[0].getdescriptorinfo(descsum_create(desc))) - assert_equal(info['descriptor'], descsum_create(desc)) + if expanded_descs is not None: + assert_equal(info["descriptor"], descsum_create(expanded_descs[0])) + assert_equal(info["multipath_expansion"], [descsum_create(x) for x in expanded_descs]) + else: + assert_equal(info['descriptor'], descsum_create(desc)) + assert "multipath_expansion" not in info assert_equal(info['isrange'], isrange) assert_equal(info['issolvable'], issolvable) assert_equal(info['hasprivatekeys'], hasprivatekeys) @@ -60,7 +65,12 @@ class DescriptorTest(BitcoinTestFramework): self.test_desc("pkh([d34db33f/44h/0h/0h]tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/*)", isrange=True, issolvable=True, hasprivatekeys=False) # A set of *1-of-2* P2WSH multisig outputs where the first multisig key is the *1/0/`i`* child of the first specified xpub and the second 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). self.test_desc("wsh(multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/0/*,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/0/0/*))", isrange=True, issolvable=True, hasprivatekeys=False) + # A multipath descriptor + self.test_desc("wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/<0;1>/*)", isrange=True, issolvable=True, hasprivatekeys=False, + expanded_descs=["wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/0/*)", "wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/*)"]) + self.test_desc("wsh(multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/<1;2>/0/*,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/<2;3>/0/*))", isrange=True, issolvable=True, hasprivatekeys=False, + expanded_descs=["wsh(multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/0/*,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/2/0/*))", "wsh(multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/2/0/*,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/3/0/*))"]) if __name__ == '__main__': - DescriptorTest().main() + DescriptorTest(__file__).main() diff --git a/test/functional/rpc_getorphantxs.py b/test/functional/rpc_getorphantxs.py new file mode 100755 index 0000000000..8d32ce1638 --- /dev/null +++ b/test/functional/rpc_getorphantxs.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-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 the getorphantxs RPC.""" + +from test_framework.mempool_util import tx_in_orphanage +from test_framework.messages import msg_tx +from test_framework.p2p import P2PInterface +from test_framework.util import assert_equal +from test_framework.test_framework import BitcoinTestFramework +from test_framework.wallet import MiniWallet + + +class GetOrphanTxsTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + self.test_orphan_activity() + self.test_orphan_details() + + def test_orphan_activity(self): + self.log.info("Check that orphaned transactions are returned with getorphantxs") + node = self.nodes[0] + + self.log.info("Create two 1P1C packages, but only broadcast the children") + tx_parent_1 = self.wallet.create_self_transfer() + tx_child_1 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_1["new_utxo"]) + tx_parent_2 = self.wallet.create_self_transfer() + tx_child_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_2["new_utxo"]) + peer = node.add_p2p_connection(P2PInterface()) + peer.send_and_ping(msg_tx(tx_child_1["tx"])) + peer.send_and_ping(msg_tx(tx_child_2["tx"])) + + self.log.info("Check that neither parent is in the mempool") + assert_equal(node.getmempoolinfo()["size"], 0) + + self.log.info("Check that both children are in the orphanage") + + orphanage = node.getorphantxs(verbosity=0) + self.log.info("Check the size of the orphanage") + assert_equal(len(orphanage), 2) + self.log.info("Check that negative verbosity is treated as 0") + assert_equal(orphanage, node.getorphantxs(verbosity=-1)) + assert tx_in_orphanage(node, tx_child_1["tx"]) + assert tx_in_orphanage(node, tx_child_2["tx"]) + + self.log.info("Broadcast parent 1") + peer.send_and_ping(msg_tx(tx_parent_1["tx"])) + self.log.info("Check that parent 1 and child 1 are in the mempool") + raw_mempool = node.getrawmempool() + assert_equal(len(raw_mempool), 2) + assert tx_parent_1["txid"] in raw_mempool + assert tx_child_1["txid"] in raw_mempool + + self.log.info("Check that orphanage only contains child 2") + orphanage = node.getorphantxs() + assert_equal(len(orphanage), 1) + assert tx_in_orphanage(node, tx_child_2["tx"]) + + peer.send_and_ping(msg_tx(tx_parent_2["tx"])) + self.log.info("Check that all parents and children are now in the mempool") + raw_mempool = node.getrawmempool() + assert_equal(len(raw_mempool), 4) + assert tx_parent_1["txid"] in raw_mempool + assert tx_child_1["txid"] in raw_mempool + assert tx_parent_2["txid"] in raw_mempool + assert tx_child_2["txid"] in raw_mempool + self.log.info("Check that the orphanage is empty") + assert_equal(len(node.getorphantxs()), 0) + + self.log.info("Confirm the transactions (clears mempool)") + self.generate(node, 1) + assert_equal(node.getmempoolinfo()["size"], 0) + + def test_orphan_details(self): + self.log.info("Check the transaction details returned from getorphantxs") + node = self.nodes[0] + + self.log.info("Create two orphans, from different peers") + tx_parent_1 = self.wallet.create_self_transfer() + tx_child_1 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_1["new_utxo"]) + tx_parent_2 = self.wallet.create_self_transfer() + tx_child_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_2["new_utxo"]) + peer_1 = node.add_p2p_connection(P2PInterface()) + peer_2 = node.add_p2p_connection(P2PInterface()) + peer_1.send_and_ping(msg_tx(tx_child_1["tx"])) + peer_2.send_and_ping(msg_tx(tx_child_2["tx"])) + + orphanage = node.getorphantxs(verbosity=2) + assert tx_in_orphanage(node, tx_child_1["tx"]) + assert tx_in_orphanage(node, tx_child_2["tx"]) + + self.log.info("Check that orphan 1 and 2 were from different peers") + assert orphanage[0]["from"][0] != orphanage[1]["from"][0] + + self.log.info("Unorphan child 2") + peer_2.send_and_ping(msg_tx(tx_parent_2["tx"])) + assert not tx_in_orphanage(node, tx_child_2["tx"]) + + self.log.info("Checking orphan details") + orphanage = node.getorphantxs(verbosity=1) + assert_equal(len(node.getorphantxs()), 1) + orphan_1 = orphanage[0] + self.orphan_details_match(orphan_1, tx_child_1, verbosity=1) + + self.log.info("Checking orphan details (verbosity 2)") + orphanage = node.getorphantxs(verbosity=2) + orphan_1 = orphanage[0] + self.orphan_details_match(orphan_1, tx_child_1, verbosity=2) + + def orphan_details_match(self, orphan, tx, verbosity): + self.log.info("Check txid/wtxid of orphan") + assert_equal(orphan["txid"], tx["txid"]) + assert_equal(orphan["wtxid"], tx["wtxid"]) + + self.log.info("Check the sizes of orphan") + assert_equal(orphan["bytes"], len(tx["tx"].serialize())) + assert_equal(orphan["vsize"], tx["tx"].get_vsize()) + assert_equal(orphan["weight"], tx["tx"].get_weight()) + + if verbosity == 2: + self.log.info("Check the transaction hex of orphan") + assert_equal(orphan["hex"], tx["hex"]) + + +if __name__ == '__main__': + GetOrphanTxsTest(__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 2701d2471d..b63059b1ee 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -237,28 +237,35 @@ class NetTest(BitcoinTestFramework): def test_addnode_getaddednodeinfo(self): self.log.info("Test addnode and getaddednodeinfo") assert_equal(self.nodes[0].getaddednodeinfo(), []) - # add a node (node2) to node0 + self.log.info("Add a node (node2) to node0") ip_port = "127.0.0.1:{}".format(p2p_port(2)) self.nodes[0].addnode(node=ip_port, command='add') - # try to add an equivalent ip - # (note that OpenBSD doesn't support the IPv4 shorthand notation with omitted zero-bytes) + self.log.info("Try to add an equivalent ip and check it fails") + self.log.debug("(note that OpenBSD doesn't support the IPv4 shorthand notation with omitted zero-bytes)") if platform.system() != "OpenBSD": ip_port2 = "127.1:{}".format(p2p_port(2)) assert_raises_rpc_error(-23, "Node already added", self.nodes[0].addnode, node=ip_port2, command='add') - # check that the node has indeed been added + self.log.info("Check that the node has indeed been added") added_nodes = self.nodes[0].getaddednodeinfo() assert_equal(len(added_nodes), 1) assert_equal(added_nodes[0]['addednode'], ip_port) - # check that node cannot be added again + self.log.info("Check that filtering by node works") + self.nodes[0].addnode(node="11.22.33.44", command='add') + first_added_node = self.nodes[0].getaddednodeinfo(node=ip_port) + assert_equal(added_nodes, first_added_node) + assert_equal(len(self.nodes[0].getaddednodeinfo()), 2) + self.log.info("Check that node cannot be added again") assert_raises_rpc_error(-23, "Node already added", self.nodes[0].addnode, node=ip_port, command='add') - # check that node can be removed + self.log.info("Check that node can be removed") self.nodes[0].addnode(node=ip_port, command='remove') - assert_equal(self.nodes[0].getaddednodeinfo(), []) - # check that an invalid command returns an error + added_nodes = self.nodes[0].getaddednodeinfo() + assert_equal(len(added_nodes), 1) + assert_equal(added_nodes[0]['addednode'], "11.22.33.44") + self.log.info("Check that an invalid command returns an error") assert_raises_rpc_error(-1, 'addnode "node" "command"', self.nodes[0].addnode, node=ip_port, command='abc') - # check that trying to remove the node again returns an error + self.log.info("Check that trying to remove the node again returns an error") assert_raises_rpc_error(-24, "Node could not be removed", self.nodes[0].addnode, node=ip_port, command='remove') - # check that a non-existent node returns an error + self.log.info("Check that a non-existent node returns an error") assert_raises_rpc_error(-24, "Node has not been added", self.nodes[0].getaddednodeinfo, '1.1.1.1') def test_service_flags(self): @@ -567,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 113424c0a6..ef2f66b3a0 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -394,7 +394,7 @@ class RPCPackagesTest(BitcoinTestFramework): peer = node.add_p2p_connection(P2PTxInvStore()) txs = self.wallet.create_self_transfer_chain(chain_length=2) bad_child = tx_from_hex(txs[1]["hex"]) - bad_child.nVersion = -1 + bad_child.version = 0xffffffff hex_partial_acceptance = [txs[0]["hex"], bad_child.serialize().hex()] res = node.submitpackage(hex_partial_acceptance) assert_equal(res["package_msg"], "transaction failed") @@ -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 3978c80dde..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") @@ -463,20 +463,34 @@ class RawTransactionsTest(BitcoinTestFramework): self.log.info("Test transaction version numbers") # Test the minimum transaction version number that fits in a signed 32-bit integer. - # As transaction version is unsigned, this should convert to its unsigned equivalent. + # As transaction version is serialized unsigned, this should convert to its unsigned equivalent. tx = CTransaction() - tx.nVersion = -0x80000000 + tx.version = 0x80000000 rawtx = tx.serialize().hex() decrawtx = self.nodes[0].decoderawtransaction(rawtx) assert_equal(decrawtx['version'], 0x80000000) # Test the maximum transaction version number that fits in a signed 32-bit integer. tx = CTransaction() - tx.nVersion = 0x7fffffff + tx.version = 0x7fffffff rawtx = tx.serialize().hex() decrawtx = self.nodes[0].decoderawtransaction(rawtx) assert_equal(decrawtx['version'], 0x7fffffff) + # Test the minimum transaction version number that fits in an unsigned 32-bit integer. + tx = CTransaction() + tx.version = 0 + rawtx = tx.serialize().hex() + decrawtx = self.nodes[0].decoderawtransaction(rawtx) + assert_equal(decrawtx['version'], 0) + + # Test the maximum transaction version number that fits in an unsigned 32-bit integer. + tx = CTransaction() + tx.version = 0xffffffff + rawtx = tx.serialize().hex() + decrawtx = self.nodes[0].decoderawtransaction(rawtx) + assert_equal(decrawtx['version'], 0xffffffff) + def raw_multisig_transaction_legacy_tests(self): self.log.info("Test raw multisig transactions (legacy)") # The traditional multisig workflow does not work with descriptor wallets so these are legacy only. @@ -585,6 +599,8 @@ class RawTransactionsTest(BitcoinTestFramework): rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(rawTx2, inputs) self.log.debug(rawTxPartialSigned2) assert_equal(rawTxPartialSigned2['complete'], False) # node2 only has one key, can't comp. sign the tx + assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].combinerawtransaction, [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex'] + "00"]) + assert_raises_rpc_error(-22, "Missing transactions", self.nodes[0].combinerawtransaction, []) rawTxComb = self.nodes[2].combinerawtransaction([rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']]) self.log.debug(rawTxComb) self.nodes[2].sendrawtransaction(rawTxComb) @@ -592,7 +608,8 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() self.generate(self.nodes[0], 1) assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') + Decimal('2.19000000')) # block reward + tx + assert_raises_rpc_error(-25, "Input not found or already spent", self.nodes[0].combinerawtransaction, [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']]) 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..a7b560ef57 100755 --- a/test/functional/rpc_scantxoutset.py +++ b/test/functional/rpc_scantxoutset.py @@ -110,6 +110,7 @@ class ScantxoutsetTest(BitcoinTestFramework): assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288")) assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672")) assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": [1500, 1500]}])['total_amount'], Decimal("16.384")) + assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "pkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/<0;1>)"}])["total_amount"], Decimal("12.288")) # Test the reported descriptors for a few matches assert_equal(descriptors(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0h/*)", "range": 1499}])), ["pkh([0c5f9a1e/0h/0h/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#rthll0rg", "pkh([0c5f9a1e/0h/0h/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#mcjajulr"]) @@ -120,7 +121,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 +140,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 268584331e..b359a08f39 100755 --- a/test/functional/rpc_signrawtransactionwithkey.py +++ b/test/functional/rpc_signrawtransactionwithkey.py @@ -4,18 +4,18 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test transaction signing using the signrawtransactionwithkey RPC.""" -from test_framework.blocktools import ( - COINBASE_MATURITY, +from test_framework.messages import ( + COIN, ) from test_framework.address import ( address_to_scriptpubkey, + p2a, script_to_p2sh, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, - find_vout_for_address, ) from test_framework.script_util import ( key_to_p2pk_script, @@ -25,6 +25,7 @@ from test_framework.script_util import ( ) from test_framework.wallet import ( getnewdestination, + MiniWallet, ) from test_framework.wallet_util import ( generate_keypair, @@ -45,16 +46,12 @@ OUTPUTS = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1} class SignRawTransactionWithKeyTest(BitcoinTestFramework): def set_test_params(self): - self.setup_clean_chain = True - self.num_nodes = 2 + self.num_nodes = 1 def send_to_address(self, addr, amount): - input = {"txid": self.nodes[0].getblock(self.block_hash[self.blk_idx])["tx"][0], "vout": 0} - output = {addr: amount} - self.blk_idx += 1 - rawtx = self.nodes[0].createrawtransaction([input], output) - txid = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransactionwithkey(rawtx, [self.nodes[0].get_deterministic_priv_key().key])["hex"], 0) - return txid + script_pub_key = address_to_scriptpubkey(addr) + tx = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=script_pub_key, amount=int(amount * COIN)) + return tx["txid"], tx["sent_vout"] def assert_signing_completed_successfully(self, signed_tx): assert 'errors' not in signed_tx @@ -79,14 +76,12 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework): self.log.info("Test signing transaction to P2SH-P2WSH addresses without wallet") # Create a new P2SH-P2WSH 1-of-1 multisig address: embedded_privkey, embedded_pubkey = generate_keypair(wif=True) - p2sh_p2wsh_address = self.nodes[1].createmultisig(1, [embedded_pubkey.hex()], "p2sh-segwit") + p2sh_p2wsh_address = self.nodes[0].createmultisig(1, [embedded_pubkey.hex()], "p2sh-segwit") # send transaction to P2SH-P2WSH 1-of-1 multisig address - self.block_hash = self.generate(self.nodes[0], COINBASE_MATURITY + 1) - self.blk_idx = 0 self.send_to_address(p2sh_p2wsh_address["address"], 49.999) self.generate(self.nodes[0], 1) # Get the UTXO info from scantxoutset - unspent_output = self.nodes[1].scantxoutset('start', [p2sh_p2wsh_address['descriptor']])['unspents'][0] + unspent_output = self.nodes[0].scantxoutset('start', [p2sh_p2wsh_address['descriptor']])['unspents'][0] spk = script_to_p2sh_p2wsh_script(p2sh_p2wsh_address['redeemScript']).hex() unspent_output['witnessScript'] = p2sh_p2wsh_address['redeemScript'] unspent_output['redeemScript'] = script_to_p2wsh_script(unspent_output['witnessScript']).hex() @@ -100,6 +95,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") + [txid, vout] = self.send_to_address(p2a(), 49.999) + spending_tx = self.nodes[0].createrawtransaction( + [{"txid": txid, "vout": vout}], + [{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) @@ -111,9 +118,7 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework): addr = script_to_p2sh(redeem_script) script_pub_key = address_to_scriptpubkey(addr).hex() # Fund that address - txid = self.send_to_address(addr, 10) - vout = find_vout_for_address(self.nodes[0], txid, addr) - self.generate(self.nodes[0], 1) + [txid, vout] = self.send_to_address(addr, 10) # Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys spending_tx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], {getnewdestination()[2]: Decimal("9.999")}) spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [{'txid': txid, 'vout': vout, 'scriptPubKey': script_pub_key, 'redeemScript': redeem_script, 'witnessScript': witness_script, 'amount': 10}]) @@ -126,11 +131,23 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework): privkeys = [self.nodes[0].get_deterministic_priv_key().key] assert_raises_rpc_error(-8, "'all' is not a valid sighash parameter.", self.nodes[0].signrawtransactionwithkey, tx, privkeys, sighashtype="all") + def invalid_private_key_and_tx(self): + self.log.info("Test signing transaction with an invalid private key") + tx = self.nodes[0].createrawtransaction(INPUTS, OUTPUTS) + privkeys = ["123"] + assert_raises_rpc_error(-5, "Invalid private key", self.nodes[0].signrawtransactionwithkey, tx, privkeys) + self.log.info("Test signing transaction with an invalid tx hex") + privkeys = [self.nodes[0].get_deterministic_priv_key().key] + assert_raises_rpc_error(-22, "TX decode failed. Make sure the tx has at least one input.", self.nodes[0].signrawtransactionwithkey, tx + "00", privkeys) + def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) 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..90572245d6 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -67,6 +67,10 @@ class MerkleBlockTest(BitcoinTestFramework): assert_equal(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid_spent], blockhash)), [txid_spent]) # We can't get the proof if we specify a non-existent block assert_raises_rpc_error(-5, "Block not found", self.nodes[0].gettxoutproof, [txid_spent], "0000000000000000000000000000000000000000000000000000000000000000") + # We can't get the proof if we only have the header of the specified block + block = self.generateblock(self.nodes[0], output="raw(55)", transactions=[], submit=False) + self.nodes[0].submitheader(block["hex"]) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", self.nodes[0].gettxoutproof, [txid_spent], block['hash']) # We can get the proof if the transaction is unspent assert_equal(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid_unspent])), [txid_unspent]) # We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter. @@ -104,4 +108,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 66cdd7cf9a..49eb64abad 100755 --- a/test/functional/rpc_users.py +++ b/test/functional/rpc_users.py @@ -11,12 +11,15 @@ from test_framework.util import ( ) import http.client +import os +import platform import urllib.parse import subprocess from random import SystemRandom import string import configparser import sys +from typing import Optional def call_with_auth(node, user, password): @@ -84,6 +87,40 @@ class HTTPBasicsTest(BitcoinTestFramework): self.log.info('Wrong...') assert_equal(401, call_with_auth(node, user + 'wrong', password + 'wrong').status) + def test_rpccookieperms(self): + p = {"owner": 0o600, "group": 0o640, "all": 0o644} + + if platform.system() == 'Windows': + self.log.info(f"Skip cookie file permissions checks as OS detected as: {platform.system()=}") + return + + self.log.info('Check cookie file permissions can be set using -rpccookieperms') + + cookie_file_path = self.nodes[1].chain_path / '.cookie' + PERM_BITS_UMASK = 0o777 + + def test_perm(perm: Optional[str]): + if not perm: + perm = 'owner' + self.restart_node(1) + else: + self.restart_node(1, extra_args=[f"-rpccookieperms={perm}"]) + + file_stat = os.stat(cookie_file_path) + actual_perms = file_stat.st_mode & PERM_BITS_UMASK + expected_perms = p[perm] + assert_equal(expected_perms, actual_perms) + + # Remove any leftover rpc{user|password} config options from previous tests + self.nodes[1].replace_in_config([("rpcuser", "#rpcuser"), ("rpcpassword", "#rpcpassword")]) + + self.log.info('Check default cookie permission') + test_perm(None) + + self.log.info('Check custom cookie permissions') + for perm in ["owner", "group", "all"]: + test_perm(perm) + def run_test(self): self.conf_setup() self.log.info('Check correctness of the rpcauth config option') @@ -102,19 +139,38 @@ class HTTPBasicsTest(BitcoinTestFramework): init_error = 'Error: Unable to start HTTP server. See debug log for details.' self.log.info('Check -rpcauth are validated') - # Empty -rpcauth= are ignored - self.restart_node(0, extra_args=['-rpcauth=']) + self.log.info('Empty -rpcauth are treated as error') self.stop_node(0) + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth']) + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=']) + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=""']) + self.log.info('Check malformed -rpcauth') self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=foo']) self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=foo:bar']) self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=foo:bar:baz']) self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=foo$bar:baz']) self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=foo$bar$baz']) + self.log.info('Check interactions between blank and non-blank rpcauth') + # pw = bitcoin + rpcauth_user1 = '-rpcauth=user1:6dd184e5e69271fdd69103464630014f$eb3d7ce67c4d1ff3564270519b03b636c0291012692a5fa3dd1d2075daedd07b' + rpcauth_user2 = '-rpcauth=user2:57b2f77c919eece63cfa46c2f06e46ae$266b63902f99f97eeaab882d4a87f8667ab84435c3799f2ce042ef5a994d620b' + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=[rpcauth_user1, rpcauth_user2, '-rpcauth=']) + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=[rpcauth_user1, '-rpcauth=', rpcauth_user2]) + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=', rpcauth_user1, rpcauth_user2]) + + self.log.info('Check -norpcauth disables previous -rpcauth params') + self.restart_node(0, extra_args=[rpcauth_user1, rpcauth_user2, '-norpcauth']) + assert_equal(401, call_with_auth(self.nodes[0], 'user1', 'bitcoin').status) + assert_equal(401, call_with_auth(self.nodes[0], 'rt', self.rtpassword).status) + self.stop_node(0) + self.log.info('Check that failure to write cookie file will abort the node gracefully') (self.nodes[0].chain_path / ".cookie.tmp").mkdir() self.nodes[0].assert_start_raises_init_error(expected_msg=init_error) + self.test_rpccookieperms() + 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/authproxy.py b/test/functional/test_framework/authproxy.py index 7edf9f3679..a357ae4d34 100644 --- a/test/functional/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py @@ -26,7 +26,7 @@ ServiceProxy class: - HTTP connections persist for the life of the AuthServiceProxy object (if server supports HTTP/1.1) -- sends protocol 'version', per JSON-RPC 1.1 +- sends "jsonrpc":"2.0", per JSON-RPC 2.0 - sends proper, incrementing 'id' - sends Basic HTTP authentication headers - parses all JSON numbers that look like floats as Decimal @@ -117,7 +117,7 @@ class AuthServiceProxy(): params = dict(args=args, **argsn) else: params = args or argsn - return {'version': '1.1', + return {'jsonrpc': '2.0', 'method': self._service_name, 'params': params, 'id': AuthServiceProxy.__id_count} @@ -125,15 +125,28 @@ class AuthServiceProxy(): def __call__(self, *args, **argsn): postdata = json.dumps(self.get_request(*args, **argsn), default=serialization_fallback, ensure_ascii=self.ensure_ascii) response, status = self._request('POST', self.__url.path, postdata.encode('utf-8')) - if response['error'] is not None: - raise JSONRPCException(response['error'], status) - elif 'result' not in response: - raise JSONRPCException({ - 'code': -343, 'message': 'missing JSON-RPC result'}, status) - elif status != HTTPStatus.OK: - raise JSONRPCException({ - 'code': -342, 'message': 'non-200 HTTP status code but no JSON-RPC error'}, status) + # For backwards compatibility tests, accept JSON RPC 1.1 responses + if 'jsonrpc' not in response: + if response['error'] is not None: + raise JSONRPCException(response['error'], status) + elif 'result' not in response: + raise JSONRPCException({ + 'code': -343, 'message': 'missing JSON-RPC result'}, status) + elif status != HTTPStatus.OK: + raise JSONRPCException({ + 'code': -342, 'message': 'non-200 HTTP status code but no JSON-RPC error'}, status) + else: + return response['result'] else: + assert response['jsonrpc'] == '2.0' + if status != HTTPStatus.OK: + raise JSONRPCException({ + 'code': -342, 'message': 'non-200 HTTP status code'}, status) + if 'error' in response: + raise JSONRPCException(response['error'], status) + elif 'result' not in response: + raise JSONRPCException({ + 'code': -343, 'message': 'missing JSON-RPC 2.0 result and error'}, status) return response['result'] def batch(self, rpc_call_list): @@ -142,7 +155,7 @@ class AuthServiceProxy(): response, status = self._request('POST', self.__url.path, postdata.encode('utf-8')) if status != HTTPStatus.OK: raise JSONRPCException({ - 'code': -342, 'message': 'non-200 HTTP status code but no JSON-RPC error'}, status) + 'code': -342, 'message': 'non-200 HTTP status code'}, status) return response def _get_response(self): diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index f0dc866f69..705b8e8fe5 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2022 The Bitcoin Core developers +# Copyright (c) 2015-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. """Utilities for manipulating blocks and transactions.""" @@ -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 @@ -73,7 +74,7 @@ def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl block.nVersion = version or tmpl.get('version') or VERSIONBITS_LAST_OLD_BLOCK_VERSION block.nTime = ntime or tmpl.get('curtime') or int(time.time() + 600) block.hashPrevBlock = hashprev or int(tmpl['previousblockhash'], 0x10) - if tmpl and not tmpl.get('bits') is None: + if tmpl and tmpl.get('bits') is not None: block.nBits = struct.unpack('>I', bytes.fromhex(tmpl['bits']))[0] else: block.nBits = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams @@ -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/mempool_util.py b/test/functional/test_framework/mempool_util.py index 148cc935ed..a6a7940c60 100644 --- a/test/functional/test_framework/mempool_util.py +++ b/test/functional/test_framework/mempool_util.py @@ -8,6 +8,7 @@ from decimal import Decimal from .blocktools import ( COINBASE_MATURITY, ) +from .messages import CTransaction from .util import ( assert_equal, assert_greater_than, @@ -19,14 +20,11 @@ from .wallet import ( ) -def fill_mempool(test_framework, node): +def fill_mempool(test_framework, node, *, tx_sync_fun=None): """Fill mempool until eviction. Allows for simpler testing of scenarios with floating mempoolminfee > minrelay - Requires -datacarriersize=100000 and - -maxmempool=5. - It will not ensure mempools become synced as it - is based on a single node and assumes -minrelaytxfee + Requires -datacarriersize=100000 and -maxmempool=5 and assumes -minrelaytxfee is 1 sat/vbyte. To avoid unintentional tx dependencies, the mempool filling txs are created with a tagged ephemeral miniwallet instance. @@ -57,18 +55,25 @@ def fill_mempool(test_framework, node): tx_to_be_evicted_id = ephemeral_miniwallet.send_self_transfer( from_node=node, utxo_to_spend=confirmed_utxos.pop(0), fee_rate=relayfee)["txid"] + def send_batch(fee): + utxos = confirmed_utxos[:tx_batch_size] + create_lots_of_big_transactions(ephemeral_miniwallet, node, fee, tx_batch_size, txouts, utxos) + del confirmed_utxos[:tx_batch_size] + # Increase the tx fee rate to give the subsequent transactions a higher priority in the mempool # The tx has an approx. vsize of 65k, i.e. multiplying the previous fee rate (in sats/kvB) # by 130 should result in a fee that corresponds to 2x of that fee rate base_fee = relayfee * 130 + batch_fees = [(i + 1) * base_fee for i in range(num_of_batches)] test_framework.log.debug("Fill up the mempool with txs with higher fee rate") - with node.assert_debug_log(["rolling minimum fee bumped"]): - for batch_of_txid in range(num_of_batches): - fee = (batch_of_txid + 1) * base_fee - utxos = confirmed_utxos[:tx_batch_size] - create_lots_of_big_transactions(ephemeral_miniwallet, node, fee, tx_batch_size, txouts, utxos) - del confirmed_utxos[:tx_batch_size] + for fee in batch_fees[:-3]: + send_batch(fee) + tx_sync_fun() if tx_sync_fun else test_framework.sync_mempools() # sync before any eviction + assert_equal(node.getmempoolinfo()["mempoolminfee"], Decimal("0.00001000")) + for fee in batch_fees[-3:]: + send_batch(fee) + tx_sync_fun() if tx_sync_fun else test_framework.sync_mempools() # sync after all evictions test_framework.log.debug("The tx should be evicted by now") # The number of transactions created should be greater than the ones present in the mempool @@ -79,3 +84,8 @@ def fill_mempool(test_framework, node): test_framework.log.debug("Check that mempoolminfee is larger than minrelaytxfee") assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000')) assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000')) + +def tx_in_orphanage(node, tx: CTransaction) -> bool: + """Returns true if the transaction is in the orphanage.""" + found = [o for o in node.getorphantxs(verbosity=1) if o["txid"] == tx.rehash() and o["wtxid"] == tx.getwtxid()] + return len(found) == 1 diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 4e496a9275..1f566a1348 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -560,12 +560,12 @@ class CTxWitness: class CTransaction: - __slots__ = ("hash", "nLockTime", "nVersion", "sha256", "vin", "vout", + __slots__ = ("hash", "nLockTime", "version", "sha256", "vin", "vout", "wit") def __init__(self, tx=None): if tx is None: - self.nVersion = 2 + self.version = 2 self.vin = [] self.vout = [] self.wit = CTxWitness() @@ -573,7 +573,7 @@ class CTransaction: self.sha256 = None self.hash = None else: - self.nVersion = tx.nVersion + self.version = tx.version self.vin = copy.deepcopy(tx.vin) self.vout = copy.deepcopy(tx.vout) self.nLockTime = tx.nLockTime @@ -582,7 +582,7 @@ class CTransaction: self.wit = copy.deepcopy(tx.wit) def deserialize(self, f): - self.nVersion = int.from_bytes(f.read(4), "little", signed=True) + self.version = int.from_bytes(f.read(4), "little") self.vin = deser_vector(f, CTxIn) flags = 0 if len(self.vin) == 0: @@ -605,7 +605,7 @@ class CTransaction: def serialize_without_witness(self): r = b"" - r += self.nVersion.to_bytes(4, "little", signed=True) + r += self.version.to_bytes(4, "little") r += ser_vector(self.vin) r += ser_vector(self.vout) r += self.nLockTime.to_bytes(4, "little") @@ -617,7 +617,7 @@ class CTransaction: if not self.wit.is_null(): flags |= 1 r = b"" - r += self.nVersion.to_bytes(4, "little", signed=True) + r += self.version.to_bytes(4, "little") if flags: dummy = [] r += ser_vector(dummy) @@ -677,8 +677,8 @@ class CTransaction: return math.ceil(self.get_weight() / WITNESS_SCALE_FACTOR) def __repr__(self): - return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ - % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) + return "CTransaction(version=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ + % (self.version, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) class CBlockHeader: @@ -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 ab3dc2ffb1..d510cf9b1c 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -738,7 +738,7 @@ def SegwitV0SignatureMsg(script, txTo, inIdx, hashtype, amount): hashOutputs = uint256_from_str(hash256(serialize_outputs)) ss = bytes() - ss += txTo.nVersion.to_bytes(4, "little", signed=True) + ss += txTo.version.to_bytes(4, "little") ss += ser_uint256(hashPrevouts) ss += ser_uint256(hashSequence) ss += txTo.vin[inIdx].prevout.serialize() @@ -810,14 +810,14 @@ 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 in_type = hash_type & SIGHASH_ANYONECANPAY spk = spent_utxos[input_index].scriptPubKey ss = bytes([0, hash_type]) # epoch, hash_type - ss += txTo.nVersion.to_bytes(4, "little", signed=True) + ss += txTo.version.to_bytes(4, "little") ss += txTo.nLockTime.to_bytes(4, "little") if in_type != SIGHASH_ANYONECANPAY: ss += BIP341_sha_prevouts(txTo) @@ -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 62894cc0f4..938183ece4 100755 --- a/test/functional/test_framework/script_util.py +++ b/test/functional/test_framework/script_util.py @@ -3,10 +3,14 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Useful Script constants and utils.""" +import unittest + from test_framework.script import ( CScript, - CScriptOp, OP_0, + OP_1, + OP_15, + OP_16, OP_CHECKMULTISIG, OP_CHECKSIG, OP_DUP, @@ -39,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]) @@ -49,10 +55,8 @@ def keys_to_multisig_script(keys, *, k=None): if k is None: # n-of-n multisig by default k = n assert k <= n - op_k = CScriptOp.encode_op_n(k) - op_n = CScriptOp.encode_op_n(n) checked_keys = [check_key(key) for key in keys] - return CScript([op_k] + checked_keys + [op_n, OP_CHECKMULTISIG]) + return CScript([k] + checked_keys + [n, OP_CHECKMULTISIG]) def keyhash_to_p2pkh_script(hash): @@ -125,3 +129,19 @@ def check_script(script): if isinstance(script, bytes) or isinstance(script, CScript): return script assert False + + +class TestFrameworkScriptUtil(unittest.TestCase): + def test_multisig(self): + fake_pubkey = bytes([0]*33) + # check correct encoding of P2MS script with n,k <= 16 + normal_ms_script = keys_to_multisig_script([fake_pubkey]*16, k=15) + self.assertEqual(len(normal_ms_script), 1 + 16*34 + 1 + 1) + self.assertTrue(normal_ms_script.startswith(bytes([OP_15]))) + self.assertTrue(normal_ms_script.endswith(bytes([OP_16, OP_CHECKMULTISIG]))) + + # check correct encoding of P2MS script with n,k > 16 + max_ms_script = keys_to_multisig_script([fake_pubkey]*20, k=19) + self.assertEqual(len(max_ms_script), 2 + 20*34 + 2 + 1) + self.assertTrue(max_ms_script.startswith(bytes([1, 19]))) # using OP_PUSH1 + self.assertTrue(max_ms_script.endswith(bytes([1, 20, OP_CHECKMULTISIG]))) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 4231cbf495..49212eb019 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2022 The Bitcoin Core developers +# Copyright (c) 2014-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. """Base class for RPC testing.""" @@ -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") @@ -636,11 +636,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): def find_conn(node, peer_subversion, inbound): return next(filter(lambda peer: peer['subver'] == peer_subversion and peer['inbound'] == inbound, node.getpeerinfo()), None) - # poll until version handshake complete to avoid race conditions - # with transaction relaying - # See comments in net_processing: - # * Must have a version message before anything else - # * Must have a verack message before anything else self.wait_until(lambda: find_conn(from_connection, to_connection_subver, inbound=False) is not None) self.wait_until(lambda: find_conn(to_connection, from_connection_subver, inbound=True) is not None) @@ -648,11 +643,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): assert peer is not None, "Error: peer disconnected" return peer['bytesrecv_per_msg'].pop(msg_type, 0) >= min_bytes_recv - self.wait_until(lambda: check_bytesrecv(find_conn(from_connection, to_connection_subver, inbound=False), 'verack', 21)) - self.wait_until(lambda: check_bytesrecv(find_conn(to_connection, from_connection_subver, inbound=True), 'verack', 21)) - - # The message bytes are counted before processing the message, so make - # sure it was fully processed by waiting for a ping. + # Poll until version handshake (fSuccessfullyConnected) is complete to + # avoid race conditions, because some message types are blocked from + # being sent or received before fSuccessfullyConnected. + # + # As the flag fSuccessfullyConnected is not exposed, check it by + # waiting for a pong, which can only happen after the flag was set. self.wait_until(lambda: check_bytesrecv(find_conn(from_connection, to_connection_subver, inbound=False), 'pong', 29)) self.wait_until(lambda: check_bytesrecv(find_conn(to_connection, from_connection_subver, inbound=True), 'pong', 29)) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 94ae96312e..60ca9269a5 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -39,9 +39,15 @@ from .util import ( rpc_url, wait_until_helper_internal, p2p_port, + tor_port, ) BITCOIND_PROC_WAIT_TIMEOUT = 60 +# The size of the blocks xor key +# from InitBlocksdirXorKey::xor_key.size() +NUM_XOR_BYTES = 8 +# The null blocks key (all 0s) +NULL_BLK_XOR_KEY = bytes([0] * NUM_XOR_BYTES) class FailedToStartError(Exception): @@ -88,8 +94,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 +219,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 @@ -241,7 +261,7 @@ class TestNode(): if self.start_perf: self._start_perf() - def wait_for_rpc_connection(self): + def wait_for_rpc_connection(self, *, wait_for_import=True): """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" # Poll at a rate of four times per second poll_per_s = 4 @@ -263,7 +283,7 @@ class TestNode(): ) rpc.getblockcount() # If the call to getblockcount() succeeds then the RPC connection is up - if self.version_is_at_least(190000): + if self.version_is_at_least(190000) and wait_for_import: # getmempoolinfo.loaded is available since commit # bb8ae2c (version 0.19.0) self.wait_until(lambda: rpc.getmempoolinfo()['loaded']) @@ -451,6 +471,14 @@ class TestNode(): return self.chain_path / "blocks" @property + def blocks_key_path(self) -> Path: + return self.blocks_path / "xor.dat" + + def read_xor_key(self) -> bytes: + with open(self.blocks_key_path, "rb") as xor_f: + return xor_f.read(NUM_XOR_BYTES) + + @property def wallets_path(self) -> Path: return self.chain_path / "wallets" @@ -666,7 +694,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 +714,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 +721,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/test_shell.py b/test/functional/test_framework/test_shell.py index 09ccec28a1..e232430507 100644 --- a/test/functional/test_framework/test_shell.py +++ b/test/functional/test_framework/test_shell.py @@ -2,9 +2,11 @@ # 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. +import pathlib from test_framework.test_framework import BitcoinTestFramework + class TestShell: """Wrapper Class for BitcoinTestFramework. @@ -67,7 +69,13 @@ class TestShell: # This implementation enforces singleton pattern, and will return the # previously initialized instance if available if not TestShell.instance: - TestShell.instance = TestShell.__TestShell() + # BitcoinTestFramework instances are supposed to be constructed with the path + # of the calling test in order to find shared data like configuration and the + # cache. Since TestShell is meant for interactive use, there is no concrete + # test; passing a dummy name is fine though, as only the containing directory + # is relevant for successful initialization. + tests_directory = pathlib.Path(__file__).resolve().parent.parent + TestShell.instance = TestShell.__TestShell(tests_directory / "testshell_dummy.py") TestShell.instance.running = False return TestShell.instance diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index c5b69a3954..ce68de7eaa 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -5,7 +5,7 @@ """Helpful routines for regression testing.""" from base64 import b64encode -from decimal import Decimal, ROUND_DOWN +from decimal import Decimal from subprocess import CalledProcessError import hashlib import inspect @@ -14,13 +14,16 @@ import logging import os import pathlib import platform +import random import re import time from . import coverage from .authproxy import AuthServiceProxy, JSONRPCException from collections.abc import Callable -from typing import Optional +from typing import Optional, Union + +SATOSHI_PRECISION = Decimal('0.00000001') logger = logging.getLogger("TestFramework.utils") @@ -247,6 +250,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 @@ -254,8 +263,9 @@ def get_fee(tx_size, feerate_btc_kvb): return target_fee_sat / Decimal(1e8) # Return result in BTC -def satoshi_round(amount): - return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) +def satoshi_round(amount: Union[int, float, str], *, rounding: str) -> Decimal: + """Rounds a Decimal amount to the nearest satoshi using the specified rounding mode.""" + return Decimal(amount).quantize(SATOSHI_PRECISION, rounding=rounding) def wait_until_helper_internal(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, timeout_factor=1.0): @@ -304,14 +314,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 +368,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): 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 4433cbcc55..1cef714705 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -33,10 +33,11 @@ from test_framework.messages import ( CTxInWitness, CTxOut, hash256, + ser_compact_size, ) from test_framework.script import ( CScript, - LEAF_VERSION_TAPSCRIPT, + OP_1, OP_NOP, OP_RETURN, OP_TRUE, @@ -52,6 +53,7 @@ from test_framework.script_util import ( from test_framework.util import ( assert_equal, assert_greater_than_or_equal, + get_fee, ) from test_framework.wallet_util import generate_keypair @@ -101,8 +103,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 @@ -115,17 +117,18 @@ class MiniWallet: def _create_utxo(self, *, txid, vout, value, height, coinbase, confirmations): return {"txid": txid, "vout": vout, "value": value, "height": height, "coinbase": coinbase, "confirmations": confirmations} - def _bulk_tx(self, tx, target_weight): - """Pad a transaction with extra outputs until it reaches a target weight (or higher). + def _bulk_tx(self, tx, target_vsize): + """Pad a transaction with extra outputs until it reaches a target vsize. returns the tx """ - tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN, b'a']))) - dummy_vbytes = (target_weight - tx.get_weight() + 3) // 4 - tx.vout[-1].scriptPubKey = CScript([OP_RETURN, b'a' * dummy_vbytes]) - # Lower bound should always be off by at most 3 - assert_greater_than_or_equal(tx.get_weight(), target_weight) - # Higher bound should always be off by at most 3 + 12 weight (for encoding the length) - assert_greater_than_or_equal(target_weight + 15, tx.get_weight()) + tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN]))) + # determine number of needed padding bytes + dummy_vbytes = target_vsize - tx.get_vsize() + # compensate for the increase of the compact-size encoded script length + # (note that the length encoding of the unpadded output script needs one byte) + dummy_vbytes -= len(ser_compact_size(dummy_vbytes)) - 1 + tx.vout[-1].scriptPubKey = CScript([OP_RETURN] + [OP_1] * dummy_vbytes) + assert_equal(tx.get_vsize(), target_vsize) def get_balance(self): return sum(u['value'] for u in self._utxos) @@ -187,7 +190,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 @@ -297,7 +305,7 @@ class MiniWallet: locktime=0, sequence=0, fee_per_output=1000, - target_weight=0, + target_vsize=0, confirmed_only=False, ): """ @@ -321,13 +329,13 @@ class MiniWallet: tx = CTransaction() tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=seq) for utxo_to_spend, seq in zip(utxos_to_spend, sequence)] tx.vout = [CTxOut(amount_per_output, bytearray(self._scriptPubKey)) for _ in range(num_outputs)] - tx.nVersion = version + tx.version = version tx.nLockTime = locktime self.sign_tx(tx) - if target_weight: - self._bulk_tx(tx, target_weight) + if target_vsize: + self._bulk_tx(tx, target_vsize) txid = tx.rehash() return { @@ -352,7 +360,7 @@ class MiniWallet: fee_rate=Decimal("0.003"), fee=Decimal("0"), utxo_to_spend=None, - target_weight=0, + target_vsize=0, confirmed_only=False, **kwargs, ): @@ -367,16 +375,18 @@ class MiniWallet: vsize = Decimal(168) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other) else: assert False + if target_vsize and not fee: # respect fee_rate if target vsize is passed + fee = get_fee(target_vsize, fee_rate) send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000)) # create tx tx = self.create_self_transfer_multi( utxos_to_spend=[utxo_to_spend], amount_per_output=int(COIN * send_value), - target_weight=target_weight, + target_vsize=target_vsize, **kwargs, ) - if not target_weight: + if not target_vsize: assert_equal(tx["tx"].get_vsize(), vsize) tx["new_utxo"] = tx.pop("new_utxos")[0] diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 725b116281..3d8c230066 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -15,8 +15,10 @@ For a description of arguments recognized by test scripts, see import argparse from collections import deque import configparser +import csv import datetime import os +import pathlib import platform import time import shutil @@ -94,10 +96,13 @@ BASE_SCRIPTS = [ 'feature_fee_estimation.py', 'feature_taproot.py', 'feature_block.py', + 'p2p_node_network_limited.py --v1transport', + 'p2p_node_network_limited.py --v2transport', # vv Tests less than 2m vv 'mining_getblocktemplate_longpoll.py', 'p2p_segwit.py', 'feature_maxuploadtarget.py', + 'feature_assumeutxo.py', 'mempool_updatefromblock.py', 'mempool_persist.py --descriptors', # vv Tests less than 60s vv @@ -155,6 +160,7 @@ BASE_SCRIPTS = [ 'wallet_importmulti.py --legacy-wallet', 'mempool_limit.py', 'rpc_txoutproof.py', + 'rpc_getorphantxs.py', 'wallet_listreceivedby.py --legacy-wallet', 'wallet_listreceivedby.py --descriptors', 'wallet_abandonconflict.py --legacy-wallet', @@ -262,9 +268,9 @@ 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_accept_v3.py', + 'mempool_truc.py', 'wallet_txn_doublespend.py --legacy-wallet', 'wallet_multisig_descriptor_psbt.py --descriptors', 'wallet_txn_doublespend.py --descriptors', @@ -280,7 +286,9 @@ BASE_SCRIPTS = [ 'mempool_packages.py', 'mempool_package_onemore.py', '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', @@ -350,7 +358,6 @@ BASE_SCRIPTS = [ 'wallet_coinbase_category.py --descriptors', 'feature_filelock.py', 'feature_loadblock.py', - 'feature_assumeutxo.py', 'wallet_assumeutxo.py --descriptors', 'p2p_dos_header_tree.py', 'p2p_add_connections.py', @@ -361,6 +368,7 @@ BASE_SCRIPTS = [ 'feature_addrman.py', 'feature_asmap.py', 'feature_fastprune.py', + 'feature_framework_miniwallet.py', 'mempool_unbroadcast.py', 'mempool_compatibility.py', 'mempool_accept_wtxid.py', @@ -380,8 +388,6 @@ BASE_SCRIPTS = [ 'feature_coinstatsindex.py', 'wallet_orphanedreward.py', 'wallet_timelock.py', - 'p2p_node_network_limited.py --v1transport', - 'p2p_node_network_limited.py --v2transport', 'p2p_permissions.py', 'feature_blocksdir.py', 'wallet_startup.py', @@ -401,6 +407,7 @@ BASE_SCRIPTS = [ 'feature_shutdown.py', 'wallet_migration.py', 'p2p_ibd_txrelay.py', + 'p2p_seednode.py', # Don't append tests at the end to avoid merge conflicts # Put them in a random line within the section that fits their approximate run-time ] @@ -438,9 +445,10 @@ def main(): parser.add_argument('--filter', help='filter scripts to run by regular expression') parser.add_argument("--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave bitcoinds and test.* datadir on exit or error") - + parser.add_argument('--resultsfile', '-r', help='store test results (as CSV) to the provided file') args, unknown_args = parser.parse_known_args() + fail_on_warn = args.ci if not args.ansi: global DEFAULT, BOLD, GREEN, RED DEFAULT = ("", "") @@ -470,11 +478,18 @@ def main(): logging.debug("Temporary test directory at %s" % tmpdir) + results_filepath = None + if args.resultsfile: + results_filepath = pathlib.Path(args.resultsfile) + # Stop early if the parent directory doesn't exist + assert results_filepath.parent.exists(), "Results file parent directory does not exist" + logging.debug("Test results will be written to " + str(results_filepath)) + enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND") if not enable_bitcoind: print("No functional tests to run.") - print("Rerun ./configure with --with-daemon and then make") + print("Re-compile with the -DBUILD_DAEMON=ON build option") sys.exit(1) # Build list of tests @@ -508,15 +523,28 @@ def main(): test_list += BASE_SCRIPTS # Remove the test cases that the user has explicitly asked to exclude. + # The user can specify a test case with or without the .py extension. if args.exclude: - exclude_tests = [test.split('.py')[0] for test in args.exclude.split(',')] - for exclude_test in exclude_tests: - # Remove <test_name>.py and <test_name>.py --arg from the test list - exclude_list = [test for test in test_list if test.split('.py')[0] == exclude_test] + + def print_warning_missing_test(test_name): + print("{}WARNING!{} Test '{}' not found in current test list. Check the --exclude list.".format(BOLD[1], BOLD[0], test_name)) + if fail_on_warn: + sys.exit(1) + + def remove_tests(exclude_list): + if not exclude_list: + print_warning_missing_test(exclude_test) for exclude_item in exclude_list: test_list.remove(exclude_item) - if not exclude_list: - print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], exclude_test)) + + exclude_tests = [test.strip() for test in args.exclude.split(",")] + for exclude_test in exclude_tests: + # A space in the name indicates it has arguments such as "wallet_basic.py --descriptors" + if ' ' in exclude_test: + remove_tests([test for test in test_list if test.replace('.py', '') == exclude_test.replace('.py', '')]) + else: + # Exclude all variants of a test + remove_tests([test for test in test_list if test.split('.py')[0] == exclude_test.split('.py')[0]]) if args.filter: test_list = list(filter(re.compile(args.filter).search, test_list)) @@ -539,7 +567,7 @@ def main(): f"A minimum of {MIN_NO_CLEANUP_SPACE // (1024 * 1024 * 1024)} GB of free space is required.") passon_args.append("--nocleanup") - check_script_list(src_dir=config["environment"]["SRCDIR"], fail_on_warn=args.ci) + check_script_list(src_dir=config["environment"]["SRCDIR"], fail_on_warn=fail_on_warn) check_script_prefixes() if not args.keepcache: @@ -547,7 +575,6 @@ def main(): run_tests( test_list=test_list, - src_dir=config["environment"]["SRCDIR"], build_dir=config["environment"]["BUILDDIR"], tmpdir=tmpdir, jobs=args.jobs, @@ -556,9 +583,10 @@ def main(): combined_logs_len=args.combinedlogslen, failfast=args.failfast, use_term_control=args.ansi, + results_filepath=results_filepath, ) -def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, use_term_control): +def run_tests(*, test_list, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, use_term_control, results_filepath=None): args = args or [] # Warn if bitcoind is already running @@ -581,7 +609,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= print(f"{BOLD[1]}WARNING!{BOLD[0]} There may be insufficient free space in {tmpdir} to run the Bitcoin functional test suite. " f"Running the test suite with fewer than {min_space // (1024 * 1024)} MB of free space might cause tests to fail.") - tests_dir = src_dir + '/test/functional/' + tests_dir = f"{build_dir}/test/functional/" # This allows `test_runner.py` to work from an out-of-source build directory using a symlink, # a hard link or a copy on any platform. See https://github.com/bitcoin/bitcoin/pull/27561. sys.path.append(tests_dir) @@ -650,11 +678,14 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= break if "[Errno 28] No space left on device" in stdout: - sys.exit(f"Early exiting after test failure due to insuffient free space in {tmpdir}\n" + sys.exit(f"Early exiting after test failure due to insufficient free space in {tmpdir}\n" f"Test execution data left in {tmpdir}.\n" f"Additional storage is needed to execute testing.") - print_results(test_results, max_len_name, (int(time.time() - start_time))) + runtime = int(time.time() - start_time) + print_results(test_results, max_len_name, runtime) + if results_filepath: + write_results(test_results, results_filepath, runtime) if coverage: coverage_passed = coverage.report_rpc_coverage() @@ -701,6 +732,17 @@ def print_results(test_results, max_len_name, runtime): results += "Runtime: %s s\n" % (runtime) print(results) + +def write_results(test_results, filepath, total_runtime): + with open(filepath, mode="w", encoding="utf8") as results_file: + results_writer = csv.writer(results_file) + results_writer.writerow(['test', 'status', 'duration(seconds)']) + all_passed = True + for test_result in test_results: + all_passed = all_passed and test_result.was_successful + results_writer.writerow([test_result.name, test_result.status, str(test_result.time)]) + results_writer.writerow(['ALL', ("Passed" if all_passed else "Failed"), str(total_runtime)]) + class TestHandler: """ Trigger the test scripts passed in via the list. @@ -834,7 +876,6 @@ def check_script_list(*, src_dir, fail_on_warn): if len(missed_tests) != 0: print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % (BOLD[1], BOLD[0], str(missed_tests))) if fail_on_warn: - # On CI this warning is an error to prevent merging incomplete commits into master sys.exit(1) diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py index 1ad2a579bf..67fb5c9f94 100755 --- a/test/functional/tool_signet_miner.py +++ b/test/functional/tool_signet_miner.py @@ -57,9 +57,10 @@ class SignetMinerTest(BitcoinTestFramework): f'--grind-cmd={self.options.bitcoinutil} grind', '--nbits=1d00ffff', f'--set-block-time={int(time.time())}', + '--poolnum=99', ], check=True, stderr=subprocess.STDOUT) assert_equal(node.getblockcount(), 1) 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..76cd2097a3 100755 --- a/test/functional/wallet_assumeutxo.py +++ b/test/functional/wallet_assumeutxo.py @@ -11,7 +11,9 @@ See feature_assumeutxo.py for background. - TODO: test loading a wallet (backup) on a pruned node """ +from test_framework.address import address_to_scriptpubkey from test_framework.test_framework import BitcoinTestFramework +from test_framework.messages import COIN from test_framework.util import ( assert_equal, assert_raises_rpc_error, @@ -62,8 +64,16 @@ class AssumeutxoTest(BitcoinTestFramework): for n in self.nodes: n.setmocktime(n.getblockheader(n.getbestblockhash())['time']) + # Create a wallet that we will create a backup for later (at snapshot height) n0.createwallet('w') w = n0.get_wallet_rpc("w") + w_address = w.getnewaddress() + + # Create another wallet and backup now (before snapshot height) + n0.createwallet('w2') + w2 = n0.get_wallet_rpc("w2") + w2_address = w2.getnewaddress() + w2.backupwallet("backup_w2.dat") # Generate a series of blocks that `n0` will have in the snapshot, # but that n1 doesn't yet see. In order for the snapshot to activate, @@ -84,6 +94,8 @@ class AssumeutxoTest(BitcoinTestFramework): assert_equal(n.getblockchaininfo()[ "headers"], SNAPSHOT_BASE_HEIGHT) + # This backup is created at the snapshot height, so it's + # not part of the background sync anymore w.backupwallet("backup_w.dat") self.log.info("-- Testing assumeutxo") @@ -93,7 +105,7 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info( f"Creating a UTXO snapshot at height {SNAPSHOT_BASE_HEIGHT}") - dump_output = n0.dumptxoutset('utxos.dat') + dump_output = n0.dumptxoutset('utxos.dat', "latest") assert_equal( dump_output['txoutset_hash'], @@ -103,7 +115,13 @@ class AssumeutxoTest(BitcoinTestFramework): # Mine more blocks on top of the snapshot that n1 hasn't yet seen. This # will allow us to test n1's sync-to-tip on top of a snapshot. - self.generate(n0, nblocks=100, sync_fun=self.no_op) + w_skp = address_to_scriptpubkey(w_address) + w2_skp = address_to_scriptpubkey(w2_address) + for i in range(100): + if i % 3 == 0: + self.mini_wallet.send_to(from_node=n0, scriptPubKey=w_skp, amount=1 * COIN) + self.mini_wallet.send_to(from_node=n0, scriptPubKey=w2_skp, amount=10 * COIN) + self.generate(n0, nblocks=1, sync_fun=self.no_op) assert_equal(n0.getblockcount(), FINAL_HEIGHT) assert_equal(n1.getblockcount(), START_HEIGHT) @@ -126,8 +144,13 @@ class AssumeutxoTest(BitcoinTestFramework): assert_equal(n1.getblockchaininfo()["blocks"], SNAPSHOT_BASE_HEIGHT) - self.log.info("Backup can't be loaded during background sync") - assert_raises_rpc_error(-4, "Wallet loading failed. 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 299", n1.restorewallet, "w", "backup_w.dat") + self.log.info("Backup from the snapshot height can be loaded during background sync") + n1.restorewallet("w", "backup_w.dat") + # Balance of w wallet is still still 0 because n1 has not synced yet + assert_equal(n1.getbalance(), 0) + + self.log.info("Backup from before the snapshot height can't be loaded during background sync") + assert_raises_rpc_error(-4, "Wallet loading failed. 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 299", n1.restorewallet, "w2", "backup_w2.dat") PAUSE_HEIGHT = FINAL_HEIGHT - 40 @@ -159,9 +182,16 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info("Ensuring background validation completes") self.wait_until(lambda: len(n1.getchainstates()['chainstates']) == 1) - self.log.info("Ensuring wallet can be restored from backup") - n1.restorewallet("w", "backup_w.dat") + self.log.info("Ensuring wallet can be restored from a backup that was created before the snapshot height") + n1.restorewallet("w2", "backup_w2.dat") + # Check balance of w2 wallet + assert_equal(n1.getbalance(), 340) + + # Check balance of w wallet after node is synced + n1.loadwallet("w") + w = n1.get_wallet_rpc("w") + assert_equal(w.getbalance(), 34) 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..83267f77e1 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -140,6 +140,25 @@ class WalletBackupTest(BitcoinTestFramework): assert_raises_rpc_error(-36, error_message, node.restorewallet, wallet_name, backup_file) assert wallet_file.exists() + def test_pruned_wallet_backup(self): + self.log.info("Test loading backup on a pruned node when the backup was created close to the prune height of the restoring node") + node = self.nodes[3] + self.restart_node(3, ["-prune=1", "-fastprune=1"]) + # Ensure the chain tip is at height 214, because this test assume it is. + assert_equal(node.getchaintips()[0]["height"], 214) + # We need a few more blocks so we can actually get above an realistic + # minimal prune height + self.generate(node, 50, sync_fun=self.no_op) + # Backup created at block height 264 + node.backupwallet(node.datadir_path / 'wallet_pruned.bak') + # Generate more blocks so we can actually prune the older blocks + self.generate(node, 300, sync_fun=self.no_op) + # This gives us an actual prune height roughly in the range of 220 - 240 + node.pruneblockchain(250) + # The backup should be updated with the latest height (locator) for + # the backup to load successfully this close to the prune height + node.restorewallet(f'pruned', node.datadir_path / 'wallet_pruned.bak') + def run_test(self): self.log.info("Generating initial blockchain") self.generate(self.nodes[0], 1) @@ -242,6 +261,8 @@ class WalletBackupTest(BitcoinTestFramework): for sourcePath in sourcePaths: assert_raises_rpc_error(-4, "backup failed", self.nodes[0].backupwallet, sourcePath) + self.test_pruned_wallet_backup() + 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..775786fbb1 100755 --- a/test/functional/wallet_backwards_compatibility.py +++ b/test/functional/wallet_backwards_compatibility.py @@ -33,7 +33,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 12 + self.num_nodes = 11 # Add new version after each release: self.extra_args = [ ["-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # Pre-release: use to mine blocks. noban for immediate tx relay @@ -47,7 +47,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v0.19.1 ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=127.0.0.1"], # v0.18.1 ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=127.0.0.1"], # v0.17.2 - ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=127.0.0.1", "-wallet=wallet.dat"], # v0.16.3 ] self.wallet_names = [self.default_wallet_name] @@ -68,7 +67,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): 190100, 180100, 170200, - 160300, ]) self.start_nodes() @@ -133,18 +131,17 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): def run_test(self): node_miner = self.nodes[0] node_master = self.nodes[1] - node_v21 = self.nodes[self.num_nodes - 6] - node_v17 = self.nodes[self.num_nodes - 2] - node_v16 = self.nodes[self.num_nodes - 1] + node_v21 = self.nodes[self.num_nodes - 5] + node_v17 = self.nodes[self.num_nodes - 1] legacy_nodes = self.nodes[2:] # Nodes that support legacy wallets - legacy_only_nodes = self.nodes[-5:] # Nodes that only support legacy wallets - descriptors_nodes = self.nodes[2:-5] # Nodes that support descriptor wallets + legacy_only_nodes = self.nodes[-4:] # Nodes that only support legacy wallets + descriptors_nodes = self.nodes[2:-4] # Nodes that support descriptor wallets self.generatetoaddress(node_miner, COINBASE_MATURITY + 1, node_miner.getnewaddress()) # Sanity check the test framework: - res = node_v16.getblockchaininfo() + res = node_v17.getblockchaininfo() assert_equal(res['blocks'], COINBASE_MATURITY + 1) self.log.info("Test wallet backwards compatibility...") @@ -215,9 +212,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): # In descriptors wallet mode, run this test on the nodes that support descriptor wallets # In legacy wallets mode, run this test on the nodes that support legacy wallets for node in descriptors_nodes if self.options.descriptors else legacy_nodes: - if self.major_version_less_than(node, 17): - # loadwallet was introduced in v0.17.0 - continue self.log.info(f"- {node.version}") for wallet_name in ["w1", "w2", "w3"]: if self.major_version_less_than(node, 18) and wallet_name == "w3": @@ -290,15 +284,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): node_v17.assert_start_raises_init_error(["-wallet=w3"], "Error: Error loading w3: Wallet requires newer version of Bitcoin Core") self.start_node(node_v17.index) - # No wallet created in master can be opened in 0.16 - self.log.info("Test that wallets created in master are too new for 0.16") - self.stop_node(node_v16.index) - for wallet_name in ["w1", "w2", "w3"]: - if self.options.descriptors: - node_v16.assert_start_raises_init_error([f"-wallet={wallet_name}"], f"Error: {wallet_name} corrupt, salvage failed") - else: - node_v16.assert_start_raises_init_error([f"-wallet={wallet_name}"], f"Error: Error loading {wallet_name}: Wallet requires newer version of Bitcoin Core") - # When descriptors are enabled, w1 cannot be opened by 0.21 since it contains a taproot descriptor if self.options.descriptors: self.log.info("Test that 0.21 cannot open wallet containing tr() descriptors") @@ -400,4 +385,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 5b7db55f45..061e9f2caa 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -117,6 +117,7 @@ class BumpFeeTest(BitcoinTestFramework): # Context independent tests test_feerate_checks_replaced_outputs(self, rbf_node, peer_node) + test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node, peer_node) def test_invalid_parameters(self, rbf_node, peer_node, dest_address): self.log.info('Test invalid parameters') @@ -816,7 +817,7 @@ def test_feerate_checks_replaced_outputs(self, rbf_node, peer_node): # Since the bumped tx will replace all of the outputs with a single output, we can estimate that its size will 31 * (len(outputs) - 1) bytes smaller tx_size = tx_details["decoded"]["vsize"] est_bumped_size = tx_size - (len(tx_details["decoded"]["vout"]) - 1) * 31 - inc_fee_rate = max(rbf_node.getmempoolinfo()["incrementalrelayfee"], Decimal(0.00005000)) # Wallet has a fixed incremental relay fee of 5 sat/vb + inc_fee_rate = rbf_node.getmempoolinfo()["incrementalrelayfee"] # RPC gives us fee as negative min_fee = (-tx_details["fee"] + get_fee(est_bumped_size, inc_fee_rate)) * Decimal(1e8) min_fee_rate = (min_fee / est_bumped_size).quantize(Decimal("1.000")) @@ -830,5 +831,27 @@ def test_feerate_checks_replaced_outputs(self, rbf_node, peer_node): self.clear_mempool() +def test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node, peer_node): + self.log.info('Test that bumpfee with fee_rate ignores walletincrementalrelayfee') + # Make sure there is enough balance + peer_node.sendtoaddress(rbf_node.getnewaddress(), 2) + self.generate(peer_node, 1) + + dest_address = peer_node.getnewaddress(address_type="bech32") + tx = rbf_node.send(outputs=[{dest_address: 1}], fee_rate=2) + + # Ensure you can not fee bump with a fee_rate below or equal to the original fee_rate + assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 1}) + assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2}) + + # Ensure you can not fee bump if the fee_rate is more than original fee_rate but the total fee from new fee_rate is + # 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 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 e5739a6a59..7a950ffae6 100755 --- a/test/functional/wallet_conflicts.py +++ b/test/functional/wallet_conflicts.py @@ -9,7 +9,6 @@ Test that wallet correctly tracks transactions that have been conflicted by bloc from decimal import Decimal -from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -37,7 +36,6 @@ class TxConflicts(BitcoinTestFramework): """ self.test_block_conflicts() - self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 7, self.nodes[2].getnewaddress()) self.test_mempool_conflict() self.test_mempool_and_block_conflicts() self.test_descendants_with_mempool_conflicts() @@ -425,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 4e31b48ec0..6deb262c9a 100755 --- a/test/functional/wallet_create_tx.py +++ b/test/functional/wallet_create_tx.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. +from test_framework.messages import ( + tx_from_hex, +) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -33,6 +36,7 @@ class CreateTxWalletTest(BitcoinTestFramework): self.test_anti_fee_sniping() self.test_tx_size_too_large() self.test_create_too_long_mempool_chain() + self.test_version3() def test_anti_fee_sniping(self): self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled') @@ -106,6 +110,23 @@ class CreateTxWalletTest(BitcoinTestFramework): test_wallet.unloadwallet() + def test_version3(self): + self.log.info('Check wallet does not create transactions with version=3 yet') + wallet_rpc = self.nodes[0].get_wallet_rpc(self.default_wallet_name) + + self.nodes[0].createwallet("version3") + wallet_v3 = self.nodes[0].get_wallet_rpc("version3") + + tx_data = wallet_rpc.send(outputs=[{wallet_v3.getnewaddress(): 25}], options={"change_position": 0}) + wallet_tx_data = wallet_rpc.gettransaction(tx_data["txid"]) + tx_current_version = tx_from_hex(wallet_tx_data["hex"]) + + # While version=3 transactions are standard, the CURRENT_VERSION is 2. + # This test can be removed if CURRENT_VERSION is changed, and replaced with tests that the + # wallet handles TRUC rules properly. + assert_equal(tx_current_version.version, 2) + wallet_v3.unloadwallet() + 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 71c883f166..827f27b431 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -114,6 +114,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.test_add_inputs_default_value() self.test_preset_inputs_selection() self.test_weight_calculation() + self.test_weight_limits() self.test_change_position() self.test_simple() self.test_simple_two_coins() @@ -1312,6 +1313,38 @@ class RawTransactionsTest(BitcoinTestFramework): self.nodes[2].unloadwallet("test_weight_calculation") + def test_weight_limits(self): + self.log.info("Test weight limits") + + self.nodes[2].createwallet("test_weight_limits") + wallet = self.nodes[2].get_wallet_rpc("test_weight_limits") + + outputs = [] + for _ in range(1472): + outputs.append({wallet.getnewaddress(address_type="legacy"): 0.1}) + 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 (pick all 1472 inputs to cover the fee) + input_weights = [] + 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) + + # 2) Let the wallet fund the transaction + assert_raises_rpc_error(-4, "The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs", + wallet.fundrawtransaction, hexstring=rawtx) + + # 3) Pre-select some inputs and let the wallet fill-up the remaining amount + inputs = input_weights[0:1000] + assert_raises_rpc_error(-4, "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", + wallet.fundrawtransaction, hexstring=rawtx, input_weights=inputs) + + self.nodes[2].unloadwallet("test_weight_limits") + def test_include_unsafe(self): self.log.info("Test fundrawtxn with unsafe inputs") @@ -1490,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..84c07b6a28 100755 --- a/test/functional/wallet_importdescriptors.py +++ b/test/functional/wallet_importdescriptors.py @@ -16,6 +16,7 @@ variants. and test the values returned.""" import concurrent.futures +import time from test_framework.authproxy import JSONRPCException from test_framework.blocktools import COINBASE_MATURITY @@ -708,5 +709,56 @@ class ImportDescriptorsTest(BitcoinTestFramework): assert_equal(temp_wallet.getbalance(), encrypted_wallet.getbalance()) + self.log.info("Multipath descriptors") + self.nodes[1].createwallet(wallet_name="multipath", descriptors=True, blank=True) + w_multipath = self.nodes[1].get_wallet_rpc("multipath") + self.nodes[1].createwallet(wallet_name="multipath_split", descriptors=True, blank=True) + w_multisplit = self.nodes[1].get_wallet_rpc("multipath_split") + timestamp = int(time.time()) + + self.test_importdesc({"desc": descsum_create(f"wpkh({xpriv}/<10;20>/0/*)"), + "active": True, + "range": 10, + "timestamp": "now", + "label": "some label"}, + success=False, + error_code=-8, + error_message="Multipath descriptors should not have a label", + wallet=w_multipath) + self.test_importdesc({"desc": descsum_create(f"wpkh({xpriv}/<10;20>/0/*)"), + "active": True, + "range": 10, + "timestamp": timestamp, + "internal": True}, + success=False, + error_code=-5, + error_message="Cannot have multipath descriptor while also specifying \'internal\'", + wallet=w_multipath) + + self.test_importdesc({"desc": descsum_create(f"wpkh({xpriv}/<10;20>/0/*)"), + "active": True, + "range": 10, + "timestamp": timestamp}, + success=True, + wallet=w_multipath) + + self.test_importdesc({"desc": descsum_create(f"wpkh({xpriv}/10/0/*)"), + "active": True, + "range": 10, + "timestamp": timestamp}, + success=True, + wallet=w_multisplit) + self.test_importdesc({"desc": descsum_create(f"wpkh({xpriv}/20/0/*)"), + "active": True, + "range": 10, + "internal": True, + "timestamp": timestamp}, + success=True, + wallet=w_multisplit) + for _ in range(0, 10): + assert_equal(w_multipath.getnewaddress(address_type="bech32"), w_multisplit.getnewaddress(address_type="bech32")) + assert_equal(w_multipath.getrawchangeaddress(address_type="bech32"), w_multisplit.getrawchangeaddress(address_type="bech32")) + assert_equal(sorted(w_multipath.listdescriptors()["descriptors"], key=lambda x: x["desc"]), sorted(w_multisplit.listdescriptors()["descriptors"], key=lambda x: x["desc"])) + if __name__ == '__main__': - ImportDescriptorsTest().main() + ImportDescriptorsTest(__file__).main() diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 31013f6323..3ce794dc2f 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -896,6 +896,43 @@ class ImportMultiTest(BitcoinTestFramework): ) assert result[0]['success'] + self.log.info("Multipath descriptors") + self.nodes[1].createwallet(wallet_name="multipath", blank=True, disable_private_keys=True) + w_multipath = self.nodes[1].get_wallet_rpc("multipath") + self.nodes[1].createwallet(wallet_name="multipath_split", blank=True, disable_private_keys=True) + w_multisplit = self.nodes[1].get_wallet_rpc("multipath_split") + + res = w_multipath.importmulti([{"desc": descsum_create(f"wpkh({xpub}/<10;20>/0/*)"), + "keypool": True, + "range": 10, + "timestamp": "now", + "internal": True}]) + assert_equal(res[0]["success"], False) + assert_equal(res[0]["error"]["code"], -5) + assert_equal(res[0]["error"]["message"], "Cannot have multipath descriptor while also specifying 'internal'") + + res = w_multipath.importmulti([{"desc": descsum_create(f"wpkh({xpub}/<10;20>/0/*)"), + "keypool": True, + "range": 10, + "timestamp": "now"}]) + assert_equal(res[0]["success"], True) + + res = w_multisplit.importmulti([{"desc": descsum_create(f"wpkh({xpub}/10/0/*)"), + "keypool": True, + "range": 10, + "timestamp": "now"}]) + assert_equal(res[0]["success"], True) + res = w_multisplit.importmulti([{"desc": descsum_create(f"wpkh({xpub}/20/0/*)"), + "keypool": True, + "range": 10, + "internal": True, + "timestamp": timestamp}]) + assert_equal(res[0]["success"], True) + + for _ in range(0, 9): + assert_equal(w_multipath.getnewaddress(address_type="bech32"), w_multisplit.getnewaddress(address_type="bech32")) + assert_equal(w_multipath.getrawchangeaddress(address_type="bech32"), w_multisplit.getrawchangeaddress(address_type="bech32")) + 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 fd586d546e..d777212f96 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -40,6 +40,7 @@ class ListSinceBlockTest(BitcoinTestFramework): self.test_no_blockhash() self.test_invalid_blockhash() self.test_reorg() + self.test_cant_read_block() self.test_double_spend() self.test_double_send() self.double_spends_filtered() @@ -167,6 +168,31 @@ class ListSinceBlockTest(BitcoinTestFramework): found = next(tx for tx in transactions if tx['txid'] == senttx) assert_equal(found['blockheight'], self.nodes[0].getblockheader(nodes2_first_blockhash)['height']) + def test_cant_read_block(self): + self.log.info('Test the RPC error "Can\'t read block from disk"') + + # Split network into two + self.split_network() + + # generate on both sides + nodes1_last_blockhash = self.generate(self.nodes[1], 6, sync_fun=lambda: self.sync_all(self.nodes[:2]))[-1] + self.generate(self.nodes[2], 7, sync_fun=lambda: self.sync_all(self.nodes[2:]))[0] + + self.join_network() + + # Renaming the block file to induce unsuccessful block read + blk_dat = (self.nodes[0].blocks_path / "blk00000.dat") + blk_dat_moved = blk_dat.rename(self.nodes[0].blocks_path / "blk00000.dat.moved") + assert not blk_dat.exists() + + # listsinceblock(nodes1_last_blockhash) should now fail as blocks are not accessible + assert_raises_rpc_error(-32603, "Can't read block from disk", + self.nodes[0].listsinceblock, nodes1_last_blockhash) + + # Restoring block file + blk_dat_moved.rename(self.nodes[0].blocks_path / "blk00000.dat") + assert blk_dat.exists() + def test_double_spend(self): ''' This tests the case where the same UTXO is spent twice on two separate @@ -479,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..149b1246d8 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -229,7 +229,7 @@ class MultiWalletTest(BitcoinTestFramework): assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", wallet_bad.getwalletinfo) # accessing wallet RPC without using wallet endpoint fails - assert_raises_rpc_error(-19, "Wallet file not specified", node.getwalletinfo) + assert_raises_rpc_error(-19, "Multiple wallets are loaded. Please select which wallet", node.getwalletinfo) w1, w2, w3, w4, *_ = wallets self.generatetoaddress(node, nblocks=COINBASE_MATURITY + 1, address=w1.getnewaddress(), sync_fun=self.no_op) @@ -275,7 +275,7 @@ class MultiWalletTest(BitcoinTestFramework): loadwallet_name = node.loadwallet(wallet_names[1]) assert_equal(loadwallet_name['name'], wallet_names[1]) assert_equal(node.listwallets(), wallet_names[0:2]) - assert_raises_rpc_error(-19, "Wallet file not specified", node.getwalletinfo) + assert_raises_rpc_error(-19, "Multiple wallets are loaded. Please select which wallet", node.getwalletinfo) w2 = node.get_wallet_rpc(wallet_names[1]) w2.getwalletinfo() @@ -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 0a0a8dba0d..2d0aad3b5d 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -577,5 +577,39 @@ class WalletSendTest(BitcoinTestFramework): # but rounded to nearest integer, it should be the same as the target fee rate assert_equal(round(actual_fee_rate_sat_vb), target_fee_rate_sat_vb) + # Check tx creation size limits + self.test_weight_limits() + + def test_weight_limits(self): + self.log.info("Test weight limits") + + self.nodes[1].createwallet("test_weight_limits") + wallet = self.nodes[1].get_wallet_rpc("test_weight_limits") + + # Generate future inputs; 272 WU per input (273 when high-s). + # Picking 1471 inputs will exceed the max standard tx weight. + outputs = [] + for _ in range(1472): + outputs.append({wallet.getnewaddress(address_type="legacy"): 0.1}) + self.nodes[0].send(outputs=outputs) + self.generate(self.nodes[0], 1) + + # 1) Try to fund transaction only using the preset inputs + inputs = wallet.listunspent() + assert_raises_rpc_error(-4, "Transaction too large", + wallet.send, outputs=[{wallet.getnewaddress(): 0.1 * 1471}], options={"inputs": inputs, "add_inputs": False}) + + # 2) Let the wallet fund the transaction + assert_raises_rpc_error(-4, "The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs", + wallet.send, outputs=[{wallet.getnewaddress(): 0.1 * 1471}]) + + # 3) Pre-select some inputs and let the wallet fill-up the remaining amount + inputs = inputs[0:1000] + assert_raises_rpc_error(-4, "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", + wallet.send, outputs=[{wallet.getnewaddress(): 0.1 * 1471}], options={"inputs": inputs, "add_inputs": True}) + + self.nodes[1].unloadwallet("test_weight_limits") + + 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..c909336a25 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -185,6 +185,7 @@ class UpgradeWalletTest(BitcoinTestFramework): self.restart_node(0) copy_v16() wallet = node_master.get_wallet_rpc(self.default_wallet_name) + assert_equal(wallet.getbalance(), v16_3_balance) self.log.info("Test upgradewallet without a version argument") self.test_upgradewallet(wallet, previous_version=159900, expected_version=169900) # wallet should still contain the same balance @@ -231,7 +232,7 @@ class UpgradeWalletTest(BitcoinTestFramework): assert b'\x07hdchain' in new_kvs hd_chain = new_kvs[b'\x07hdchain'] assert_equal(28, len(hd_chain)) - hd_chain_version, external_counter, seed_id = struct.unpack('<iI20s', hd_chain) + hd_chain_version, _external_counter, seed_id = struct.unpack('<iI20s', hd_chain) assert_equal(1, hd_chain_version) seed_id = bytearray(seed_id) seed_id.reverse() @@ -258,7 +259,7 @@ class UpgradeWalletTest(BitcoinTestFramework): new_kvs = dump_bdb_kv(node_master_wallet) hd_chain = new_kvs[b'\x07hdchain'] assert_equal(32, len(hd_chain)) - hd_chain_version, external_counter, seed_id, internal_counter = struct.unpack('<iI20sI', hd_chain) + hd_chain_version, _external_counter, seed_id, internal_counter = struct.unpack('<iI20sI', hd_chain) assert_equal(2, hd_chain_version) assert_equal(0, internal_counter) seed_id = bytearray(seed_id) @@ -284,7 +285,7 @@ class UpgradeWalletTest(BitcoinTestFramework): new_kvs = dump_bdb_kv(node_master_wallet) hd_chain = new_kvs[b'\x07hdchain'] assert_equal(32, len(hd_chain)) - hd_chain_version, external_counter, seed_id, internal_counter = struct.unpack('<iI20sI', hd_chain) + hd_chain_version, _external_counter, seed_id, internal_counter = struct.unpack('<iI20sI', hd_chain) assert_equal(2, hd_chain_version) assert_equal(2, internal_counter) # The next addresses are HD and should be on different HD chains (the one remaining key in each pool should have been flushed) @@ -301,8 +302,8 @@ class UpgradeWalletTest(BitcoinTestFramework): new_kvs = dump_bdb_kv(node_master_wallet) for k, old_v in old_kvs.items(): if k.startswith(b'\x07keymeta'): - new_ver, new_create_time, new_kp_str, new_seed_id, new_fpr, new_path_len, new_path, new_has_key_orig = deser_keymeta(BytesIO(new_kvs[k])) - old_ver, old_create_time, old_kp_str, old_seed_id, old_fpr, old_path_len, old_path, old_has_key_orig = deser_keymeta(BytesIO(old_v)) + new_ver, new_create_time, new_kp_str, new_seed_id, _new_fpr, new_path_len, new_path, new_has_key_orig = deser_keymeta(BytesIO(new_kvs[k])) + old_ver, old_create_time, old_kp_str, old_seed_id, _old_fpr, old_path_len, old_path, old_has_key_orig = deser_keymeta(BytesIO(old_v)) assert_equal(10, old_ver) if old_kp_str == b"": # imported things that don't have keymeta (i.e. imported coinbase privkeys) won't be upgraded assert_equal(new_kvs[k], old_v) @@ -360,4 +361,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/fuzz/test_runner.py b/test/fuzz/test_runner.py index c74246ef45..9917eca75a 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -23,10 +23,10 @@ def get_fuzz_env(*, target, source_dir): 'FUZZ': target, 'UBSAN_OPTIONS': f'suppressions={source_dir}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1', - 'UBSAN_SYMBOLIZER_PATH':symbolizer, - "ASAN_OPTIONS": "detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1", - 'ASAN_SYMBOLIZER_PATH':symbolizer, - 'MSAN_SYMBOLIZER_PATH':symbolizer, + 'UBSAN_SYMBOLIZER_PATH': symbolizer, + "ASAN_OPTIONS": "detect_leaks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1", + 'ASAN_SYMBOLIZER_PATH': symbolizer, + 'MSAN_SYMBOLIZER_PATH': symbolizer, } if platform.system() == "Windows": # On Windows, `env` option must include valid `SystemRoot`. diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py index 459693102b..1d397e721e 100755 --- a/test/get_previous_releases.py +++ b/test/get_previous_releases.py @@ -133,20 +133,9 @@ def download_binary(tag, args) -> int: print('Fetching: {tarballUrl}'.format(tarballUrl=tarballUrl)) - header, status = subprocess.Popen( - ['curl', '--head', tarballUrl], stdout=subprocess.PIPE).communicate() - if re.search("404 Not Found", header.decode("utf-8")): - print("Binary tag was not found") - return 1 - - curlCmds = [ - ['curl', '--remote-name', tarballUrl] - ] - - for cmd in curlCmds: - ret = subprocess.run(cmd).returncode - if ret: - return ret + ret = subprocess.run(['curl', '--fail', '--remote-name', tarballUrl]).returncode + if ret: + return ret hasher = hashlib.sha256() with open(tarball, "rb") as afile: diff --git a/test/lint/README.md b/test/lint/README.md index 49ed8356c3..8c1f0fedf0 100644 --- a/test/lint/README.md +++ b/test/lint/README.md @@ -26,17 +26,32 @@ Then you can use: ( cd ./test/lint/test_runner/ && cargo fmt && cargo clippy && RUST_BACKTRACE=1 cargo run ) ``` +If you wish to run individual lint checks, run the test_runner with +`--lint=TEST_TO_RUN` arguments. If running with `cargo run`, arguments after +`--` are passed to the binary you are running e.g.: + +```sh +( cd ./test/lint/test_runner/ && RUST_BACKTRACE=1 cargo run -- --lint=doc --lint=trailing_whitespace ) +``` + +To see a list of all individual lint checks available in test_runner, use `-h` +or `--help`: + +```sh +( cd ./test/lint/test_runner/ && RUST_BACKTRACE=1 cargo run -- --help ) +``` + #### Dependencies | Lint test | Dependency | |-----------|:----------:| -| [`lint-python.py`](/test/lint/lint-python.py) | [flake8](https://github.com/PyCQA/flake8) | [`lint-python.py`](/test/lint/lint-python.py) | [lief](https://github.com/lief-project/LIEF) | [`lint-python.py`](/test/lint/lint-python.py) | [mypy](https://github.com/python/mypy) | [`lint-python.py`](/test/lint/lint-python.py) | [pyzmq](https://github.com/zeromq/pyzmq) | [`lint-python-dead-code.py`](/test/lint/lint-python-dead-code.py) | [vulture](https://github.com/jendrikseipp/vulture) | [`lint-shell.py`](/test/lint/lint-shell.py) | [ShellCheck](https://github.com/koalaman/shellcheck) | [`lint-spelling.py`](/test/lint/lint-spelling.py) | [codespell](https://github.com/codespell-project/codespell) +| `py_lint` | [ruff](https://github.com/astral-sh/ruff) | markdown link check | [mlc](https://github.com/becheran/mlc) In use versions and install instructions are available in the [CI setup](../../ci/lint/04_install.sh). diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh index fe845ed19e..52ae95fbb6 100755 --- a/test/lint/commit-script-check.sh +++ b/test/lint/commit-script-check.sh @@ -35,20 +35,20 @@ for commit in $(git rev-list --reverse "$1"); do git checkout --quiet "$commit"^ || exit SCRIPT="$(git rev-list --format=%b -n1 "$commit" | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d')" if test -z "$SCRIPT"; then - echo "Error: missing script for: $commit" - echo "Failed" + echo "Error: missing script for: $commit" >&2 + echo "Failed" >&2 RET=1 else - echo "Running script for: $commit" - echo "$SCRIPT" + echo "Running script for: $commit" >&2 + echo "$SCRIPT" >&2 (eval "$SCRIPT") - git --no-pager diff --exit-code "$commit" && echo "OK" || (echo "Failed"; false) || RET=1 + git --no-pager diff --exit-code "$commit" && echo "OK" >&2 || (echo "Failed" >&2; false) || RET=1 fi git reset --quiet --hard HEAD else if git rev-list "--format=%b" -n1 "$commit" | grep -q '^-\(BEGIN\|END\)[ a-zA-Z]*-$'; then - echo "Error: script block marker but no scripted-diff in title of commit $commit" - echo "Failed" + echo "Error: script block marker but no scripted-diff in title of commit $commit" >&2 + echo "Failed" >&2 RET=1 fi fi 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-format-strings.py b/test/lint/lint-format-strings.py index 09d858e131..86a17fb0f8 100755 --- a/test/lint/lint-format-strings.py +++ b/test/lint/lint-format-strings.py @@ -16,28 +16,8 @@ import re import sys FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS = [ - 'FatalErrorf,0', - 'fprintf,1', 'tfm::format,1', # Assuming tfm::::format(std::ostream&, ... - 'LogConnectFailure,1', - 'LogError,0', - 'LogWarning,0', - 'LogInfo,0', - 'LogDebug,1', - 'LogTrace,1', - 'LogPrint,1', - 'LogPrintf,0', - 'LogPrintfCategory,1', - 'LogPrintLevel,2', - 'printf,0', - 'snprintf,2', - 'sprintf,1', 'strprintf,0', - 'vfprintf,1', - 'vprintf,1', - 'vsnprintf,1', - 'vsprintf,1', - 'WalletLogPrintf,0', ] RUN_LINT_FILE = 'test/lint/run-lint-format-strings.py' @@ -82,7 +62,7 @@ def main(): matching_files_filtered = [] for matching_file in matching_files: - if not re.search('^src/(leveldb|secp256k1|minisketch|tinyformat|test/fuzz/strprintf.cpp)|contrib/devtools/bitcoin-tidy/example_logprintf.cpp', matching_file): + if not re.search('^src/(leveldb|secp256k1|minisketch|tinyformat|test/fuzz/strprintf.cpp)', matching_file): matching_files_filtered.append(matching_file) matching_files_filtered.sort() 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/lint-python.py b/test/lint/lint-python.py index eabd13322e..e2dbe25b88 100755 --- a/test/lint/lint-python.py +++ b/test/lint/lint-python.py @@ -5,13 +5,12 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """ -Check for specified flake8 and mypy warnings in python files. +Check for specified mypy warnings in python files. """ import os from pathlib import Path import subprocess -import sys from importlib.metadata import metadata, PackageNotFoundError @@ -19,89 +18,12 @@ from importlib.metadata import metadata, PackageNotFoundError cache_dir = Path(__file__).parent.parent / ".mypy_cache" os.environ["MYPY_CACHE_DIR"] = str(cache_dir) -DEPS = ['flake8', 'lief', 'mypy', 'pyzmq'] - -# All .py files, except those in src/ (to exclude subtrees there) -FLAKE_FILES_ARGS = ['git', 'ls-files', '*.py', ':!:src/*.py'] +DEPS = ['lief', 'mypy', 'pyzmq'] # Only .py files in test/functional and contrib/devtools have type annotations # enforced. MYPY_FILES_ARGS = ['git', 'ls-files', 'test/functional/*.py', 'contrib/devtools/*.py'] -ENABLED = ( - 'E101,' # indentation contains mixed spaces and tabs - 'E112,' # expected an indented block - 'E113,' # unexpected indentation - 'E115,' # expected an indented block (comment) - 'E116,' # unexpected indentation (comment) - 'E125,' # continuation line with same indent as next logical line - 'E129,' # visually indented line with same indent as next logical line - 'E131,' # continuation line unaligned for hanging indent - 'E133,' # closing bracket is missing indentation - 'E223,' # tab before operator - 'E224,' # tab after operator - 'E242,' # tab after ',' - 'E266,' # too many leading '#' for block comment - 'E271,' # multiple spaces after keyword - 'E272,' # multiple spaces before keyword - 'E273,' # tab after keyword - 'E274,' # tab before keyword - 'E275,' # missing whitespace after keyword - 'E304,' # blank lines found after function decorator - 'E306,' # expected 1 blank line before a nested definition - 'E401,' # multiple imports on one line - 'E402,' # module level import not at top of file - 'E502,' # the backslash is redundant between brackets - 'E701,' # multiple statements on one line (colon) - 'E702,' # multiple statements on one line (semicolon) - 'E703,' # statement ends with a semicolon - 'E711,' # comparison to None should be 'if cond is None:' - 'E714,' # test for object identity should be "is not" - 'E721,' # do not compare types, use "isinstance()" - 'E722,' # do not use bare 'except' - 'E742,' # do not define classes named "l", "O", or "I" - 'E743,' # do not define functions named "l", "O", or "I" - 'E901,' # SyntaxError: invalid syntax - 'E902,' # TokenError: EOF in multi-line string - 'F401,' # module imported but unused - 'F402,' # import module from line N shadowed by loop variable - 'F403,' # 'from foo_module import *' used; unable to detect undefined names - 'F404,' # future import(s) name after other statements - 'F405,' # foo_function may be undefined, or defined from star imports: bar_module - 'F406,' # "from module import *" only allowed at module level - 'F407,' # an undefined __future__ feature name was imported - 'F601,' # dictionary key name repeated with different values - 'F602,' # dictionary key variable name repeated with different values - 'F621,' # too many expressions in an assignment with star-unpacking - 'F622,' # two or more starred expressions in an assignment (a, *b, *c = d) - 'F631,' # assertion test is a tuple, which are always True - 'F632,' # use ==/!= to compare str, bytes, and int literals - 'F701,' # a break statement outside of a while or for loop - 'F702,' # a continue statement outside of a while or for loop - 'F703,' # a continue statement in a finally block in a loop - 'F704,' # a yield or yield from statement outside of a function - 'F705,' # a return statement with arguments inside a generator - 'F706,' # a return statement outside of a function/method - 'F707,' # an except: block as not the last exception handler - 'F811,' # redefinition of unused name from line N - 'F812,' # list comprehension redefines 'foo' from line N - 'F821,' # undefined name 'Foo' - 'F822,' # undefined name name in __all__ - 'F823,' # local variable name … referenced before assignment - 'F831,' # duplicate argument name in function definition - 'F841,' # local variable 'foo' is assigned to but never used - 'W191,' # indentation contains tabs - 'W291,' # trailing whitespace - 'W292,' # no newline at end of file - 'W293,' # blank line contains whitespace - 'W601,' # .has_key() is deprecated, use "in" - 'W602,' # deprecated form of raising exception - 'W603,' # "<>" is deprecated, use "!=" - 'W604,' # backticks are deprecated, use "repr()" - 'W605,' # invalid escape sequence "x" - 'W606,' # 'async' and 'await' are reserved keywords starting with Python 3.7 -) - def check_dependencies(): for dep in DEPS: @@ -115,20 +37,6 @@ def check_dependencies(): def main(): check_dependencies() - if len(sys.argv) > 1: - flake8_files = sys.argv[1:] - else: - flake8_files = subprocess.check_output(FLAKE_FILES_ARGS).decode("utf-8").splitlines() - - flake8_args = ['flake8', '--ignore=B,C,E,F,I,N,W', f'--select={ENABLED}'] + flake8_files - flake8_env = os.environ.copy() - flake8_env["PYTHONWARNINGS"] = "ignore" - - try: - subprocess.check_call(flake8_args, env=flake8_env) - except subprocess.CalledProcessError: - exit(1) - mypy_files = subprocess.check_output(MYPY_FILES_ARGS).decode("utf-8").splitlines() mypy_args = ['mypy', '--show-error-codes'] + mypy_files diff --git a/test/lint/lint-spelling.py b/test/lint/lint-spelling.py index 3e578b218f..945288a3dd 100755 --- a/test/lint/lint-spelling.py +++ b/test/lint/lint-spelling.py @@ -14,7 +14,7 @@ from subprocess import check_output, STDOUT, CalledProcessError from lint_ignore_dirs import SHARED_EXCLUDED_SUBTREES IGNORE_WORDS_FILE = 'test/lint/spelling.ignore-words.txt' -FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)build-aux/m4/", ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)contrib/guix/patches"] +FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)contrib/guix/patches"] FILES_ARGS += [f":(exclude){dir}" for dir in SHARED_EXCLUDED_SUBTREES] diff --git a/test/lint/run-lint-format-strings.py b/test/lint/run-lint-format-strings.py index 244bf5956f..d3c0ac92e5 100755 --- a/test/lint/run-lint-format-strings.py +++ b/test/lint/run-lint-format-strings.py @@ -13,17 +13,8 @@ import re import sys FALSE_POSITIVES = [ - ("src/dbwrapper.cpp", "vsnprintf(p, limit - p, format, backup_ap)"), - ("src/index/base.cpp", "FatalErrorf(const char* fmt, const Args&... args)"), - ("src/index/base.h", "FatalErrorf(const char* fmt, const Args&... args)"), - ("src/netbase.cpp", "LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args)"), ("src/clientversion.cpp", "strprintf(_(COPYRIGHT_HOLDERS).translated, COPYRIGHT_HOLDERS_SUBSTITUTION)"), ("src/test/translation_tests.cpp", "strprintf(format, arg)"), - ("src/validationinterface.cpp", "LogPrint(BCLog::VALIDATION, fmt \"\\n\", __VA_ARGS__)"), - ("src/wallet/wallet.h", "WalletLogPrintf(const char* fmt, Params... parameters)"), - ("src/wallet/wallet.h", "LogPrintf((\"%s \" + std::string{fmt}).c_str(), GetDisplayName(), parameters...)"), - ("src/wallet/scriptpubkeyman.h", "WalletLogPrintf(const char* fmt, Params... parameters)"), - ("src/wallet/scriptpubkeyman.h", "LogPrintf((\"%s \" + std::string{fmt}).c_str(), m_storage.GetDisplayName(), parameters...)"), ] diff --git a/test/lint/spelling.ignore-words.txt b/test/lint/spelling.ignore-words.txt index cb0e0c4d31..ccf2e6964b 100644 --- a/test/lint/spelling.ignore-words.txt +++ b/test/lint/spelling.ignore-words.txt @@ -1,22 +1,25 @@ afile +amountIn asend -ba blockin bu cachable clen crypted debbugs +deques fo fpr +hashIn hights -inflight +incomin invokable -keypair lief mor nd nin +outIn +re-use requestor ser siz @@ -24,5 +27,5 @@ stap unparseable unser useable -warmup -wit +viewIn +wit
\ No newline at end of file diff --git a/test/lint/test_runner/src/main.rs b/test/lint/test_runner/src/main.rs index 5f980eb398..42c880052e 100644 --- a/test/lint/test_runner/src/main.rs +++ b/test/lint/test_runner/src/main.rs @@ -5,28 +5,155 @@ use std::env; use std::fs; use std::io::ErrorKind; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::process::{Command, ExitCode, Stdio}; +/// A possible error returned by any of the linters. +/// +/// The error string should explain the failure type and list all violations. type LintError = String; type LintResult = Result<(), LintError>; type LintFn = fn() -> LintResult; +struct Linter { + pub description: &'static str, + pub name: &'static str, + pub lint_fn: LintFn, +} + +fn get_linter_list() -> Vec<&'static Linter> { + vec![ + &Linter { + description: "Check that all command line arguments are documented.", + name: "doc", + lint_fn: lint_doc + }, + &Linter { + description: "Check that no symbol from bitcoin-build-config.h is used without the header being included", + name: "includes_build_config", + lint_fn: lint_includes_build_config + }, + &Linter { + description: "Check that markdown links resolve", + name: "markdown", + lint_fn: lint_markdown + }, + &Linter { + description: "Lint Python code", + name: "py_lint", + lint_fn: lint_py_lint, + }, + &Linter { + description: "Check that std::filesystem is not used directly", + name: "std_filesystem", + lint_fn: lint_std_filesystem + }, + &Linter { + description: "Check that release note snippets are in the right folder", + name: "doc_release_note_snippets", + lint_fn: lint_doc_release_note_snippets + }, + &Linter { + description: "Check that subtrees are pure subtrees", + name: "subtree", + lint_fn: lint_subtree + }, + &Linter { + description: "Check that tabs are not used as whitespace", + name: "tabs_whitespace", + lint_fn: lint_tabs_whitespace + }, + &Linter { + description: "Check for trailing whitespace", + name: "trailing_whitespace", + lint_fn: lint_trailing_whitespace + }, + &Linter { + description: "Run all linters of the form: test/lint/lint-*.py", + name: "all_python_linters", + lint_fn: run_all_python_linters + }, + ] +} + +fn print_help_and_exit() { + print!( + r#" +Usage: test_runner [--lint=LINTER_TO_RUN] +Runs all linters in the lint test suite, printing any errors +they detect. + +If you wish to only run some particular lint tests, pass +'--lint=' with the name of the lint test you wish to run. +You can set as many '--lint=' values as you wish, e.g.: +test_runner --lint=doc --lint=subtree + +The individual linters available to run are: +"# + ); + for linter in get_linter_list() { + println!("{}: \"{}\"", linter.name, linter.description) + } + + std::process::exit(1); +} + +fn parse_lint_args(args: &[String]) -> Vec<&'static Linter> { + let linter_list = get_linter_list(); + let mut lint_values = Vec::new(); + + for arg in args { + #[allow(clippy::if_same_then_else)] + if arg.starts_with("--lint=") { + let lint_arg_value = arg + .trim_start_matches("--lint=") + .trim_matches('"') + .trim_matches('\''); + + let try_find_linter = linter_list + .iter() + .find(|linter| linter.name == lint_arg_value); + match try_find_linter { + Some(linter) => { + lint_values.push(*linter); + } + None => { + println!("No linter {lint_arg_value} found!"); + print_help_and_exit(); + } + } + } else if arg.eq("--help") || arg.eq("-h") { + print_help_and_exit(); + } else { + print_help_and_exit(); + } + } + + lint_values +} + /// Return the git command +/// +/// Lint functions should use this command, so that only files tracked by git are considered and +/// temporary and untracked files are ignored. For example, instead of 'grep', 'git grep' should be +/// used. fn git() -> Command { let mut git = Command::new("git"); git.arg("--no-pager"); git } -/// Return stdout +/// Return stdout on success and a LintError on failure, when invalid UTF8 was detected or the +/// command did not succeed. fn check_output(cmd: &mut std::process::Command) -> Result<String, LintError> { let out = cmd.output().expect("command error"); if !out.status.success() { return Err(String::from_utf8_lossy(&out.stderr).to_string()); } Ok(String::from_utf8(out.stdout) - .map_err(|e| format!("{e}"))? + .map_err(|e| { + format!("All path names, source code, messages, and output must be valid UTF8!\n{e}") + })? .trim() .to_string()) } @@ -73,6 +200,73 @@ fn lint_subtree() -> LintResult { } } +fn lint_py_lint() -> LintResult { + let bin_name = "ruff"; + let checks = format!( + "--select={}", + [ + "B006", // mutable-argument-default + "B008", // function-call-in-default-argument + "E101", // indentation contains mixed spaces and tabs + "E401", // multiple imports on one line + "E402", // module level import not at top of file + "E701", // multiple statements on one line (colon) + "E702", // multiple statements on one line (semicolon) + "E703", // statement ends with a semicolon + "E711", // comparison to None should be 'if cond is None:' + "E714", // test for object identity should be "is not" + "E721", // do not compare types, use "isinstance()" + "E722", // do not use bare 'except' + "E742", // do not define classes named "l", "O", or "I" + "E743", // do not define functions named "l", "O", or "I" + "F401", // module imported but unused + "F402", // import module from line N shadowed by loop variable + "F403", // 'from foo_module import *' used; unable to detect undefined names + "F404", // future import(s) name after other statements + "F405", // foo_function may be undefined, or defined from star imports: bar_module + "F406", // "from module import *" only allowed at module level + "F407", // an undefined __future__ feature name was imported + "F601", // dictionary key name repeated with different values + "F602", // dictionary key variable name repeated with different values + "F621", // too many expressions in an assignment with star-unpacking + "F631", // assertion test is a tuple, which are always True + "F632", // use ==/!= to compare str, bytes, and int literals + "F811", // redefinition of unused name from line N + "F821", // undefined name 'Foo' + "F822", // undefined name name in __all__ + "F823", // local variable name … referenced before assignment + "F841", // local variable 'foo' is assigned to but never used + "W191", // indentation contains tabs + "W291", // trailing whitespace + "W292", // no newline at end of file + "W293", // blank line contains whitespace + "W605", // invalid escape sequence "x" + ] + .join(",") + ); + let files = check_output( + git() + .args(["ls-files", "--", "*.py"]) + .args(get_pathspecs_exclude_subtrees()), + )?; + + let mut cmd = Command::new(bin_name); + cmd.args(["check", &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([ @@ -97,6 +291,30 @@ fs:: namespace, which has unsafe filesystem functions marked as deleted. } } +fn lint_doc_release_note_snippets() -> LintResult { + let non_release_notes = check_output(git().args([ + "ls-files", + "--", + "doc/release-notes/", + ":(exclude)doc/release-notes/*.*.md", // Assume that at least one dot implies a proper release note + ]))?; + if non_release_notes.is_empty() { + Ok(()) + } else { + Err(format!( + r#" +{} +^^^ +Release note snippets and other docs must be put into the doc/ folder directly. + +The doc/release-notes/ folder is for archived release notes of previous releases only. Snippets are +expected to follow the naming "/doc/release-notes-<PR number>.md". + "#, + non_release_notes + )) + } +} + /// Return the pathspecs for whitespace related excludes fn get_pathspecs_exclude_whitespace() -> Vec<String> { let mut list = get_pathspecs_exclude_subtrees(); @@ -177,20 +395,14 @@ Please add any false positives, such as subtrees, or externally sourced files to } fn lint_includes_build_config() -> LintResult { - let config_path = "./src/config/bitcoin-config.h.in"; - if !Path::new(config_path).is_file() { - assert!(Command::new("./autogen.sh") - .status() - .expect("command error") - .success()); - } + let config_path = "./cmake/bitcoin-build-config.h.in"; let defines_regex = format!( r"^\s*(?!//).*({})", - check_output(Command::new("grep").args(["undef ", "--", config_path])) + check_output(Command::new("grep").args(["define", "--", config_path])) .expect("grep failed") .lines() .map(|line| { - line.split("undef ") + line.split_whitespace() .nth(1) .unwrap_or_else(|| panic!("Could not extract name in line: {line}")) }) @@ -217,7 +429,7 @@ fn lint_includes_build_config() -> LintResult { ]) .args(get_pathspecs_exclude_subtrees()) .args([ - // These are exceptions which don't use bitcoin-config.h, rather the Makefile.am adds + // These are exceptions which don't use bitcoin-build-config.h, rather CMakeLists.txt adds // these cppflags manually. ":(exclude)src/crypto/sha256_arm_shani.cpp", ":(exclude)src/crypto/sha256_avx2.cpp", @@ -235,9 +447,9 @@ fn lint_includes_build_config() -> LintResult { "--files-with-matches" }, if mode { - "^#include <config/bitcoin-config.h> // IWYU pragma: keep$" + "^#include <bitcoin-build-config.h> // IWYU pragma: keep$" } else { - "#include <config/bitcoin-config.h>" // Catch redundant includes with and without the IWYU pragma + "#include <bitcoin-build-config.h>" // Catch redundant includes with and without the IWYU pragma }, "--", ]) @@ -251,11 +463,11 @@ fn lint_includes_build_config() -> LintResult { return Err(format!( r#" ^^^ -One or more files use a symbol declared in the bitcoin-config.h header. However, they are not +One or more files use a symbol declared in the bitcoin-build-config.h header. However, they are not including the header. This is problematic, because the header may or may not be indirectly included. If the indirect include were to be intentionally or accidentally removed, the build could still succeed, but silently be buggy. For example, a slower fallback algorithm could be picked, -even though bitcoin-config.h indicates that a faster feature is available and should be used. +even though bitcoin-build-config.h indicates that a faster feature is available and should be used. If you are unsure which symbol is used, you can find it with this command: git grep --perl-regexp '{}' -- file_name @@ -263,7 +475,7 @@ git grep --perl-regexp '{}' -- file_name Make sure to include it with the IWYU pragma. Otherwise, IWYU may falsely instruct to remove the include again. -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep "#, defines_regex )); @@ -272,7 +484,7 @@ include again. if redundant { return Err(r#" ^^^ -None of the files use a symbol declared in the bitcoin-config.h header. However, they are including +None of the files use a symbol declared in the bitcoin-build-config.h header. However, they are including the header. Consider removing the unused include. "# .to_string()); @@ -303,6 +515,7 @@ fn lint_markdown() -> LintResult { "--offline", "--ignore-path", md_ignore_path_str.as_str(), + "--gitignore", "--root-dir", ".", ]) @@ -312,11 +525,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. @@ -326,7 +534,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 => { @@ -337,7 +545,7 @@ Markdown link errors found: } } -fn lint_all() -> LintResult { +fn run_all_python_linters() -> LintResult { let mut good = true; let lint_dir = get_git_root().join("test/lint"); for entry in fs::read_dir(lint_dir).unwrap() { @@ -352,7 +560,7 @@ fn lint_all() -> LintResult { .success() { good = false; - println!("^---- failure generated from {}", entry_fn); + println!("^---- ⚠️ Failure generated from {}", entry_fn); } } if good { @@ -363,25 +571,26 @@ fn lint_all() -> LintResult { } fn main() -> ExitCode { - let test_list: Vec<(&str, LintFn)> = vec![ - ("subtree check", lint_subtree), - ("std::filesystem check", lint_std_filesystem), - ("trailing whitespace check", lint_trailing_whitespace), - ("no-tabs check", lint_tabs_whitespace), - ("build config includes check", lint_includes_build_config), - ("-help=1 documentation check", lint_doc), - ("markdown hyperlink check", lint_markdown), - ("lint-*.py scripts", lint_all), - ]; + let linters_to_run: Vec<&Linter> = if env::args().count() > 1 { + let args: Vec<String> = env::args().skip(1).collect(); + parse_lint_args(&args) + } else { + // If no arguments are passed, run all linters. + get_linter_list() + }; let git_root = get_git_root(); let mut test_failed = false; - for (lint_name, lint_fn) in test_list { + for linter in linters_to_run { // chdir to root before each lint test env::set_current_dir(&git_root).unwrap(); - if let Err(err) = lint_fn() { - println!("{err}\n^---- ⚠️ Failure generated from {lint_name}!"); + if let Err(err) = (linter.lint_fn)() { + println!( + "{err}\n^---- ⚠️ Failure generated from lint check '{}'!", + linter.name + ); + println!("{}", linter.description); test_failed = true; } } diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index 482667a26a..94bd14e6c3 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -51,18 +51,18 @@ unsigned-integer-overflow:CCoinsViewCache::Uncache unsigned-integer-overflow:CompressAmount unsigned-integer-overflow:DecompressAmount unsigned-integer-overflow:crypto/ -unsigned-integer-overflow:getchaintxstats* unsigned-integer-overflow:MurmurHash3 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 implicit-integer-sign-change:compressor.h implicit-integer-sign-change:crypto/ -implicit-integer-sign-change:getchaintxstats* implicit-integer-sign-change:TxConfirmStats::removeTx implicit-integer-sign-change:prevector.h implicit-integer-sign-change:verify_flags @@ -74,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<*> diff --git a/test/util/test_runner.py b/test/util/test_runner.py index 1cd368f6f4..cac184ca30 100755 --- a/test/util/test_runner.py +++ b/test/util/test_runner.py @@ -5,7 +5,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test framework for bitcoin utils. -Runs automatically during `make check`. +Runs automatically during `ctest --test-dir build/`. Can also be run manually.""" @@ -83,13 +83,11 @@ def bctest(testDir, testObj, buildenv): execrun = [execprog] + execargs # Read the input data (if there is any) - stdinCfg = None inputData = None if "input" in testObj: filename = os.path.join(testDir, testObj["input"]) with open(filename, encoding="utf8") as f: inputData = f.read() - stdinCfg = subprocess.PIPE # Read the expected output data (if there is any) outputFn = None @@ -112,9 +110,8 @@ def bctest(testDir, testObj, buildenv): raise Exception # Run the test - proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) try: - outs = proc.communicate(input=inputData) + res = subprocess.run(execrun, capture_output=True, text=True, input=inputData) except OSError: logging.error("OSError, Failed to execute " + execprog) raise @@ -123,9 +120,9 @@ def bctest(testDir, testObj, buildenv): data_mismatch, formatting_mismatch = False, False # Parse command output and expected output try: - a_parsed = parse_output(outs[0], outputType) + a_parsed = parse_output(res.stdout, outputType) except Exception as e: - logging.error('Error parsing command output as %s: %s' % (outputType, e)) + logging.error(f"Error parsing command output as {outputType}: '{str(e)}'; res: {str(res)}") raise try: b_parsed = parse_output(outputData, outputType) @@ -134,13 +131,13 @@ def bctest(testDir, testObj, buildenv): raise # Compare data if a_parsed != b_parsed: - logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")") + logging.error(f"Output data mismatch for {outputFn} (format {outputType}); res: {str(res)}") data_mismatch = True # Compare formatting - if outs[0] != outputData: - error_message = "Output formatting mismatch for " + outputFn + ":\n" + if res.stdout != outputData: + error_message = f"Output formatting mismatch for {outputFn}:\nres: {str(res)}\n" error_message += "".join(difflib.context_diff(outputData.splitlines(True), - outs[0].splitlines(True), + res.stdout.splitlines(True), fromfile=outputFn, tofile="returned")) logging.error(error_message) @@ -152,8 +149,8 @@ def bctest(testDir, testObj, buildenv): wantRC = 0 if "return_code" in testObj: wantRC = testObj['return_code'] - if proc.returncode != wantRC: - logging.error("Return code mismatch for " + outputFn) + if res.returncode != wantRC: + logging.error(f"Return code mismatch for {outputFn}; res: {str(res)}") raise Exception if "error_txt" in testObj: @@ -164,8 +161,8 @@ def bctest(testDir, testObj, buildenv): # emits DISPLAY errors when running as a windows application on # linux through wine. Just assert that the expected error text appears # somewhere in stderr. - if want_error not in outs[1]: - logging.error("Error mismatch:\n" + "Expected: " + want_error + "\nReceived: " + outs[1].rstrip()) + if want_error not in res.stderr: + logging.error(f"Error mismatch:\nExpected: {want_error}\nReceived: {res.stderr.rstrip()}\nres: {str(res)}") raise Exception def parse_output(a, fmt): diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000000..ecbccb072c --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", + "builtin-baseline": "9edb1b8e590cc086563301d735cae4b6e732d2d2", + "overrides":[ + {"name": "libevent", "version": "2.1.12#7"}, + {"name": "liblzma", "version": "5.4.1#1"} + ], + "dependencies": [ + "boost-date-time", + "boost-multi-index", + "boost-signals2", + "libevent" + ], + "default-features": [ + "wallet", + "miniupnpc", + "zeromq", + "tests", + "qt5" + ], + "features": { + "wallet": { + "description": "Enable wallet", + "dependencies": [ "berkeleydb", "sqlite3" ] + }, + "sqlite": { + "description": "Enable SQLite wallet support", + "dependencies": [ "sqlite3" ] + }, + "berkeleydb": { + "description": "Enable Berkeley DB wallet support", + "dependencies": [ "berkeleydb" ] + }, + "miniupnpc": { + "description": "Enable UPnP", + "dependencies": [ "miniupnpc" ] + }, + "zeromq": { + "description": "Enable ZMQ notifications", + "dependencies": [ "zeromq" ] + }, + "tests": { + "description": "Build test_bitcoin.exe executable", + "dependencies": [ "boost-test" ] + }, + "qt5": { + "description": "Build GUI, Qt 5", + "dependencies": [ "qt5-base", "qt5-tools" ] + } + } +} |